blob: d57e8bdbf4e548278148ac94f7d7b6a621c7c331 [file] [log] [blame]
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -02001/*
2 * kmod-rmmod - remove modules from linux kernel using libkmod.
3 *
Lucas De Marchia66a6a92012-01-09 00:40:50 -02004 * Copyright (C) 2011-2012 ProFUSION embedded systems
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -02005 *
Lucas De Marchicb451f32011-12-12 18:24:35 -02006 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -020010 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Lucas De Marchicb451f32011-12-12 18:24:35 -020013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -020015 *
Lucas De Marchicb451f32011-12-12 18:24:35 -020016 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -020018 */
Lucas De Marchicb451f32011-12-12 18:24:35 -020019
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -020020#include <stdio.h>
21#include <stdlib.h>
22#include <getopt.h>
23#include <errno.h>
24#include <string.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <unistd.h>
28#include <syslog.h>
29#include "libkmod.h"
30
Lucas De Marchi04c26d22012-11-05 17:51:32 -020031#define LOGPREFIX "rmmod: "
32#define ERR(...) fprintf(stderr, LOGPREFIX "ERROR: " __VA_ARGS__)
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -020033
34static const char cmdopts_s[] = "fsvVwh";
35static const struct option cmdopts[] = {
36 {"force", no_argument, 0, 'f'},
37 {"syslog", no_argument, 0, 's'},
38 {"verbose", no_argument, 0, 'v'},
39 {"version", no_argument, 0, 'V'},
40 {"wait", no_argument, 0, 'w'},
41 {"help", no_argument, 0, 'h'},
42 {NULL, 0, 0, 0}
43};
44
45static void help(const char *progname)
46{
47 fprintf(stderr,
48 "Usage:\n"
49 "\t%s [options] modulename ...\n"
50 "Options:\n"
51 "\t-f, --force forces a module unload and may crash your\n"
52 "\t machine. This requires Forced Module Removal\n"
53 "\t option in your kernel. DANGEROUS\n"
54 "\t-s, --syslog print to syslog, not stderr\n"
55 "\t-v, --verbose enables more messages\n"
56 "\t-V, --version show version\n"
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -020057 "\t-h, --help show this help\n",
58 progname);
59}
60
61static void log_syslog(void *data, int priority, const char *file, int line,
62 const char *fn, const char *format,
63 va_list args)
64{
65 char *str, buf[32];
66 const char *prioname;
67
68 switch (priority) {
69 case LOG_CRIT:
70 prioname = "FATAL";
71 break;
72 case LOG_ERR:
73 prioname = "ERROR";
74 break;
75 case LOG_WARNING:
76 prioname = "WARNING";
77 break;
78 case LOG_NOTICE:
79 prioname = "NOTICE";
80 break;
81 case LOG_INFO:
82 prioname = "INFO";
83 break;
84 case LOG_DEBUG:
85 prioname = "DEBUG";
86 break;
87 default:
88 snprintf(buf, sizeof(buf), "LOG-%03d", priority);
89 prioname = buf;
90 }
91
92 if (vasprintf(&str, format, args) < 0)
93 return;
94#ifdef ENABLE_DEBUG
95 syslog(LOG_NOTICE, "%s: %s:%d %s() %s", prioname, file, line, fn, str);
96#else
97 syslog(LOG_NOTICE, "%s: %s", prioname, str);
98#endif
99 free(str);
100 (void)data;
101}
102
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500103static int check_module_inuse(struct kmod_module *mod) {
104 struct kmod_list *holders;
105
106 if (kmod_module_get_initstate(mod) == -ENOENT) {
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200107 ERR("Module %s is not currently loaded\n",
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500108 kmod_module_get_name(mod));
109 return -ENOENT;
110 }
111
112 holders = kmod_module_get_holders(mod);
113 if (holders != NULL) {
114 struct kmod_list *itr;
115
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200116 ERR("Module %s is in use by:", kmod_module_get_name(mod));
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500117
118 kmod_list_foreach(itr, holders) {
119 struct kmod_module *hm = kmod_module_get_module(itr);
120 fprintf(stderr, " %s", kmod_module_get_name(hm));
121 kmod_module_unref(hm);
122 }
123 fputc('\n', stderr);
124
125 kmod_module_unref_list(holders);
126 return -EBUSY;
127 }
128
129 if (kmod_module_get_refcnt(mod) != 0) {
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200130 ERR("Module %s is in use\n", kmod_module_get_name(mod));
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500131 return -EBUSY;
132 }
133
134 return 0;
135}
136
Lucas De Marchif712ebc2011-12-22 03:39:11 -0200137static int do_rmmod(int argc, char *argv[])
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200138{
139 struct kmod_ctx *ctx;
Lucas De Marchi2411c072011-12-12 15:41:02 -0200140 const char *null_config = NULL;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200141 int flags = KMOD_REMOVE_NOWAIT;
142 int use_syslog = 0;
143 int verbose = 0;
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500144 int i, err, r = 0;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200145
146 for (;;) {
147 int c, idx = 0;
148 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
149 if (c == -1)
150 break;
151 switch (c) {
152 case 'f':
153 flags |= KMOD_REMOVE_FORCE;
154 break;
155 case 's':
156 use_syslog = 1;
157 break;
158 case 'v':
159 verbose++;
160 break;
161 case 'w':
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200162 ERR("'Wait' behavior is targeted for removal from kernel.\nWe will now sleep for 10s, and then continue.\n");
Lucas De Marchicc833642012-10-17 18:32:56 -0300163 sleep(10);
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200164 flags &= ~KMOD_REMOVE_NOWAIT;
165 break;
166 case 'h':
Lucas De Marchiaa156c92012-01-05 08:15:51 -0200167 help(basename(argv[0]));
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200168 return EXIT_SUCCESS;
169 case 'V':
170 puts(PACKAGE " version " VERSION);
171 return EXIT_SUCCESS;
172 case '?':
173 return EXIT_FAILURE;
174 default:
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200175 ERR("unexpected getopt_long() value '%c'.\n", c);
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200176 return EXIT_FAILURE;
177 }
178 }
179
180 if (optind >= argc) {
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200181 ERR("missing module name.\n");
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200182 return EXIT_FAILURE;
183 }
184
Lucas De Marchi2411c072011-12-12 15:41:02 -0200185 ctx = kmod_new(NULL, &null_config);
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200186 if (!ctx) {
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200187 ERR("kmod_new() failed!\n");
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200188 return EXIT_FAILURE;
189 }
190
191 kmod_set_log_priority(ctx, kmod_get_log_priority(ctx) + verbose);
192 if (use_syslog) {
193 openlog("rmmod", LOG_CONS, LOG_DAEMON);
194 kmod_set_log_fn(ctx, log_syslog, NULL);
195 }
196
197 for (i = optind; i < argc; i++) {
198 struct kmod_module *mod;
199 const char *arg = argv[i];
200 struct stat st;
201 if (stat(arg, &st) == 0)
202 err = kmod_module_new_from_path(ctx, arg, &mod);
203 else
204 err = kmod_module_new_from_name(ctx, arg, &mod);
205
206 if (err < 0) {
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200207 ERR("could not use module %s: %s\n", arg,
208 strerror(-err));
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200209 break;
210 }
211
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500212 if (!(flags & KMOD_REMOVE_FORCE) && (flags & KMOD_REMOVE_NOWAIT))
213 if (check_module_inuse(mod) < 0) {
214 r++;
215 goto next;
216 }
217
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200218 err = kmod_module_remove_module(mod, flags);
219 if (err < 0) {
Lucas De Marchi04c26d22012-11-05 17:51:32 -0200220 ERR("could not remove module %s: %s\n", arg,
221 strerror(-err));
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500222 r++;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200223 }
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500224next:
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200225 kmod_module_unref(mod);
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200226 }
227
228 kmod_unref(ctx);
229
230 if (use_syslog)
231 closelog();
232
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500233 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200234}
Lucas De Marchif712ebc2011-12-22 03:39:11 -0200235
Lucas De Marchif712ebc2011-12-22 03:39:11 -0200236#include "kmod.h"
237
238const struct kmod_cmd kmod_cmd_compat_rmmod = {
239 .name = "rmmod",
240 .cmd = do_rmmod,
241 .help = "compat rmmod command",
242};