]> git.ipfire.org Git - thirdparty/kmod.git/blame - tools/kmod-modprobe.c
README: add link to packages place
[thirdparty/kmod.git] / tools / kmod-modprobe.c
CommitLineData
c3d0a5f2 1/*
8b013767 2 * kmod-modprobe - manage linux kernel modules using libkmod.
c3d0a5f2 3 *
a66a6a99 4 * Copyright (C) 2011-2012 ProFUSION embedded systems
c3d0a5f2 5 *
cb451f35
LDM
6 * 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.
c3d0a5f2
GSB
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cb451f35
LDM
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
c3d0a5f2 15 *
cb451f35
LDM
16 * 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/>.
c3d0a5f2 18 */
cb451f35 19
c3d0a5f2
GSB
20#include <stdio.h>
21#include <stdlib.h>
0cf2832a 22#include <stdbool.h>
c3d0a5f2
GSB
23#include <getopt.h>
24#include <errno.h>
25#include <string.h>
26#include <sys/types.h>
27#include <sys/stat.h>
28#include <sys/utsname.h>
eff917c0 29#include <sys/wait.h>
c3d0a5f2
GSB
30#include <unistd.h>
31#include <syslog.h>
32#include <limits.h>
33
34#include "libkmod.h"
8b013767 35#include "libkmod-array.h"
bc43496a 36#include "macro.h"
c3d0a5f2
GSB
37
38static int log_priority = LOG_CRIT;
39static int use_syslog = 0;
40
41#define DEFAULT_VERBOSE LOG_WARNING
42static int verbose = DEFAULT_VERBOSE;
525fa07b 43static int do_show = 0;
c3d0a5f2
GSB
44static int dry_run = 0;
45static int ignore_loaded = 0;
8122985d 46static int lookup_only = 0;
c3d0a5f2
GSB
47static int first_time = 0;
48static int ignore_commands = 0;
49static int use_blacklist = 0;
50static int force = 0;
51static int strip_modversion = 0;
52static int strip_vermagic = 0;
53static int remove_dependencies = 0;
d8a6c0cc 54static int quiet_inuse = 0;
c3d0a5f2 55
b09668cf 56static const char cmdopts_s[] = "arRibft:DcnC:d:S:sqvVh";
c3d0a5f2
GSB
57static const struct option cmdopts[] = {
58 {"all", no_argument, 0, 'a'},
59 {"remove", no_argument, 0, 'r'},
60 {"remove-dependencies", no_argument, 0, 5},
61 {"resolve-alias", no_argument, 0, 'R'},
62 {"first-time", no_argument, 0, 3},
63 {"ignore-install", no_argument, 0, 'i'},
64 {"ignore-remove", no_argument, 0, 'i'},
65 {"use-blacklist", no_argument, 0, 'b'},
66 {"force", no_argument, 0, 'f'},
67 {"force-modversion", no_argument, 0, 2},
68 {"force-vermagic", no_argument, 0, 1},
69
70 {"type", required_argument, 0, 't'},
c3d0a5f2
GSB
71 {"show-depends", no_argument, 0, 'D'},
72 {"showconfig", no_argument, 0, 'c'},
73 {"show-config", no_argument, 0, 'c'},
74 {"show-modversions", no_argument, 0, 4},
75 {"dump-modversions", no_argument, 0, 4},
76
77 {"dry-run", no_argument, 0, 'n'},
78 {"show", no_argument, 0, 'n'},
79
80 {"config", required_argument, 0, 'C'},
81 {"dirname", required_argument, 0, 'd'},
82 {"set-version", required_argument, 0, 'S'},
83
84 {"syslog", no_argument, 0, 's'},
85 {"quiet", no_argument, 0, 'q'},
86 {"verbose", no_argument, 0, 'v'},
87 {"version", no_argument, 0, 'V'},
88 {"help", no_argument, 0, 'h'},
89 {NULL, 0, 0, 0}
90};
91
92static void help(const char *progname)
93{
94 fprintf(stderr,
95 "Usage:\n"
96 "\t%s [options] [-i] [-b] modulename\n"
97 "\t%s [options] -a [-i] [-b] modulename [modulename...]\n"
98 "\t%s [options] -r [-i] modulename\n"
99 "\t%s [options] -r -a [-i] modulename [modulename...]\n"
100 "\t%s [options] -l [-t dirname] [wildcard]\n"
101 "\t%s [options] -c\n"
102 "\t%s [options] --dump-modversions filename\n"
103 "Management Options:\n"
ab70dce1
GSB
104 "\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"
c3d0a5f2
GSB
119 "\n"
120 "Query Options:\n"
ab70dce1 121 "\t-t, --type=DIR Limit type used by --list\n"
ab70dce1
GSB
122 "\t-D, --show-depends Only print module dependencies and exit\n"
123 "\t-c, --showconfig Print out known configuration and exit\n"
124 "\t-c, --show-config Same as --showconfig\n"
125 "\t --show-modversions Dump module symbol version and exit\n"
126 "\t --dump-modversions Same as --show-modversions\n"
c3d0a5f2
GSB
127 "\n"
128 "General Options:\n"
ab70dce1
GSB
129 "\t-n, --dry-run Do not execute operations, just print out\n"
130 "\t-n, --show Same as --dry-run\n"
c3d0a5f2 131
2c96693e 132 "\t-C, --config=FILE Use FILE instead of default search paths\n"
a308abec 133 "\t-d, --dirname=DIR Use DIR as filesystem root for " ROOTPREFIX "/lib/modules\n"
ab70dce1 134 "\t-S, --set-version=VERSION Use VERSION instead of `uname -r`\n"
c3d0a5f2
GSB
135
136 "\t-s, --syslog print to syslog, not stderr\n"
137 "\t-q, --quiet disable messages\n"
138 "\t-v, --verbose enables more messages\n"
139 "\t-V, --version show version\n"
140 "\t-h, --help show this help\n",
141 progname, progname, progname, progname, progname, progname,
142 progname);
143}
144
145static inline void _show(const char *fmt, ...)
146{
147 va_list args;
148
525fa07b 149 if (!do_show && verbose <= DEFAULT_VERBOSE)
c3d0a5f2
GSB
150 return;
151
152 va_start(args, fmt);
153 vfprintf(stdout, fmt, args);
154 fflush(stdout);
155 va_end(args);
156}
157
158static inline void _log(int prio, const char *fmt, ...)
159{
160 const char *prioname;
161 char buf[32], *msg;
162 va_list args;
163
164 if (prio > verbose)
165 return;
166
167 va_start(args, fmt);
168 if (vasprintf(&msg, fmt, args) < 0)
169 msg = NULL;
170 va_end(args);
171 if (msg == NULL)
172 return;
173
174 switch (prio) {
175 case LOG_CRIT:
176 prioname = "FATAL";
177 break;
178 case LOG_ERR:
179 prioname = "ERROR";
180 break;
181 case LOG_WARNING:
182 prioname = "WARNING";
183 break;
184 case LOG_NOTICE:
185 prioname = "NOTICE";
186 break;
187 case LOG_INFO:
188 prioname = "INFO";
189 break;
190 case LOG_DEBUG:
191 prioname = "DEBUG";
192 break;
193 default:
194 snprintf(buf, sizeof(buf), "LOG-%03d", prio);
195 prioname = buf;
196 }
197
198 if (use_syslog)
199 syslog(LOG_NOTICE, "%s: %s", prioname, msg);
200 else
201 fprintf(stderr, "%s: %s", prioname, msg);
202 free(msg);
203
204 if (prio <= LOG_CRIT)
205 exit(EXIT_FAILURE);
206}
207#define ERR(...) _log(LOG_ERR, __VA_ARGS__)
208#define WRN(...) _log(LOG_WARNING, __VA_ARGS__)
209#define INF(...) _log(LOG_INFO, __VA_ARGS__)
210#define DBG(...) _log(LOG_DEBUG, __VA_ARGS__)
211#define LOG(...) _log(log_priority, __VA_ARGS__)
212#define SHOW(...) _show(__VA_ARGS__)
213
c3d0a5f2
GSB
214static int show_config(struct kmod_ctx *ctx)
215{
bc43496a
LDM
216 struct config_iterators {
217 const char *name;
218 struct kmod_config_iter *(*get_iter)(const struct kmod_ctx *ctx);
219 } ci[] = {
220 { "blacklist", kmod_config_get_blacklists },
221 { "install", kmod_config_get_install_commands },
222 { "remove", kmod_config_get_remove_commands },
223 { "alias", kmod_config_get_aliases },
224 { "option", kmod_config_get_options },
225 { "softdep", kmod_config_get_softdeps },
226 };
227 size_t i;
228
229 for (i = 0; i < ARRAY_SIZE(ci); i++) {
230 struct kmod_config_iter *iter = ci[i].get_iter(ctx);
231
232 if (iter == NULL)
233 continue;
234
235 while (kmod_config_iter_next(iter)) {
236 const char *val;
237
238 printf("%s %s", ci[i].name,
239 kmod_config_iter_get_key(iter));
240 val = kmod_config_iter_get_value(iter);
241 if (val != NULL) {
242 putchar(' ');
243 puts(val);
244 } else
245 putchar('\n');
246 }
247
248 kmod_config_iter_free_iter(iter);
249 }
250
09e9ae58
LDM
251 fflush(stdout);
252
49a16375
LDM
253 kmod_dump_index(ctx, KMOD_INDEX_MODULES_ALIAS, STDOUT_FILENO);
254 kmod_dump_index(ctx, KMOD_INDEX_MODULES_SYMBOL, STDOUT_FILENO);
255
bc43496a 256 return 0;
c3d0a5f2
GSB
257}
258
259static int show_modversions(struct kmod_ctx *ctx, const char *filename)
260{
0e3e2f43
GSB
261 struct kmod_list *l, *list = NULL;
262 struct kmod_module *mod;
263 int err = kmod_module_new_from_path(ctx, filename, &mod);
264 if (err < 0) {
265 LOG("Module %s not found.\n", filename);
266 return err;
267 }
268
269 err = kmod_module_get_versions(mod, &list);
270 if (err < 0) {
63698377 271 LOG("could not get modversions of %s: %s\n",
0e3e2f43
GSB
272 filename, strerror(-err));
273 kmod_module_unref(mod);
274 return err;
275 }
276
277 kmod_list_foreach(l, list) {
278 const char *symbol = kmod_module_version_get_symbol(l);
279 uint64_t crc = kmod_module_version_get_crc(l);
280 printf("0x%08"PRIx64"\t%s\n", crc, symbol);
281 }
282 kmod_module_versions_free_list(list);
283 kmod_module_unref(mod);
284 return 0;
c3d0a5f2
GSB
285}
286
8f192210
LDM
287static int command_do(struct kmod_module *module, const char *type,
288 const char *command, const char *cmdline_opts)
c3d0a5f2
GSB
289{
290 const char *modname = kmod_module_get_name(module);
291 char *p, *cmd = NULL;
292 size_t cmdlen, cmdline_opts_len, varlen;
293 int ret = 0;
294
295 if (cmdline_opts == NULL)
296 cmdline_opts = "";
297 cmdline_opts_len = strlen(cmdline_opts);
298
299 cmd = strdup(command);
300 if (cmd == NULL)
301 return -ENOMEM;
302 cmdlen = strlen(cmd);
303 varlen = sizeof("$CMDLINE_OPTS") - 1;
304 while ((p = strstr(cmd, "$CMDLINE_OPTS")) != NULL) {
305 size_t prefixlen = p - cmd;
306 size_t suffixlen = cmdlen - prefixlen - varlen;
307 size_t slen = cmdlen - varlen + cmdline_opts_len;
308 char *suffix = p + varlen;
309 char *s = malloc(slen + 1);
310 if (s == NULL) {
311 free(cmd);
312 return -ENOMEM;
313 }
314 memcpy(s, cmd, p - cmd);
315 memcpy(s + prefixlen, cmdline_opts, cmdline_opts_len);
316 memcpy(s + prefixlen + cmdline_opts_len, suffix, suffixlen);
317 s[slen] = '\0';
318
319 free(cmd);
320 cmd = s;
321 cmdlen = slen;
322 }
323
324 SHOW("%s %s\n", type, cmd);
325 if (dry_run)
326 goto end;
327
328 setenv("MODPROBE_MODULE", modname, 1);
329 ret = system(cmd);
330 unsetenv("MODPROBE_MODULE");
331 if (ret == -1 || WEXITSTATUS(ret)) {
332 LOG("Error running %s command for %s\n", type, modname);
333 if (ret != -1)
334 ret = -WEXITSTATUS(ret);
335 }
336
337end:
338 free(cmd);
339 return ret;
340}
341
a872bba2 342static int rmmod_do_remove_module(struct kmod_module *mod)
c3d0a5f2 343{
a872bba2
LDM
344 const char *modname = kmod_module_get_name(mod);
345 int flags = 0, err;
e793f1ea 346
a872bba2 347 SHOW("rmmod %s\n", kmod_module_get_name(mod));
c3d0a5f2 348
a872bba2
LDM
349 if (dry_run)
350 return 0;
c3d0a5f2 351
a872bba2
LDM
352 if (force)
353 flags |= KMOD_REMOVE_FORCE;
c3d0a5f2 354
a872bba2
LDM
355 err = kmod_module_remove_module(mod, flags);
356 if (err == -EEXIST) {
357 if (!first_time)
358 err = 0;
e793f1ea 359 else
a872bba2 360 LOG("Module %s is not in kernel.\n", modname);
c3d0a5f2 361 }
e793f1ea
GSB
362
363 return err;
364}
365
a872bba2 366static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies);
e793f1ea 367
a872bba2 368static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors)
e793f1ea 369{
a872bba2
LDM
370 struct kmod_list *l;
371
372 kmod_list_foreach_reverse(l, list) {
373 struct kmod_module *m = kmod_module_get_module(l);
374 int r = rmmod_do_module(m, false);
375 kmod_module_unref(m);
376
377 if (r < 0 && stop_on_errors)
378 return r;
379 }
380
381 return 0;
c3d0a5f2
GSB
382}
383
a872bba2 384static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies)
c3d0a5f2
GSB
385{
386 const char *modname = kmod_module_get_name(mod);
a872bba2
LDM
387 struct kmod_list *pre = NULL, *post = NULL;
388 const char *cmd = NULL;
c3d0a5f2
GSB
389 int err;
390
c3d0a5f2 391 if (!ignore_commands) {
e793f1ea
GSB
392 err = kmod_module_get_softdeps(mod, &pre, &post);
393 if (err < 0) {
394 WRN("could not get softdeps of '%s': %s\n",
8f192210 395 modname, strerror(-err));
c3d0a5f2 396 return err;
e793f1ea
GSB
397 }
398
c3d0a5f2 399 cmd = kmod_module_get_remove_commands(mod);
c3d0a5f2
GSB
400 }
401
a872bba2 402 if (cmd == NULL && !ignore_loaded) {
9bf60d21
LDM
403 int state = kmod_module_get_initstate(mod);
404
e5e2a683
LDM
405 if (state < 0) {
406 LOG ("Module %s not found.\n", modname);
e4e1e64a
LDM
407 err = -ENOENT;
408 goto error;
e5e2a683 409 } else if (state == KMOD_MODULE_BUILTIN) {
9bf60d21 410 LOG("Module %s is builtin.\n", modname);
e4e1e64a
LDM
411 err = -ENOENT;
412 goto error;
9bf60d21
LDM
413 } else if (state != KMOD_MODULE_LIVE) {
414 if (first_time) {
415 LOG("Module %s is not in kernel.\n", modname);
e4e1e64a
LDM
416 err = -ENOENT;
417 goto error;
418 } else {
419 err = 0;
420 goto error;
421 }
9bf60d21
LDM
422 }
423 }
424
a872bba2
LDM
425 rmmod_do_deps_list(post, false);
426
427 if (do_dependencies && remove_dependencies) {
428 struct kmod_list *deps = kmod_module_get_dependencies(mod);
429
430 err = rmmod_do_deps_list(deps, true);
9bf60d21 431 if (err < 0)
a872bba2 432 goto error;
9bf60d21
LDM
433 }
434
c3d0a5f2
GSB
435 if (!ignore_loaded) {
436 int usage = kmod_module_get_refcnt(mod);
d8a6c0cc 437
c3d0a5f2 438 if (usage > 0) {
d8a6c0cc
LDM
439 if (!quiet_inuse)
440 LOG("Module %s is in use.\n", modname);
441
e793f1ea 442 err = -EBUSY;
e793f1ea
GSB
443 goto error;
444 }
445 }
446
a872bba2
LDM
447 if (cmd == NULL)
448 err = rmmod_do_remove_module(mod);
449 else
450 err = command_do(mod, "remove", cmd, NULL);
d8a6c0cc 451
a872bba2
LDM
452 if (err < 0)
453 goto error;
c9a14448 454
a872bba2 455 rmmod_do_deps_list(pre, false);
0e9bd2d1 456
e793f1ea
GSB
457error:
458 kmod_module_unref_list(pre);
459 kmod_module_unref_list(post);
a872bba2 460
c3d0a5f2
GSB
461 return err;
462}
463
569f1609 464static int rmmod(struct kmod_ctx *ctx, const char *alias)
c3d0a5f2
GSB
465{
466 struct kmod_list *l, *list = NULL;
467 int err;
468
469 err = kmod_module_new_from_lookup(ctx, alias, &list);
e5e2a683 470 if (err < 0)
c3d0a5f2 471 return err;
e5e2a683
LDM
472
473 if (list == NULL)
474 LOG("Module %s not found.\n", alias);
c3d0a5f2
GSB
475
476 kmod_list_foreach(l, list) {
477 struct kmod_module *mod = kmod_module_get_module(l);
a872bba2 478 err = rmmod_do_module(mod, true);
c3d0a5f2
GSB
479 kmod_module_unref(mod);
480 if (err < 0)
481 break;
482 }
483
484 kmod_module_unref_list(list);
485 return err;
486}
487
c3d0a5f2
GSB
488static int rmmod_all(struct kmod_ctx *ctx, char **args, int nargs)
489{
490 int i, err = 0;
491
492 for (i = 0; i < nargs; i++) {
493 int r = rmmod(ctx, args[i]);
494 if (r < 0)
495 err = r;
496 }
497
498 return err;
499}
500
8b013767
LDM
501#define INSMOD_RECURSION_STEP 15
502
0cf2832a
LDM
503static int concat_options(const char *conf_opts, const char *extra_opts,
504 char **opts)
c3d0a5f2 505{
0cf2832a
LDM
506 if (conf_opts == NULL && extra_opts == NULL)
507 *opts = NULL;
508 else if (conf_opts == NULL)
509 *opts = strdup(extra_opts);
510 else if (extra_opts == NULL)
511 *opts = strdup(conf_opts);
512 else if (asprintf(opts, "%s %s", conf_opts, extra_opts) < 0)
513 return -ENOMEM;
c3d0a5f2 514
0cf2832a
LDM
515 return 0;
516}
c3d0a5f2 517
0cf2832a
LDM
518static int insmod_do_insert_module(struct kmod_module *mod, const char *opts)
519{
520 int flags = 0, err;
e793f1ea 521
0cf2832a 522 SHOW("insmod %s %s\n", kmod_module_get_path(mod), opts ? opts : "");
e793f1ea 523
0cf2832a
LDM
524 if (dry_run)
525 return 0;
526
527 if (strip_modversion || force)
528 flags |= KMOD_INSERT_FORCE_MODVERSION;
529 if (strip_vermagic || force)
530 flags |= KMOD_INSERT_FORCE_VERMAGIC;
531
532 err = kmod_module_insert_module(mod, flags, opts);
533 switch (err) {
534 case -EEXIST:
535 /*
536 * We checked for EEXIST with an earlier call to
537 * retrieve the initstate, but to avoid a race
538 * condition, we don't make any assumptions and handle
539 * the error again here
540 */
541 if (!first_time)
542 err = 0;
e793f1ea 543 else
0cf2832a
LDM
544 ERR("Module %s already in kernel.\n",
545 kmod_module_get_name(mod));
546 break;
547 case -EPERM:
548 ERR("could not insert '%s': %s\n", kmod_module_get_name(mod),
549 strerror(-err));
550 break;
c3d0a5f2 551 }
e793f1ea
GSB
552
553 return err;
e793f1ea 554
e793f1ea
GSB
555}
556
8b013767
LDM
557static bool insmod_recursion_has_loop(struct kmod_module *mod,
558 struct array *recursion)
559{
560 unsigned int i;
561
562 /*
563 * Don't check every time to not impact normal use cases. If the
564 * recursion hits INSMOD_RECURSION_STEP, then search loop in
565 * @recursion.
566 */
567 if ((recursion->count + 1) % INSMOD_RECURSION_STEP != 0)
568 return false;
569
570 for (i = 0; i < recursion->count; i++) {
571 if (recursion->array[i] != mod)
572 continue;
573
574 ERR("Dependency loop detected while inserting '%s'. Operation aborted.\n",
575 kmod_module_get_name(mod));
576
577 for (; i < recursion->count; i++)
578 ERR("\t%s\n", kmod_module_get_name(recursion->array[i]));
579
580 return true;
581 }
582
583 return false;
584}
585
0cf2832a 586static int insmod_do_module(struct kmod_module *mod, const char *extra_opts,
8b013767 587 bool do_dependencies, struct array *recursion);
0cf2832a
LDM
588
589static int insmod_do_deps_list(struct kmod_list *list,
8b013767 590 bool stop_on_errors, struct array *recursion)
e793f1ea 591{
0cf2832a 592 struct kmod_list *l;
8b013767
LDM
593 struct kmod_module *m;
594 int r;
595
596 if (list == NULL)
597 return 0;
598
599 m = kmod_module_get_module(list);
600 r = insmod_recursion_has_loop(m, recursion);
601 kmod_module_unref(m);
602
603 if (r)
604 return -ELOOP;
0cf2832a
LDM
605
606 kmod_list_foreach(l, list) {
8b013767
LDM
607 m = kmod_module_get_module(l);
608 array_append(recursion, m);
609 r = insmod_do_module(m, NULL, false, recursion);
0cf2832a 610 kmod_module_unref(m);
8b013767
LDM
611 array_pop(recursion);
612
613 if (r == -ELOOP)
614 return r;
0cf2832a
LDM
615
616 if (r < 0 && stop_on_errors)
617 return r;
618 }
619
620 return 0;
c3d0a5f2
GSB
621}
622
0cf2832a 623static int insmod_do_module(struct kmod_module *mod, const char *extra_opts,
8b013767 624 bool do_dependencies, struct array *recursion)
c3d0a5f2
GSB
625{
626 const char *modname = kmod_module_get_name(mod);
627 const char *conf_opts = kmod_module_get_options(mod);
e793f1ea 628 struct kmod_list *pre = NULL, *post = NULL;
0cf2832a 629 const char *cmd = NULL;
c3d0a5f2
GSB
630 char *opts = NULL;
631 int err;
632
c3d0a5f2 633 if (!ignore_commands) {
e793f1ea
GSB
634 err = kmod_module_get_softdeps(mod, &pre, &post);
635 if (err < 0) {
636 WRN("could not get softdeps of '%s': %s\n",
8f192210 637 modname, strerror(-err));
c3d0a5f2 638 return err;
e793f1ea
GSB
639 }
640
c3d0a5f2 641 cmd = kmod_module_get_install_commands(mod);
c3d0a5f2
GSB
642 }
643
0cf2832a 644 if (cmd == NULL && !ignore_loaded) {
9bf60d21
LDM
645 int state = kmod_module_get_initstate(mod);
646
95dd837d 647 if (state == KMOD_MODULE_BUILTIN) {
9bf60d21 648 if (first_time) {
0cf2832a 649 err = -EEXIST;
9bf60d21 650 LOG("Module %s already in kernel (builtin).\n",
8f192210 651 modname);
0cf2832a
LDM
652 } else
653 err = 0;
654
655 goto error;
9bf60d21
LDM
656 } else if (state == KMOD_MODULE_LIVE) {
657 if (first_time) {
0cf2832a 658 err = -EEXIST;
9bf60d21 659 LOG("Module %s already in kernel.\n", modname);
0cf2832a
LDM
660
661 } else
662 err = 0;
663
664 goto error;
9bf60d21
LDM
665 }
666 }
667
0cf2832a
LDM
668 if (cmd == NULL && kmod_module_get_path(mod) == NULL) {
669 err = -ENOENT;
95dd837d 670 LOG("Module %s not found.\n", modname);
0cf2832a 671 goto error;
95dd837d
LDM
672 }
673
8b013767
LDM
674 err = insmod_do_deps_list(pre, false, recursion);
675 if (err == -ELOOP)
676 goto error;
9bf60d21 677
0cf2832a
LDM
678 if (do_dependencies) {
679 struct kmod_list *deps = kmod_module_get_dependencies(mod);
c3d0a5f2 680
8b013767 681 err = insmod_do_deps_list(deps, true, recursion);
0cf2832a 682 if (err < 0)
e793f1ea 683 goto error;
c3d0a5f2
GSB
684 }
685
0cf2832a
LDM
686 if ((err = concat_options(conf_opts, extra_opts, &opts)) < 0)
687 goto error;
c3d0a5f2 688
0cf2832a
LDM
689 if (cmd == NULL)
690 err = insmod_do_insert_module(mod, opts);
691 else
692 err = command_do(mod, "install", cmd, NULL);
c3d0a5f2 693
0cf2832a
LDM
694 if (err < 0)
695 goto error;
e793f1ea 696
8b013767 697 err = insmod_do_deps_list(post, false, recursion);
e793f1ea
GSB
698
699error:
700 kmod_module_unref_list(pre);
701 kmod_module_unref_list(post);
c3d0a5f2 702 free(opts);
0cf2832a 703
c3d0a5f2
GSB
704 return err;
705}
706
92122614
LDM
707static int handle_failed_lookup(struct kmod_ctx *ctx, const char *alias)
708{
709 struct kmod_module *mod;
710 int state, err;
711
712 DBG("lookup failed - trying to check if it's builtin\n");
713
714 err = kmod_module_new_from_name(ctx, alias, &mod);
715 if (err < 0)
716 return err;
717
718 state = kmod_module_get_initstate(mod);
719 kmod_module_unref(mod);
720
721 if (state != KMOD_MODULE_BUILTIN) {
722 LOG("Module %s not found.\n", alias);
723 return -ENOENT;
724 }
725
726 if (first_time) {
727 LOG("Module %s already in kernel (builtin).\n", alias);
728 return -ENOENT;
729 }
730
731 SHOW("builtin %s\n", alias);
732 return 0;
733}
734
569f1609 735static int insmod(struct kmod_ctx *ctx, const char *alias,
8f192210 736 const char *extra_options)
c3d0a5f2
GSB
737{
738 struct kmod_list *l, *list = NULL;
739 int err;
740
741 err = kmod_module_new_from_lookup(ctx, alias, &list);
e5e2a683
LDM
742 if (err < 0)
743 return err;
744
92122614
LDM
745 if (list == NULL)
746 return handle_failed_lookup(ctx, alias);
c3d0a5f2
GSB
747
748 if (use_blacklist) {
749 struct kmod_list *filtered = NULL;
750 err = kmod_module_get_filtered_blacklist(ctx, list, &filtered);
751 DBG("using blacklist: input %p, output=%p\n", list, filtered);
752 kmod_module_unref_list(list);
753 if (err < 0) {
63698377 754 LOG("could not filter alias list!\n");
c3d0a5f2
GSB
755 return err;
756 }
757 list = filtered;
758 }
759
760 kmod_list_foreach(l, list) {
761 struct kmod_module *mod = kmod_module_get_module(l);
8b013767 762
8122985d
LDM
763 if (lookup_only)
764 printf("%s\n", kmod_module_get_name(mod));
8b013767
LDM
765 else {
766 struct array recursion;
767
768 array_init(&recursion, INSMOD_RECURSION_STEP);
769 err = insmod_do_module(mod, extra_options, true,
770 &recursion);
771 array_free_array(&recursion);
772 }
c3d0a5f2
GSB
773 kmod_module_unref(mod);
774 if (err < 0)
775 break;
776 }
777
778 kmod_module_unref_list(list);
779 return err;
780}
781
c3d0a5f2
GSB
782static int insmod_all(struct kmod_ctx *ctx, char **args, int nargs)
783{
784 int i, err = 0;
785
786 for (i = 0; i < nargs; i++) {
787 int r = insmod(ctx, args[i], NULL);
788 if (r < 0)
789 err = r;
790 }
791
792 return err;
793}
794
795static void env_modprobe_options_append(const char *value)
796{
797 const char *old = getenv("MODPROBE_OPTIONS");
798 char *env;
799
800 if (old == NULL) {
801 setenv("MODPROBE_OPTIONS", value, 1);
802 return;
803 }
804
805 if (asprintf(&env, "%s %s", old, value) < 0) {
806 ERR("could not append value to $MODPROBE_OPTIONS\n");
807 return;
808 }
809
810 if (setenv("MODPROBE_OPTIONS", env, 1) < 0)
811 ERR("could not setenv(MODPROBE_OPTIONS, \"%s\")\n", env);
812 free(env);
813}
814
815static int options_from_array(char **args, int nargs, char **output)
816{
817 char *opts = NULL;
818 size_t optslen = 0;
819 int i, err = 0;
820
821 for (i = 1; i < nargs; i++) {
822 size_t len = strlen(args[i]);
823 size_t qlen = 0;
824 const char *value;
825 void *tmp;
826
827 value = strchr(args[i], '=');
828 if (value) {
829 value++;
830 if (*value != '"' && *value != '\'') {
831 if (strchr(value, ' '))
832 qlen = 2;
833 }
834 }
835
836 tmp = realloc(opts, optslen + len + qlen + 2);
837 if (!tmp) {
838 err = -errno;
839 free(opts);
840 opts = NULL;
841 ERR("could not gather module options: out-of-memory\n");
842 break;
843 }
844 opts = tmp;
845 if (optslen > 0) {
846 opts[optslen] = ' ';
847 optslen++;
848 }
849 if (qlen == 0) {
850 memcpy(opts + optslen, args[i], len + 1);
851 optslen += len;
852 } else {
853 size_t keylen = value - args[i];
854 size_t valuelen = len - keylen;
855 memcpy(opts + optslen, args[i], keylen);
856 optslen += keylen;
857 opts[optslen] = '"';
858 optslen++;
859 memcpy(opts + optslen, value, valuelen);
860 optslen += valuelen;
861 opts[optslen] = '"';
862 optslen++;
863 opts[optslen] = '\0';
864 }
865 }
866
867 *output = opts;
868 return err;
869}
870
871static char **prepend_options_from_env(int *p_argc, char **orig_argv)
872{
873 const char *p, *env = getenv("MODPROBE_OPTIONS");
874 char **new_argv, *str_start, *str_end, *str, *s, *quote;
875 int i, argc = *p_argc;
876 size_t envlen, space_count = 0;
877
878 if (env == NULL)
879 return orig_argv;
880
881 for (p = env; *p != '\0'; p++) {
882 if (*p == ' ')
883 space_count++;
884 }
885
886 envlen = p - env;
887 new_argv = malloc(sizeof(char *) * (argc + space_count + 3 + envlen));
888 if (new_argv == NULL)
889 return NULL;
890
891 new_argv[0] = orig_argv[0];
892 str_start = str = (char *) (new_argv + argc + space_count + 3);
893 memcpy(str, env, envlen + 1);
894
895 str_end = str_start + envlen;
896
897 quote = NULL;
898 for (i = 1, s = str; *s != '\0'; s++) {
899 if (quote == NULL) {
900 if (*s == ' ') {
901 new_argv[i] = str;
902 i++;
903 *s = '\0';
904 str = s + 1;
905 } else if (*s == '"' || *s == '\'')
906 quote = s;
907 } else {
908 if (*s == *quote) {
909 if (quote == str) {
910 new_argv[i] = str + 1;
911 i++;
912 *s = '\0';
913 str = s + 1;
914 } else {
915 char *it;
916 for (it = quote; it < s - 1; it++)
917 it[0] = it[1];
918 for (it = s - 1; it < str_end - 2; it++)
919 it[0] = it[2];
920 str_end -= 2;
921 *str_end = '\0';
922 s -= 2;
923 }
924 quote = NULL;
925 }
926 }
927 }
928 if (str < s) {
929 new_argv[i] = str;
930 i++;
931 }
932
933 memcpy(new_argv + i, orig_argv + 1, sizeof(char *) * (argc - 1));
934 new_argv[i + argc] = NULL;
935 *p_argc = i + argc - 1;
936
937 return new_argv;
938}
939
940static void log_syslog(void *data, int priority, const char *file, int line,
8f192210 941 const char *fn, const char *format, va_list args)
c3d0a5f2
GSB
942{
943 char *str, buf[32];
944 const char *prioname;
945
946 switch (priority) {
947 case LOG_CRIT:
948 prioname = "FATAL";
949 break;
950 case LOG_ERR:
951 prioname = "ERROR";
952 break;
953 case LOG_WARNING:
954 prioname = "WARNING";
955 break;
956 case LOG_NOTICE:
957 prioname = "NOTICE";
958 break;
959 case LOG_INFO:
960 prioname = "INFO";
961 break;
962 case LOG_DEBUG:
963 prioname = "DEBUG";
964 break;
965 default:
966 snprintf(buf, sizeof(buf), "LOG-%03d", priority);
967 prioname = buf;
968 }
969
970 if (vasprintf(&str, format, args) < 0)
971 return;
972#ifdef ENABLE_DEBUG
973 syslog(LOG_NOTICE, "%s: %s:%d %s() %s", prioname, file, line, fn, str);
974#else
975 syslog(LOG_NOTICE, "%s: %s", prioname, str);
976#endif
977 free(str);
978 (void)data;
979}
980
fa29c0ee 981static int do_modprobe(int argc, char **orig_argv)
c3d0a5f2
GSB
982{
983 struct kmod_ctx *ctx;
984 char **args = NULL, **argv;
cb8d4d3e
GSB
985 const char **config_paths = NULL;
986 int nargs = 0, n_config_paths = 0;
c3d0a5f2
GSB
987 char dirname_buf[PATH_MAX];
988 const char *dirname = NULL;
989 const char *root = NULL;
c3d0a5f2
GSB
990 const char *kversion = NULL;
991 const char *list_type = NULL;
992 int use_all = 0;
993 int do_remove = 0;
994 int do_show_config = 0;
995 int do_show_modversions = 0;
c3d0a5f2
GSB
996 int err;
997
998 argv = prepend_options_from_env(&argc, orig_argv);
999 if (argv == NULL) {
1000 fputs("Error: could not prepend options from command line\n",
1001 stderr);
1002 return EXIT_FAILURE;
1003 }
1004
1005 for (;;) {
1006 int c, idx = 0;
1007 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
1008 if (c == -1)
1009 break;
1010 switch (c) {
1011 case 'a':
1012 log_priority = LOG_WARNING;
1013 use_all = 1;
1014 break;
1015 case 'r':
1016 do_remove = 1;
1017 break;
1018 case 5:
1019 remove_dependencies = 1;
1020 break;
1021 case 'R':
8122985d 1022 lookup_only = 1;
c3d0a5f2
GSB
1023 break;
1024 case 3:
1025 first_time = 1;
1026 break;
1027 case 'i':
1028 ignore_commands = 1;
1029 break;
1030 case 'b':
1031 use_blacklist = 1;
1032 break;
1033 case 'f':
1034 force = 1;
1035 break;
1036 case 2:
1037 strip_modversion = 1;
1038 break;
1039 case 1:
1040 strip_vermagic = 1;
1041 break;
1042 case 't':
1043 list_type = optarg;
1044 break;
c3d0a5f2
GSB
1045 case 'D':
1046 ignore_loaded = 1;
1047 dry_run = 1;
525fa07b 1048 do_show = 1;
c3d0a5f2
GSB
1049 break;
1050 case 'c':
1051 do_show_config = 1;
1052 break;
1053 case 4:
1054 do_show_modversions = 1;
1055 break;
1056 case 'n':
1057 dry_run = 1;
1058 break;
cb8d4d3e
GSB
1059 case 'C': {
1060 size_t bytes = sizeof(char *) * (n_config_paths + 2);
1061 void *tmp = realloc(config_paths, bytes);
1062 if (!tmp) {
1063 fputs("Error: out-of-memory\n", stderr);
1064 goto cmdline_failed;
1065 }
1066 config_paths = tmp;
1067 config_paths[n_config_paths] = optarg;
1068 n_config_paths++;
1069 config_paths[n_config_paths] = NULL;
1070
c3d0a5f2
GSB
1071 env_modprobe_options_append("-C");
1072 env_modprobe_options_append(optarg);
c3d0a5f2 1073 break;
cb8d4d3e 1074 }
c3d0a5f2
GSB
1075 case 'd':
1076 root = optarg;
1077 break;
1078 case 'S':
1079 kversion = optarg;
1080 break;
1081 case 's':
1082 env_modprobe_options_append("-s");
1083 use_syslog = 1;
1084 break;
1085 case 'q':
1086 env_modprobe_options_append("-q");
1087 verbose--;
1088 break;
1089 case 'v':
1090 env_modprobe_options_append("-v");
1091 verbose++;
1092 break;
1093 case 'V':
1094 puts(PACKAGE " version " VERSION);
1095 if (argv != orig_argv)
1096 free(argv);
5f9f58f9 1097 free(config_paths);
c3d0a5f2
GSB
1098 return EXIT_SUCCESS;
1099 case 'h':
3e8de63d 1100 help(basename(argv[0]));
c3d0a5f2
GSB
1101 if (argv != orig_argv)
1102 free(argv);
5f9f58f9 1103 free(config_paths);
c3d0a5f2
GSB
1104 return EXIT_SUCCESS;
1105 case '?':
1106 goto cmdline_failed;
1107 default:
8f192210
LDM
1108 fprintf(stderr, "Error: unexpected getopt_long() value '%c'.\n",
1109 c);
c3d0a5f2
GSB
1110 goto cmdline_failed;
1111 }
1112 }
1113
1114 args = argv + optind;
1115 nargs = argc - optind;
1116
b09668cf 1117 if (!do_show_config) {
c3d0a5f2
GSB
1118 if (nargs == 0) {
1119 fputs("Error: missing parameters. See -h.\n", stderr);
1120 goto cmdline_failed;
1121 }
1122 }
1123
b09668cf 1124 if (list_type != NULL) {
c3d0a5f2 1125 fputs("Error: -t (--type) only supported with -l (--list).\n",
8f192210 1126 stderr);
c3d0a5f2
GSB
1127 goto cmdline_failed;
1128 }
1129
1130 if (root != NULL || kversion != NULL) {
1131 struct utsname u;
1132 if (root == NULL)
1133 root = "";
1134 if (kversion == NULL) {
1135 if (uname(&u) < 0) {
1136 fprintf(stderr, "Error: uname() failed: %s\n",
1137 strerror(errno));
1138 goto cmdline_failed;
1139 }
1140 kversion = u.release;
1141 }
8f192210
LDM
1142 snprintf(dirname_buf, sizeof(dirname_buf),
1143 "%s" ROOTPREFIX "/lib/modules/%s", root,
1144 kversion);
c3d0a5f2
GSB
1145 dirname = dirname_buf;
1146 }
1147
cb8d4d3e 1148 ctx = kmod_new(dirname, config_paths);
c3d0a5f2
GSB
1149 if (!ctx) {
1150 fputs("Error: kmod_new() failed!\n", stderr);
1151 goto cmdline_failed;
1152 }
1153 kmod_load_resources(ctx);
1154
1155 kmod_set_log_priority(ctx, verbose);
1156 if (use_syslog) {
1157 openlog("modprobe", LOG_CONS, LOG_DAEMON);
1158 kmod_set_log_fn(ctx, log_syslog, NULL);
1159 }
1160
b09668cf 1161 if (do_show_config)
c3d0a5f2
GSB
1162 err = show_config(ctx);
1163 else if (do_show_modversions)
1164 err = show_modversions(ctx, args[0]);
1165 else if (do_remove)
1166 err = rmmod_all(ctx, args, use_all ? nargs : 1);
1167 else if (use_all)
1168 err = insmod_all(ctx, args, nargs);
1169 else {
1170 char *opts;
1171 err = options_from_array(args, nargs, &opts);
1172 if (err == 0) {
1173 err = insmod(ctx, args[0], opts);
1174 free(opts);
1175 }
1176 }
1177
1178 kmod_unref(ctx);
1179
1180 if (use_syslog)
1181 closelog();
1182
1183 if (argv != orig_argv)
1184 free(argv);
8f192210 1185
cb8d4d3e 1186 free(config_paths);
c3d0a5f2
GSB
1187 return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1188
1189cmdline_failed:
1190 if (argv != orig_argv)
1191 free(argv);
cb8d4d3e 1192 free(config_paths);
c3d0a5f2
GSB
1193 return EXIT_FAILURE;
1194}
fa29c0ee
LDM
1195
1196#ifndef KMOD_BUNDLE_TOOL
1197int main(int argc, char *argv[])
1198{
1199 return do_modprobe(argc, argv);
1200}
1201
1202#else
1203#include "kmod.h"
1204
1205const struct kmod_cmd kmod_cmd_compat_modprobe = {
1206 .name = "modprobe",
1207 .cmd = do_modprobe,
1208 .help = "compat modprobe command",
1209};
1210
1211#endif