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