Home | History | Annotate | Download | only in tools
      1 /*
      2  * kmod-remove - remove modules from the kernel.
      3  *
      4  * Copyright (C) 2015 Intel Corporation. All rights reserved.
      5  * Copyright (C) 2011-2013  ProFUSION embedded systems
      6  *
      7  * This program is free software: you can redistribute it and/or modify
      8  * it under the terms of the GNU General Public License as published by
      9  * the Free Software Foundation, either version 2 of the License, or
     10  * (at your option) any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License
     18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include <errno.h>
     22 #include <getopt.h>
     23 #include <stdlib.h>
     24 #include <string.h>
     25 
     26 #include <libkmod/libkmod.h>
     27 
     28 #include "kmod.h"
     29 
     30 static const char cmdopts_s[] = "h";
     31 static const struct option cmdopts[] = {
     32 	{"help", no_argument, 0, 'h'},
     33 	{ }
     34 };
     35 
     36 static void help(void)
     37 {
     38 	printf("Usage:\n"
     39 	       "\t%s remove [options] module\n"
     40 	       "Options:\n"
     41 	       "\t-h, --help        show this help\n",
     42 	       program_invocation_short_name);
     43 }
     44 
     45 static int check_module_inuse(struct kmod_module *mod) {
     46 	struct kmod_list *holders;
     47 	int state;
     48 
     49 	state = kmod_module_get_initstate(mod);
     50 
     51 	if (state == KMOD_MODULE_BUILTIN) {
     52 		ERR("Module %s is builtin.\n", kmod_module_get_name(mod));
     53 		return -ENOENT;
     54 	} else if (state < 0) {
     55 		ERR("Module %s is not currently loaded\n",
     56 				kmod_module_get_name(mod));
     57 		return -ENOENT;
     58 	}
     59 
     60 	holders = kmod_module_get_holders(mod);
     61 	if (holders != NULL) {
     62 		struct kmod_list *itr;
     63 
     64 		ERR("Module %s is in use by:", kmod_module_get_name(mod));
     65 
     66 		kmod_list_foreach(itr, holders) {
     67 			struct kmod_module *hm = kmod_module_get_module(itr);
     68 			fprintf(stderr, " %s", kmod_module_get_name(hm));
     69 			kmod_module_unref(hm);
     70 		}
     71 		fputc('\n', stderr);
     72 
     73 		kmod_module_unref_list(holders);
     74 		return -EBUSY;
     75 	}
     76 
     77 	if (kmod_module_get_refcnt(mod) != 0) {
     78 		ERR("Module %s is in use\n", kmod_module_get_name(mod));
     79 		return -EBUSY;
     80 	}
     81 
     82 	return 0;
     83 }
     84 
     85 static int do_remove(int argc, char *argv[])
     86 {
     87 	struct kmod_ctx *ctx;
     88 	struct kmod_module *mod;
     89 	const char *name;
     90 	int err, r = EXIT_SUCCESS;
     91 
     92 	for (;;) {
     93 		int c, idx =0;
     94 		c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
     95 		if (c == -1)
     96 			break;
     97 		switch (c) {
     98 		case 'h':
     99 			help();
    100 			return EXIT_SUCCESS;
    101 
    102 		default:
    103 			ERR("Unexpected getopt_long() value '%c'.\n", c);
    104 			return EXIT_FAILURE;
    105 		}
    106 	}
    107 
    108 	if (optind >= argc) {
    109 		ERR("Missing module name\n");
    110 		return EXIT_FAILURE;
    111 	}
    112 
    113 	ctx = kmod_new(NULL, NULL);
    114 	if (!ctx) {
    115 		ERR("kmod_new() failed!\n");
    116 		return EXIT_FAILURE;
    117 	}
    118 
    119 	name = argv[optind];
    120 	err = kmod_module_new_from_name(ctx, name, &mod);
    121 	if (err < 0) {
    122 		ERR("Could not remove module %s: %s\n", name, strerror(-err));
    123 		goto end;
    124 	}
    125 
    126 	err = check_module_inuse(mod);
    127 	if (err < 0)
    128 		goto unref;
    129 
    130 	err = kmod_module_remove_module(mod, 0);
    131 	if (err < 0)
    132 		goto unref;
    133 
    134 unref:
    135 	kmod_module_unref(mod);
    136 
    137 end:
    138 	kmod_unref(ctx);
    139 	if (err < 0) {
    140 		r = EXIT_FAILURE;
    141 		ERR("Could not remove module %s: %s\n", name, strerror(-err));
    142 	}
    143 	return r;
    144 }
    145 
    146 const struct kmod_cmd kmod_cmd_remove = {
    147 	.name = "remove",
    148 	.cmd = do_remove,
    149 	.help = "remove module from kernel",
    150 };
    151