blob: 0dea87875e31014be1a205e563dfaee3cfed9ce7 [file] [log] [blame]
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -02001/*
Lucas De Marchi8b013762012-01-12 17:14:30 -02002 * kmod-modprobe - manage linux kernel modules using libkmod.
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -02003 *
Lucas De Marchia66a6a92012-01-09 00:40:50 -02004 * Copyright (C) 2011-2012 ProFUSION embedded systems
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -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 Barbieric3d0a5f2011-12-11 19:36:18 -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 Barbieric3d0a5f2011-12-11 19:36:18 -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 Barbieric3d0a5f2011-12-11 19:36:18 -020018 */
Lucas De Marchicb451f32011-12-12 18:24:35 -020019
Lucas De Marchi4744ebc2012-03-15 00:14:35 -030020#include <assert.h>
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020021#include <stdio.h>
22#include <stdlib.h>
Lucas De Marchi0cf28322012-01-12 02:21:26 -020023#include <stdbool.h>
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020024#include <getopt.h>
25#include <errno.h>
26#include <string.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/utsname.h>
Thierry Vignaudeff917c2012-01-17 17:32:48 -020030#include <sys/wait.h>
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020031#include <unistd.h>
32#include <syslog.h>
33#include <limits.h>
34
35#include "libkmod.h"
Lucas De Marchi8b013762012-01-12 17:14:30 -020036#include "libkmod-array.h"
Lucas De Marchibc434962012-01-13 02:35:34 -020037#include "macro.h"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020038
Lucas De Marchi4a2e20d2012-11-06 16:54:17 -020039#include "kmod.h"
40
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020041static int log_priority = LOG_CRIT;
42static int use_syslog = 0;
43
44#define DEFAULT_VERBOSE LOG_WARNING
45static int verbose = DEFAULT_VERBOSE;
Gustavo Sverzut Barbieri525fa072012-01-08 13:58:28 -020046static int do_show = 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020047static int dry_run = 0;
48static int ignore_loaded = 0;
Lucas De Marchi81229852011-12-16 02:58:48 -020049static int lookup_only = 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020050static int first_time = 0;
51static int ignore_commands = 0;
52static int use_blacklist = 0;
53static int force = 0;
54static int strip_modversion = 0;
55static int strip_vermagic = 0;
56static int remove_dependencies = 0;
Lucas De Marchid8a6c0c2012-01-01 06:07:46 -020057static int quiet_inuse = 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020058
Dave Reisnercc988302012-01-26 11:36:35 -050059static const char cmdopts_s[] = "arRibfDcnC:d:S:sqvVh";
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020060static const struct option cmdopts[] = {
61 {"all", no_argument, 0, 'a'},
62 {"remove", no_argument, 0, 'r'},
63 {"remove-dependencies", no_argument, 0, 5},
64 {"resolve-alias", no_argument, 0, 'R'},
65 {"first-time", no_argument, 0, 3},
66 {"ignore-install", no_argument, 0, 'i'},
67 {"ignore-remove", no_argument, 0, 'i'},
68 {"use-blacklist", no_argument, 0, 'b'},
69 {"force", no_argument, 0, 'f'},
70 {"force-modversion", no_argument, 0, 2},
71 {"force-vermagic", no_argument, 0, 1},
72
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020073 {"show-depends", no_argument, 0, 'D'},
74 {"showconfig", no_argument, 0, 'c'},
75 {"show-config", no_argument, 0, 'c'},
76 {"show-modversions", no_argument, 0, 4},
77 {"dump-modversions", no_argument, 0, 4},
78
79 {"dry-run", no_argument, 0, 'n'},
80 {"show", no_argument, 0, 'n'},
81
82 {"config", required_argument, 0, 'C'},
83 {"dirname", required_argument, 0, 'd'},
84 {"set-version", required_argument, 0, 'S'},
85
86 {"syslog", no_argument, 0, 's'},
87 {"quiet", no_argument, 0, 'q'},
88 {"verbose", no_argument, 0, 'v'},
89 {"version", no_argument, 0, 'V'},
90 {"help", no_argument, 0, 'h'},
91 {NULL, 0, 0, 0}
92};
93
Lucas De Marchi4a2e20d2012-11-06 16:54:17 -020094static void help(void)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020095{
Lucas De Marchi34e06bf2012-11-06 17:32:41 -020096 printf("Usage:\n"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -020097 "\t%s [options] [-i] [-b] modulename\n"
98 "\t%s [options] -a [-i] [-b] modulename [modulename...]\n"
99 "\t%s [options] -r [-i] modulename\n"
100 "\t%s [options] -r -a [-i] modulename [modulename...]\n"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200101 "\t%s [options] -c\n"
102 "\t%s [options] --dump-modversions filename\n"
103 "Management Options:\n"
Gustavo Sverzut Barbieriab70dce2011-12-19 13:02:15 -0200104 "\t-a, --all Consider every non-argument to\n"
105 "\t be a module name to be inserted\n"
106 "\t or removed (-r)\n"
107 "\t-r, --remove Remove modules instead of inserting\n"
108 "\t --remove-dependencies Also remove modules depending on it\n"
109 "\t-R, --resolve-alias Only lookup and print alias and exit\n"
110 "\t --first-time Fail if module already inserted or removed\n"
111 "\t-i, --ignore-install Ignore install commands\n"
112 "\t-i, --ignore-remove Ignore remove commands\n"
113 "\t-b, --use-blacklist Apply blacklist to resolved alias.\n"
114 "\t-f, --force Force module insertion or removal.\n"
115 "\t implies --force-modversions and\n"
116 "\t --force-vermagic\n"
117 "\t --force-modversion Ignore module's version\n"
118 "\t --force-vermagic Ignore module's version magic\n"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200119 "\n"
120 "Query Options:\n"
Gustavo Sverzut Barbieriab70dce2011-12-19 13:02:15 -0200121 "\t-D, --show-depends Only print module dependencies and exit\n"
122 "\t-c, --showconfig Print out known configuration and exit\n"
123 "\t-c, --show-config Same as --showconfig\n"
124 "\t --show-modversions Dump module symbol version and exit\n"
125 "\t --dump-modversions Same as --show-modversions\n"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200126 "\n"
127 "General Options:\n"
Gustavo Sverzut Barbieriab70dce2011-12-19 13:02:15 -0200128 "\t-n, --dry-run Do not execute operations, just print out\n"
129 "\t-n, --show Same as --dry-run\n"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200130
Lucas De Marchi2c966932011-12-20 16:39:59 -0200131 "\t-C, --config=FILE Use FILE instead of default search paths\n"
Dave Reisnerc5b37db2012-09-27 11:00:42 -0400132 "\t-d, --dirname=DIR Use DIR as filesystem root for /lib/modules\n"
Gustavo Sverzut Barbieriab70dce2011-12-19 13:02:15 -0200133 "\t-S, --set-version=VERSION Use VERSION instead of `uname -r`\n"
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200134
135 "\t-s, --syslog print to syslog, not stderr\n"
136 "\t-q, --quiet disable messages\n"
137 "\t-v, --verbose enables more messages\n"
138 "\t-V, --version show version\n"
139 "\t-h, --help show this help\n",
Lucas De Marchi4a2e20d2012-11-06 16:54:17 -0200140 binname, binname, binname, binname, binname, binname);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200141}
142
143static inline void _show(const char *fmt, ...)
144{
145 va_list args;
146
Gustavo Sverzut Barbieri525fa072012-01-08 13:58:28 -0200147 if (!do_show && verbose <= DEFAULT_VERBOSE)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200148 return;
149
150 va_start(args, fmt);
151 vfprintf(stdout, fmt, args);
152 fflush(stdout);
153 va_end(args);
154}
155
Lucas De Marchi07df56e2012-11-01 12:39:18 -0200156static void log_modprobe(void *data, int priority, const char *file, int line,
157 const char *fn, const char *format, va_list args)
158{
159 const char *prioname = prio_to_str(priority);
160 char *str;
161
162 if (vasprintf(&str, format, args) < 0)
163 return;
164
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200165 if (use_syslog > 1) {
Lucas De Marchi07df56e2012-11-01 12:39:18 -0200166#ifdef ENABLE_DEBUG
167 syslog(priority, "%s: %s:%d %s() %s", prioname, file, line,
168 fn, str);
169#else
170 syslog(priority, "%s: %s", prioname, str);
171#endif
172 } else {
173#ifdef ENABLE_DEBUG
174 fprintf(stderr, "modprobe: %s: %s:%d %s() %s", prioname, file,
175 line, fn, str);
176#else
177 fprintf(stderr, "modprobe: %s: %s", prioname, str);
178#endif
179 }
180
181 free(str);
182 (void)data;
183}
184
Lucas De Marchid96ae032012-11-01 12:45:23 -0200185static void _log(int prio, const char *fmt, ...)
Lucas De Marchi1e947e32012-10-31 22:00:40 -0200186{
187 const char *prioname;
188 char *msg;
189 va_list args;
190
191 if (prio > verbose)
192 return;
193
194 va_start(args, fmt);
195 if (vasprintf(&msg, fmt, args) < 0)
196 msg = NULL;
197 va_end(args);
198 if (msg == NULL)
199 return;
200
201 prioname = prio_to_str(prio);
202
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200203 if (use_syslog > 1)
Lucas De Marchid96ae032012-11-01 12:45:23 -0200204 syslog(prio, "%s: %s", prioname, msg);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200205 else
Lucas De Marchid96ae032012-11-01 12:45:23 -0200206 fprintf(stderr, "modprobe: %s: %s", prioname, msg);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200207 free(msg);
208
209 if (prio <= LOG_CRIT)
210 exit(EXIT_FAILURE);
211}
212#define ERR(...) _log(LOG_ERR, __VA_ARGS__)
213#define WRN(...) _log(LOG_WARNING, __VA_ARGS__)
214#define INF(...) _log(LOG_INFO, __VA_ARGS__)
215#define DBG(...) _log(LOG_DEBUG, __VA_ARGS__)
216#define LOG(...) _log(log_priority, __VA_ARGS__)
217#define SHOW(...) _show(__VA_ARGS__)
218
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200219static int show_config(struct kmod_ctx *ctx)
220{
Lucas De Marchibc434962012-01-13 02:35:34 -0200221 struct config_iterators {
222 const char *name;
223 struct kmod_config_iter *(*get_iter)(const struct kmod_ctx *ctx);
224 } ci[] = {
225 { "blacklist", kmod_config_get_blacklists },
226 { "install", kmod_config_get_install_commands },
227 { "remove", kmod_config_get_remove_commands },
228 { "alias", kmod_config_get_aliases },
Elan Ruusamäe02629fa2012-03-22 12:00:16 -0300229 { "options", kmod_config_get_options },
Lucas De Marchibc434962012-01-13 02:35:34 -0200230 { "softdep", kmod_config_get_softdeps },
231 };
232 size_t i;
233
234 for (i = 0; i < ARRAY_SIZE(ci); i++) {
235 struct kmod_config_iter *iter = ci[i].get_iter(ctx);
236
237 if (iter == NULL)
238 continue;
239
240 while (kmod_config_iter_next(iter)) {
241 const char *val;
242
243 printf("%s %s", ci[i].name,
244 kmod_config_iter_get_key(iter));
245 val = kmod_config_iter_get_value(iter);
246 if (val != NULL) {
247 putchar(' ');
248 puts(val);
249 } else
250 putchar('\n');
251 }
252
253 kmod_config_iter_free_iter(iter);
254 }
255
Lucas De Marchi28f32c62012-01-27 23:56:46 -0200256 puts("\n# End of configuration files. Dumping indexes now:\n");
Lucas De Marchi09e9ae52012-01-17 10:05:02 -0200257 fflush(stdout);
258
Lucas De Marchi49a16372012-01-16 16:00:35 -0200259 kmod_dump_index(ctx, KMOD_INDEX_MODULES_ALIAS, STDOUT_FILENO);
260 kmod_dump_index(ctx, KMOD_INDEX_MODULES_SYMBOL, STDOUT_FILENO);
261
Lucas De Marchibc434962012-01-13 02:35:34 -0200262 return 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200263}
264
265static int show_modversions(struct kmod_ctx *ctx, const char *filename)
266{
Gustavo Sverzut Barbieri0e3e2f42011-12-19 12:45:22 -0200267 struct kmod_list *l, *list = NULL;
268 struct kmod_module *mod;
269 int err = kmod_module_new_from_path(ctx, filename, &mod);
270 if (err < 0) {
271 LOG("Module %s not found.\n", filename);
272 return err;
273 }
274
275 err = kmod_module_get_versions(mod, &list);
276 if (err < 0) {
Dave Reisner63698372012-01-04 10:41:50 -0500277 LOG("could not get modversions of %s: %s\n",
Gustavo Sverzut Barbieri0e3e2f42011-12-19 12:45:22 -0200278 filename, strerror(-err));
279 kmod_module_unref(mod);
280 return err;
281 }
282
283 kmod_list_foreach(l, list) {
284 const char *symbol = kmod_module_version_get_symbol(l);
285 uint64_t crc = kmod_module_version_get_crc(l);
286 printf("0x%08"PRIx64"\t%s\n", crc, symbol);
287 }
288 kmod_module_versions_free_list(list);
289 kmod_module_unref(mod);
290 return 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200291}
292
Lucas De Marchi8f192212012-01-11 15:38:50 -0200293static int command_do(struct kmod_module *module, const char *type,
294 const char *command, const char *cmdline_opts)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200295{
296 const char *modname = kmod_module_get_name(module);
297 char *p, *cmd = NULL;
298 size_t cmdlen, cmdline_opts_len, varlen;
299 int ret = 0;
300
301 if (cmdline_opts == NULL)
302 cmdline_opts = "";
303 cmdline_opts_len = strlen(cmdline_opts);
304
305 cmd = strdup(command);
306 if (cmd == NULL)
307 return -ENOMEM;
308 cmdlen = strlen(cmd);
309 varlen = sizeof("$CMDLINE_OPTS") - 1;
310 while ((p = strstr(cmd, "$CMDLINE_OPTS")) != NULL) {
311 size_t prefixlen = p - cmd;
312 size_t suffixlen = cmdlen - prefixlen - varlen;
313 size_t slen = cmdlen - varlen + cmdline_opts_len;
314 char *suffix = p + varlen;
315 char *s = malloc(slen + 1);
316 if (s == NULL) {
317 free(cmd);
318 return -ENOMEM;
319 }
320 memcpy(s, cmd, p - cmd);
321 memcpy(s + prefixlen, cmdline_opts, cmdline_opts_len);
322 memcpy(s + prefixlen + cmdline_opts_len, suffix, suffixlen);
323 s[slen] = '\0';
324
325 free(cmd);
326 cmd = s;
327 cmdlen = slen;
328 }
329
330 SHOW("%s %s\n", type, cmd);
331 if (dry_run)
332 goto end;
333
334 setenv("MODPROBE_MODULE", modname, 1);
335 ret = system(cmd);
336 unsetenv("MODPROBE_MODULE");
337 if (ret == -1 || WEXITSTATUS(ret)) {
338 LOG("Error running %s command for %s\n", type, modname);
339 if (ret != -1)
340 ret = -WEXITSTATUS(ret);
341 }
342
343end:
344 free(cmd);
345 return ret;
346}
347
Lucas De Marchia872bba2012-01-12 15:23:51 -0200348static int rmmod_do_remove_module(struct kmod_module *mod)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200349{
Lucas De Marchia872bba2012-01-12 15:23:51 -0200350 const char *modname = kmod_module_get_name(mod);
Dave Reisner69a19742012-01-30 17:16:50 -0500351 struct kmod_list *deps, *itr;
Lucas De Marchia872bba2012-01-12 15:23:51 -0200352 int flags = 0, err;
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200353
Lucas De Marchia872bba2012-01-12 15:23:51 -0200354 SHOW("rmmod %s\n", kmod_module_get_name(mod));
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200355
Lucas De Marchia872bba2012-01-12 15:23:51 -0200356 if (dry_run)
357 return 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200358
Lucas De Marchia872bba2012-01-12 15:23:51 -0200359 if (force)
360 flags |= KMOD_REMOVE_FORCE;
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200361
Lucas De Marchia872bba2012-01-12 15:23:51 -0200362 err = kmod_module_remove_module(mod, flags);
363 if (err == -EEXIST) {
364 if (!first_time)
365 err = 0;
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200366 else
Lucas De Marchia872bba2012-01-12 15:23:51 -0200367 LOG("Module %s is not in kernel.\n", modname);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200368 }
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200369
Dave Reisner69a19742012-01-30 17:16:50 -0500370 deps = kmod_module_get_dependencies(mod);
371 if (deps != NULL) {
372 kmod_list_foreach(itr, deps) {
373 struct kmod_module *dep = kmod_module_get_module(itr);
374 if (kmod_module_get_refcnt(dep) == 0)
375 rmmod_do_remove_module(dep);
376 kmod_module_unref(dep);
377 }
378 kmod_module_unref_list(deps);
379 }
380
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200381 return err;
382}
383
Lucas De Marchia872bba2012-01-12 15:23:51 -0200384static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies);
385
386static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors)
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200387{
Lucas De Marchia872bba2012-01-12 15:23:51 -0200388 struct kmod_list *l;
389
390 kmod_list_foreach_reverse(l, list) {
391 struct kmod_module *m = kmod_module_get_module(l);
392 int r = rmmod_do_module(m, false);
393 kmod_module_unref(m);
394
395 if (r < 0 && stop_on_errors)
396 return r;
397 }
398
399 return 0;
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200400}
401
Lucas De Marchia872bba2012-01-12 15:23:51 -0200402static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200403{
404 const char *modname = kmod_module_get_name(mod);
Lucas De Marchia872bba2012-01-12 15:23:51 -0200405 struct kmod_list *pre = NULL, *post = NULL;
406 const char *cmd = NULL;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200407 int err;
408
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200409 if (!ignore_commands) {
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200410 err = kmod_module_get_softdeps(mod, &pre, &post);
411 if (err < 0) {
412 WRN("could not get softdeps of '%s': %s\n",
Lucas De Marchi8f192212012-01-11 15:38:50 -0200413 modname, strerror(-err));
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200414 return err;
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200415 }
416
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200417 cmd = kmod_module_get_remove_commands(mod);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200418 }
419
Lucas De Marchia872bba2012-01-12 15:23:51 -0200420 if (cmd == NULL && !ignore_loaded) {
Lucas De Marchi9bf60d22011-12-19 02:18:14 -0200421 int state = kmod_module_get_initstate(mod);
422
Lucas De Marchie5e2a682011-12-19 02:26:34 -0200423 if (state < 0) {
Dave Reisnerf758caf2012-03-14 22:15:21 -0400424 if (first_time) {
425 LOG("Module %s is not in kernel.\n", modname);
426 err = -ENOENT;
427 } else {
428 err = 0;
429 }
Lucas De Marchie4e1e642012-01-12 15:36:54 -0200430 goto error;
Lucas De Marchie5e2a682011-12-19 02:26:34 -0200431 } else if (state == KMOD_MODULE_BUILTIN) {
Lucas De Marchi9bf60d22011-12-19 02:18:14 -0200432 LOG("Module %s is builtin.\n", modname);
Lucas De Marchie4e1e642012-01-12 15:36:54 -0200433 err = -ENOENT;
434 goto error;
Lucas De Marchi9bf60d22011-12-19 02:18:14 -0200435 }
436 }
437
Lucas De Marchia872bba2012-01-12 15:23:51 -0200438 rmmod_do_deps_list(post, false);
439
440 if (do_dependencies && remove_dependencies) {
441 struct kmod_list *deps = kmod_module_get_dependencies(mod);
442
443 err = rmmod_do_deps_list(deps, true);
Lucas De Marchi9bf60d22011-12-19 02:18:14 -0200444 if (err < 0)
Lucas De Marchia872bba2012-01-12 15:23:51 -0200445 goto error;
Lucas De Marchi9bf60d22011-12-19 02:18:14 -0200446 }
447
448 if (!ignore_loaded) {
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200449 int usage = kmod_module_get_refcnt(mod);
Lucas De Marchid8a6c0c2012-01-01 06:07:46 -0200450
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200451 if (usage > 0) {
Lucas De Marchid8a6c0c2012-01-01 06:07:46 -0200452 if (!quiet_inuse)
453 LOG("Module %s is in use.\n", modname);
454
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200455 err = -EBUSY;
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200456 goto error;
457 }
458 }
459
Lucas De Marchia872bba2012-01-12 15:23:51 -0200460 if (cmd == NULL)
461 err = rmmod_do_remove_module(mod);
462 else
463 err = command_do(mod, "remove", cmd, NULL);
Lucas De Marchid8a6c0c2012-01-01 06:07:46 -0200464
Lucas De Marchia872bba2012-01-12 15:23:51 -0200465 if (err < 0)
466 goto error;
Lucas De Marchid8a6c0c2012-01-01 06:07:46 -0200467
Lucas De Marchia872bba2012-01-12 15:23:51 -0200468 rmmod_do_deps_list(pre, false);
Dave Reisner0e9bd2d2011-12-31 18:02:45 -0500469
Gustavo Sverzut Barbierie793f1e2011-12-16 22:35:28 -0200470error:
471 kmod_module_unref_list(pre);
472 kmod_module_unref_list(post);
Lucas De Marchia872bba2012-01-12 15:23:51 -0200473
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200474 return err;
475}
476
Lucas De Marchi569f1602012-01-21 02:45:06 -0200477static int rmmod(struct kmod_ctx *ctx, const char *alias)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200478{
479 struct kmod_list *l, *list = NULL;
480 int err;
481
482 err = kmod_module_new_from_lookup(ctx, alias, &list);
Lucas De Marchie5e2a682011-12-19 02:26:34 -0200483 if (err < 0)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200484 return err;
Lucas De Marchie5e2a682011-12-19 02:26:34 -0200485
Dave Reisnerf758caf2012-03-14 22:15:21 -0400486 if (list == NULL) {
Lucas De Marchie5e2a682011-12-19 02:26:34 -0200487 LOG("Module %s not found.\n", alias);
Dave Reisnerf758caf2012-03-14 22:15:21 -0400488 err = -ENOENT;
489 }
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200490
491 kmod_list_foreach(l, list) {
492 struct kmod_module *mod = kmod_module_get_module(l);
Lucas De Marchia872bba2012-01-12 15:23:51 -0200493 err = rmmod_do_module(mod, true);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200494 kmod_module_unref(mod);
495 if (err < 0)
496 break;
497 }
498
499 kmod_module_unref_list(list);
500 return err;
501}
502
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200503static int rmmod_all(struct kmod_ctx *ctx, char **args, int nargs)
504{
505 int i, err = 0;
506
507 for (i = 0; i < nargs; i++) {
508 int r = rmmod(ctx, args[i]);
509 if (r < 0)
510 err = r;
511 }
512
513 return err;
514}
515
Lucas De Marchi92122612012-01-11 21:48:08 -0200516static int handle_failed_lookup(struct kmod_ctx *ctx, const char *alias)
517{
518 struct kmod_module *mod;
519 int state, err;
520
521 DBG("lookup failed - trying to check if it's builtin\n");
522
523 err = kmod_module_new_from_name(ctx, alias, &mod);
524 if (err < 0)
525 return err;
526
527 state = kmod_module_get_initstate(mod);
528 kmod_module_unref(mod);
529
530 if (state != KMOD_MODULE_BUILTIN) {
531 LOG("Module %s not found.\n", alias);
532 return -ENOENT;
533 }
534
535 if (first_time) {
536 LOG("Module %s already in kernel (builtin).\n", alias);
537 return -ENOENT;
538 }
539
540 SHOW("builtin %s\n", alias);
541 return 0;
542}
543
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200544static void print_action(struct kmod_module *m, bool install,
545 const char *options)
546{
Lucas De Marchi4744ebc2012-03-15 00:14:35 -0300547 const char *path;
548
549 if (install) {
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200550 printf("install %s %s\n", kmod_module_get_install_commands(m),
551 options);
Lucas De Marchi4744ebc2012-03-15 00:14:35 -0300552 return;
553 }
554
555 path = kmod_module_get_path(m);
556
557 if (path == NULL) {
558 assert(kmod_module_get_initstate(m) == KMOD_MODULE_BUILTIN);
559 printf("builtin %s\n", kmod_module_get_name(m));
560 } else
561 printf("insmod %s %s\n", kmod_module_get_path(m), options);
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200562}
563
Lucas De Marchi569f1602012-01-21 02:45:06 -0200564static int insmod(struct kmod_ctx *ctx, const char *alias,
Lucas De Marchi8f192212012-01-11 15:38:50 -0200565 const char *extra_options)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200566{
567 struct kmod_list *l, *list = NULL;
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200568 int err, flags = 0;
569
570 void (*show)(struct kmod_module *m, bool install,
571 const char *options) = NULL;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200572
573 err = kmod_module_new_from_lookup(ctx, alias, &list);
Lucas De Marchie5e2a682011-12-19 02:26:34 -0200574 if (err < 0)
575 return err;
576
Lucas De Marchi92122612012-01-11 21:48:08 -0200577 if (list == NULL)
578 return handle_failed_lookup(ctx, alias);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200579
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200580 if (strip_modversion || force)
581 flags |= KMOD_PROBE_FORCE_MODVERSION;
582 if (strip_vermagic || force)
583 flags |= KMOD_PROBE_FORCE_VERMAGIC;
584 if (ignore_commands)
585 flags |= KMOD_PROBE_IGNORE_COMMAND;
586 if (ignore_loaded)
587 flags |= KMOD_PROBE_IGNORE_LOADED;
588 if (dry_run)
589 flags |= KMOD_PROBE_DRY_RUN;
590 if (do_show || verbose > DEFAULT_VERBOSE)
591 show = &print_action;
592
Lucas De Marchi36ddee62012-08-17 09:42:47 -0300593 flags |= KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY;
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200594
595 if (use_blacklist)
596 flags |= KMOD_PROBE_APPLY_BLACKLIST;
597 if (first_time)
Lucas De Marchi814a57b2012-02-06 12:46:39 -0200598 flags |= KMOD_PROBE_FAIL_ON_LOADED;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200599
600 kmod_list_foreach(l, list) {
601 struct kmod_module *mod = kmod_module_get_module(l);
Lucas De Marchi8b013762012-01-12 17:14:30 -0200602
Lucas De Marchi81229852011-12-16 02:58:48 -0200603 if (lookup_only)
604 printf("%s\n", kmod_module_get_name(mod));
Lucas De Marchi8b013762012-01-12 17:14:30 -0200605 else {
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200606 err = kmod_module_probe_insert_module(mod, flags,
607 extra_options, NULL, NULL, show);
Lucas De Marchi8b013762012-01-12 17:14:30 -0200608 }
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200609
Dave Reisner297a3182012-01-30 20:57:36 -0500610 if (err >= 0)
611 /* ignore flag return values such as a mod being blacklisted */
612 err = 0;
613 else {
614 switch (err) {
615 case -EEXIST:
616 ERR("could not insert '%s': Module already in kernel\n",
617 kmod_module_get_name(mod));
618 break;
Dave Reisnerccb64d12012-04-16 10:37:32 -0400619 case -ENOENT:
620 ERR("could not insert '%s': Unknown symbol in module, "
621 "or unknown parameter (see dmesg)\n",
622 kmod_module_get_name(mod));
623 break;
Dave Reisner297a3182012-01-30 20:57:36 -0500624 default:
625 ERR("could not insert '%s': %s\n",
626 kmod_module_get_name(mod),
627 strerror(-err));
628 break;
629 }
Lucas De Marchi2e9dcd72012-01-30 19:01:24 -0200630 }
631
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200632 kmod_module_unref(mod);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200633 }
634
635 kmod_module_unref_list(list);
636 return err;
637}
638
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200639static int insmod_all(struct kmod_ctx *ctx, char **args, int nargs)
640{
641 int i, err = 0;
642
643 for (i = 0; i < nargs; i++) {
644 int r = insmod(ctx, args[i], NULL);
645 if (r < 0)
646 err = r;
647 }
648
649 return err;
650}
651
652static void env_modprobe_options_append(const char *value)
653{
654 const char *old = getenv("MODPROBE_OPTIONS");
655 char *env;
656
657 if (old == NULL) {
658 setenv("MODPROBE_OPTIONS", value, 1);
659 return;
660 }
661
662 if (asprintf(&env, "%s %s", old, value) < 0) {
663 ERR("could not append value to $MODPROBE_OPTIONS\n");
664 return;
665 }
666
667 if (setenv("MODPROBE_OPTIONS", env, 1) < 0)
668 ERR("could not setenv(MODPROBE_OPTIONS, \"%s\")\n", env);
669 free(env);
670}
671
672static int options_from_array(char **args, int nargs, char **output)
673{
674 char *opts = NULL;
675 size_t optslen = 0;
676 int i, err = 0;
677
678 for (i = 1; i < nargs; i++) {
679 size_t len = strlen(args[i]);
680 size_t qlen = 0;
681 const char *value;
682 void *tmp;
683
684 value = strchr(args[i], '=');
685 if (value) {
686 value++;
687 if (*value != '"' && *value != '\'') {
688 if (strchr(value, ' '))
689 qlen = 2;
690 }
691 }
692
693 tmp = realloc(opts, optslen + len + qlen + 2);
694 if (!tmp) {
695 err = -errno;
696 free(opts);
697 opts = NULL;
698 ERR("could not gather module options: out-of-memory\n");
699 break;
700 }
701 opts = tmp;
702 if (optslen > 0) {
703 opts[optslen] = ' ';
704 optslen++;
705 }
706 if (qlen == 0) {
707 memcpy(opts + optslen, args[i], len + 1);
708 optslen += len;
709 } else {
710 size_t keylen = value - args[i];
711 size_t valuelen = len - keylen;
712 memcpy(opts + optslen, args[i], keylen);
713 optslen += keylen;
714 opts[optslen] = '"';
715 optslen++;
716 memcpy(opts + optslen, value, valuelen);
717 optslen += valuelen;
718 opts[optslen] = '"';
719 optslen++;
720 opts[optslen] = '\0';
721 }
722 }
723
724 *output = opts;
725 return err;
726}
727
728static char **prepend_options_from_env(int *p_argc, char **orig_argv)
729{
730 const char *p, *env = getenv("MODPROBE_OPTIONS");
731 char **new_argv, *str_start, *str_end, *str, *s, *quote;
732 int i, argc = *p_argc;
733 size_t envlen, space_count = 0;
734
735 if (env == NULL)
736 return orig_argv;
737
738 for (p = env; *p != '\0'; p++) {
739 if (*p == ' ')
740 space_count++;
741 }
742
743 envlen = p - env;
744 new_argv = malloc(sizeof(char *) * (argc + space_count + 3 + envlen));
745 if (new_argv == NULL)
746 return NULL;
747
748 new_argv[0] = orig_argv[0];
749 str_start = str = (char *) (new_argv + argc + space_count + 3);
750 memcpy(str, env, envlen + 1);
751
752 str_end = str_start + envlen;
753
754 quote = NULL;
755 for (i = 1, s = str; *s != '\0'; s++) {
756 if (quote == NULL) {
757 if (*s == ' ') {
758 new_argv[i] = str;
759 i++;
760 *s = '\0';
761 str = s + 1;
762 } else if (*s == '"' || *s == '\'')
763 quote = s;
764 } else {
765 if (*s == *quote) {
766 if (quote == str) {
767 new_argv[i] = str + 1;
768 i++;
769 *s = '\0';
770 str = s + 1;
771 } else {
772 char *it;
773 for (it = quote; it < s - 1; it++)
774 it[0] = it[1];
775 for (it = s - 1; it < str_end - 2; it++)
776 it[0] = it[2];
777 str_end -= 2;
778 *str_end = '\0';
779 s -= 2;
780 }
781 quote = NULL;
782 }
783 }
784 }
785 if (str < s) {
786 new_argv[i] = str;
787 i++;
788 }
789
790 memcpy(new_argv + i, orig_argv + 1, sizeof(char *) * (argc - 1));
791 new_argv[i + argc] = NULL;
792 *p_argc = i + argc - 1;
793
794 return new_argv;
795}
796
Lucas De Marchifa29c0e2011-12-22 03:54:46 -0200797static int do_modprobe(int argc, char **orig_argv)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200798{
799 struct kmod_ctx *ctx;
800 char **args = NULL, **argv;
Gustavo Sverzut Barbiericb8d4d32011-12-11 20:37:01 -0200801 const char **config_paths = NULL;
802 int nargs = 0, n_config_paths = 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200803 char dirname_buf[PATH_MAX];
804 const char *dirname = NULL;
805 const char *root = NULL;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200806 const char *kversion = NULL;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200807 int use_all = 0;
808 int do_remove = 0;
809 int do_show_config = 0;
810 int do_show_modversions = 0;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200811 int err;
812
813 argv = prepend_options_from_env(&argc, orig_argv);
814 if (argv == NULL) {
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200815 ERR("Could not prepend options from command line\n");
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200816 return EXIT_FAILURE;
817 }
818
819 for (;;) {
820 int c, idx = 0;
821 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
822 if (c == -1)
823 break;
824 switch (c) {
825 case 'a':
826 log_priority = LOG_WARNING;
827 use_all = 1;
828 break;
829 case 'r':
830 do_remove = 1;
831 break;
832 case 5:
833 remove_dependencies = 1;
834 break;
835 case 'R':
Lucas De Marchi81229852011-12-16 02:58:48 -0200836 lookup_only = 1;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200837 break;
838 case 3:
839 first_time = 1;
840 break;
841 case 'i':
842 ignore_commands = 1;
843 break;
844 case 'b':
845 use_blacklist = 1;
846 break;
847 case 'f':
848 force = 1;
849 break;
850 case 2:
851 strip_modversion = 1;
852 break;
853 case 1:
854 strip_vermagic = 1;
855 break;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200856 case 'D':
857 ignore_loaded = 1;
858 dry_run = 1;
Gustavo Sverzut Barbieri525fa072012-01-08 13:58:28 -0200859 do_show = 1;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200860 break;
861 case 'c':
862 do_show_config = 1;
863 break;
864 case 4:
865 do_show_modversions = 1;
866 break;
867 case 'n':
868 dry_run = 1;
869 break;
Gustavo Sverzut Barbiericb8d4d32011-12-11 20:37:01 -0200870 case 'C': {
871 size_t bytes = sizeof(char *) * (n_config_paths + 2);
872 void *tmp = realloc(config_paths, bytes);
873 if (!tmp) {
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200874 ERR("out-of-memory\n");
875 err = -1;
876 goto done;
Gustavo Sverzut Barbiericb8d4d32011-12-11 20:37:01 -0200877 }
878 config_paths = tmp;
879 config_paths[n_config_paths] = optarg;
880 n_config_paths++;
881 config_paths[n_config_paths] = NULL;
882
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200883 env_modprobe_options_append("-C");
884 env_modprobe_options_append(optarg);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200885 break;
Gustavo Sverzut Barbiericb8d4d32011-12-11 20:37:01 -0200886 }
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200887 case 'd':
888 root = optarg;
889 break;
890 case 'S':
891 kversion = optarg;
892 break;
893 case 's':
894 env_modprobe_options_append("-s");
895 use_syslog = 1;
896 break;
897 case 'q':
898 env_modprobe_options_append("-q");
Lucas De Marchiae7ebe82012-03-15 01:11:10 -0300899 verbose = LOG_EMERG;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200900 break;
901 case 'v':
902 env_modprobe_options_append("-v");
903 verbose++;
904 break;
905 case 'V':
906 puts(PACKAGE " version " VERSION);
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200907 err = 0;
Lucas De Marchi4434d8b2012-10-31 21:29:54 -0200908 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200909 case 'h':
Lucas De Marchi4a2e20d2012-11-06 16:54:17 -0200910 help();
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200911 err = 0;
Lucas De Marchi4434d8b2012-10-31 21:29:54 -0200912 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200913 case '?':
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200914 err = -1;
915 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200916 default:
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200917 ERR("unexpected getopt_long() value '%c'.\n", c);
918 err = -1;
919 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200920 }
921 }
922
923 args = argv + optind;
924 nargs = argc - optind;
925
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200926 if (use_syslog) {
927 openlog("modprobe", LOG_CONS, LOG_DAEMON);
928 use_syslog++;
929 }
930
Dave Reisnerb09668c2011-12-31 16:51:40 -0500931 if (!do_show_config) {
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200932 if (nargs == 0) {
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200933 ERR("missing parameters. See -h.\n");
934 err = -1;
935 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200936 }
937 }
938
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200939 if (root != NULL || kversion != NULL) {
940 struct utsname u;
941 if (root == NULL)
942 root = "";
943 if (kversion == NULL) {
944 if (uname(&u) < 0) {
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200945 ERR("uname() failed: %m\n");
946 err = -1;
947 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200948 }
949 kversion = u.release;
950 }
Lucas De Marchi8f192212012-01-11 15:38:50 -0200951 snprintf(dirname_buf, sizeof(dirname_buf),
Dave Reisnerc5b37db2012-09-27 11:00:42 -0400952 "%s/lib/modules/%s", root,
Lucas De Marchi8f192212012-01-11 15:38:50 -0200953 kversion);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200954 dirname = dirname_buf;
955 }
956
Gustavo Sverzut Barbiericb8d4d32011-12-11 20:37:01 -0200957 ctx = kmod_new(dirname, config_paths);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200958 if (!ctx) {
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200959 ERR("kmod_new() failed!\n");
960 err = -1;
961 goto done;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200962 }
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200963
964 kmod_set_log_priority(ctx, verbose);
Lucas De Marchi86cc1f22012-11-01 12:24:58 -0200965 kmod_set_log_fn(ctx, log_modprobe, NULL);
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200966
967 kmod_load_resources(ctx);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200968
Dave Reisnerb09668c2011-12-31 16:51:40 -0500969 if (do_show_config)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200970 err = show_config(ctx);
971 else if (do_show_modversions)
972 err = show_modversions(ctx, args[0]);
973 else if (do_remove)
Lucas De Marchic1b84542012-03-15 00:27:18 -0300974 err = rmmod_all(ctx, args, nargs);
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200975 else if (use_all)
976 err = insmod_all(ctx, args, nargs);
977 else {
978 char *opts;
979 err = options_from_array(args, nargs, &opts);
980 if (err == 0) {
981 err = insmod(ctx, args[0], opts);
982 free(opts);
983 }
984 }
985
986 kmod_unref(ctx);
987
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200988done:
989 if (use_syslog > 1)
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200990 closelog();
991
992 if (argv != orig_argv)
993 free(argv);
Lucas De Marchi8f192212012-01-11 15:38:50 -0200994
Gustavo Sverzut Barbiericb8d4d32011-12-11 20:37:01 -0200995 free(config_paths);
Lucas De Marchid9a2e152012-11-01 13:02:10 -0200996
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200997 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
Gustavo Sverzut Barbieric3d0a5f2011-12-11 19:36:18 -0200998}
Lucas De Marchifa29c0e2011-12-22 03:54:46 -0200999
Lucas De Marchifa29c0e2011-12-22 03:54:46 -02001000const struct kmod_cmd kmod_cmd_compat_modprobe = {
1001 .name = "modprobe",
1002 .cmd = do_modprobe,
1003 .help = "compat modprobe command",
1004};