blob: 33a73ca324348d36d369ebd5fe00ec996cee82b1 [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
31
32static const char cmdopts_s[] = "fsvVwh";
33static const struct option cmdopts[] = {
34 {"force", no_argument, 0, 'f'},
35 {"syslog", no_argument, 0, 's'},
36 {"verbose", no_argument, 0, 'v'},
37 {"version", no_argument, 0, 'V'},
38 {"wait", no_argument, 0, 'w'},
39 {"help", no_argument, 0, 'h'},
40 {NULL, 0, 0, 0}
41};
42
43static void help(const char *progname)
44{
45 fprintf(stderr,
46 "Usage:\n"
47 "\t%s [options] modulename ...\n"
48 "Options:\n"
49 "\t-f, --force forces a module unload and may crash your\n"
50 "\t machine. This requires Forced Module Removal\n"
51 "\t option in your kernel. DANGEROUS\n"
52 "\t-s, --syslog print to syslog, not stderr\n"
53 "\t-v, --verbose enables more messages\n"
54 "\t-V, --version show version\n"
55 "\t-w, --wait begins module removal even if it is used and\n"
56 "\t will stop new users from accessing it.\n"
57 "\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) {
107 fprintf(stderr, "Error: Module %s is not currently loaded\n",
108 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
116 fprintf(stderr, "Error: Module %s is in use by:",
117 kmod_module_get_name(mod));
118
119 kmod_list_foreach(itr, holders) {
120 struct kmod_module *hm = kmod_module_get_module(itr);
121 fprintf(stderr, " %s", kmod_module_get_name(hm));
122 kmod_module_unref(hm);
123 }
124 fputc('\n', stderr);
125
126 kmod_module_unref_list(holders);
127 return -EBUSY;
128 }
129
130 if (kmod_module_get_refcnt(mod) != 0) {
131 fprintf(stderr, "Error: Module %s is in use\n",
132 kmod_module_get_name(mod));
133 return -EBUSY;
134 }
135
136 return 0;
137}
138
Lucas De Marchif712ebc2011-12-22 03:39:11 -0200139static int do_rmmod(int argc, char *argv[])
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200140{
141 struct kmod_ctx *ctx;
Lucas De Marchi2411c072011-12-12 15:41:02 -0200142 const char *null_config = NULL;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200143 int flags = KMOD_REMOVE_NOWAIT;
144 int use_syslog = 0;
145 int verbose = 0;
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500146 int i, err, r = 0;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200147
148 for (;;) {
149 int c, idx = 0;
150 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
151 if (c == -1)
152 break;
153 switch (c) {
154 case 'f':
155 flags |= KMOD_REMOVE_FORCE;
156 break;
157 case 's':
158 use_syslog = 1;
159 break;
160 case 'v':
161 verbose++;
162 break;
163 case 'w':
164 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:
175 fprintf(stderr,
176 "Error: unexpected getopt_long() value '%c'.\n",
177 c);
178 return EXIT_FAILURE;
179 }
180 }
181
182 if (optind >= argc) {
183 fprintf(stderr, "Error: missing module name.\n");
184 return EXIT_FAILURE;
185 }
186
Lucas De Marchi2411c072011-12-12 15:41:02 -0200187 ctx = kmod_new(NULL, &null_config);
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200188 if (!ctx) {
189 fputs("Error: kmod_new() failed!\n", stderr);
190 return EXIT_FAILURE;
191 }
192
193 kmod_set_log_priority(ctx, kmod_get_log_priority(ctx) + verbose);
194 if (use_syslog) {
195 openlog("rmmod", LOG_CONS, LOG_DAEMON);
196 kmod_set_log_fn(ctx, log_syslog, NULL);
197 }
198
199 for (i = optind; i < argc; i++) {
200 struct kmod_module *mod;
201 const char *arg = argv[i];
202 struct stat st;
203 if (stat(arg, &st) == 0)
204 err = kmod_module_new_from_path(ctx, arg, &mod);
205 else
206 err = kmod_module_new_from_name(ctx, arg, &mod);
207
208 if (err < 0) {
209 fprintf(stderr, "Error: could not use module %s: %s\n",
210 arg, strerror(-err));
211 break;
212 }
213
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500214 if (!(flags & KMOD_REMOVE_FORCE) && (flags & KMOD_REMOVE_NOWAIT))
215 if (check_module_inuse(mod) < 0) {
216 r++;
217 goto next;
218 }
219
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200220 err = kmod_module_remove_module(mod, flags);
221 if (err < 0) {
222 fprintf(stderr,
223 "Error: could not remove module %s: %s\n",
224 arg, strerror(-err));
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500225 r++;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200226 }
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500227next:
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200228 kmod_module_unref(mod);
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200229 }
230
231 kmod_unref(ctx);
232
233 if (use_syslog)
234 closelog();
235
Dave Reisner6da9cdf2012-01-10 19:28:30 -0500236 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
Gustavo Sverzut Barbieri72c51a92011-12-10 22:19:41 -0200237}
Lucas De Marchif712ebc2011-12-22 03:39:11 -0200238
239#ifndef KMOD_BUNDLE_TOOL
240int main(int argc, char *argv[])
241{
242 return do_rmmod(argc, argv);
243}
244
245#else
246#include "kmod.h"
247
248const struct kmod_cmd kmod_cmd_compat_rmmod = {
249 .name = "rmmod",
250 .cmd = do_rmmod,
251 .help = "compat rmmod command",
252};
253
254#endif