modprobe.c revision 4434d8ba363900e47190f39297ee690485794c1c
1/*
2 * kmod-modprobe - manage linux kernel modules using libkmod.
3 *
4 * Copyright (C) 2011-2012  ProFUSION embedded systems
5 *
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.
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
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
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/>.
18 */
19
20#include <assert.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdbool.h>
24#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>
30#include <sys/wait.h>
31#include <unistd.h>
32#include <syslog.h>
33#include <limits.h>
34
35#include "libkmod.h"
36#include "libkmod-array.h"
37#include "macro.h"
38
39static int log_priority = LOG_CRIT;
40static int use_syslog = 0;
41
42#define DEFAULT_VERBOSE LOG_WARNING
43static int verbose = DEFAULT_VERBOSE;
44static int do_show = 0;
45static int dry_run = 0;
46static int ignore_loaded = 0;
47static int lookup_only = 0;
48static int first_time = 0;
49static int ignore_commands = 0;
50static int use_blacklist = 0;
51static int force = 0;
52static int strip_modversion = 0;
53static int strip_vermagic = 0;
54static int remove_dependencies = 0;
55static int quiet_inuse = 0;
56
57static const char cmdopts_s[] = "arRibfDcnC:d:S:sqvVh";
58static const struct option cmdopts[] = {
59	{"all", no_argument, 0, 'a'},
60	{"remove", no_argument, 0, 'r'},
61	{"remove-dependencies", no_argument, 0, 5},
62	{"resolve-alias", no_argument, 0, 'R'},
63	{"first-time", no_argument, 0, 3},
64	{"ignore-install", no_argument, 0, 'i'},
65	{"ignore-remove", no_argument, 0, 'i'},
66	{"use-blacklist", no_argument, 0, 'b'},
67	{"force", no_argument, 0, 'f'},
68	{"force-modversion", no_argument, 0, 2},
69	{"force-vermagic", no_argument, 0, 1},
70
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] -c\n"
101		"\t%s [options] --dump-modversions filename\n"
102		"Management Options:\n"
103		"\t-a, --all                   Consider every non-argument to\n"
104		"\t                            be a module name to be inserted\n"
105		"\t                            or removed (-r)\n"
106		"\t-r, --remove                Remove modules instead of inserting\n"
107		"\t    --remove-dependencies   Also remove modules depending on it\n"
108		"\t-R, --resolve-alias         Only lookup and print alias and exit\n"
109		"\t    --first-time            Fail if module already inserted or removed\n"
110		"\t-i, --ignore-install        Ignore install commands\n"
111		"\t-i, --ignore-remove         Ignore remove commands\n"
112		"\t-b, --use-blacklist         Apply blacklist to resolved alias.\n"
113		"\t-f, --force                 Force module insertion or removal.\n"
114		"\t                            implies --force-modversions and\n"
115		"\t                            --force-vermagic\n"
116		"\t    --force-modversion      Ignore module's version\n"
117		"\t    --force-vermagic        Ignore module's version magic\n"
118		"\n"
119		"Query Options:\n"
120		"\t-D, --show-depends          Only print module dependencies and exit\n"
121		"\t-c, --showconfig            Print out known configuration and exit\n"
122		"\t-c, --show-config           Same as --showconfig\n"
123		"\t    --show-modversions      Dump module symbol version and exit\n"
124		"\t    --dump-modversions      Same as --show-modversions\n"
125		"\n"
126		"General Options:\n"
127		"\t-n, --dry-run               Do not execute operations, just print out\n"
128		"\t-n, --show                  Same as --dry-run\n"
129
130		"\t-C, --config=FILE           Use FILE instead of default search paths\n"
131		"\t-d, --dirname=DIR           Use DIR as filesystem root for /lib/modules\n"
132		"\t-S, --set-version=VERSION   Use VERSION instead of `uname -r`\n"
133
134		"\t-s, --syslog                print to syslog, not stderr\n"
135		"\t-q, --quiet                 disable messages\n"
136		"\t-v, --verbose               enables more messages\n"
137		"\t-V, --version               show version\n"
138		"\t-h, --help                  show this help\n",
139		progname, progname, progname, progname, progname, progname);
140}
141
142static inline void _show(const char *fmt, ...)
143{
144	va_list args;
145
146	if (!do_show && verbose <= DEFAULT_VERBOSE)
147		return;
148
149	va_start(args, fmt);
150	vfprintf(stdout, fmt, args);
151	fflush(stdout);
152	va_end(args);
153}
154
155static inline void _log(int prio, const char *fmt, ...)
156{
157	const char *prioname;
158	char buf[32], *msg;
159	va_list args;
160
161	if (prio > verbose)
162		return;
163
164	va_start(args, fmt);
165	if (vasprintf(&msg, fmt, args) < 0)
166		msg = NULL;
167	va_end(args);
168	if (msg == NULL)
169		return;
170
171	switch (prio) {
172	case LOG_CRIT:
173		prioname = "FATAL";
174		break;
175	case LOG_ERR:
176		prioname = "ERROR";
177		break;
178	case LOG_WARNING:
179		prioname = "WARNING";
180		break;
181	case LOG_NOTICE:
182		prioname = "NOTICE";
183		break;
184	case LOG_INFO:
185		prioname = "INFO";
186		break;
187	case LOG_DEBUG:
188		prioname = "DEBUG";
189		break;
190	default:
191		snprintf(buf, sizeof(buf), "LOG-%03d", prio);
192		prioname = buf;
193	}
194
195	if (use_syslog)
196		syslog(LOG_NOTICE, "%s: %s", prioname, msg);
197	else
198		fprintf(stderr, "%s: %s", prioname, msg);
199	free(msg);
200
201	if (prio <= LOG_CRIT)
202		exit(EXIT_FAILURE);
203}
204#define ERR(...) _log(LOG_ERR, __VA_ARGS__)
205#define WRN(...) _log(LOG_WARNING, __VA_ARGS__)
206#define INF(...) _log(LOG_INFO, __VA_ARGS__)
207#define DBG(...) _log(LOG_DEBUG, __VA_ARGS__)
208#define LOG(...) _log(log_priority, __VA_ARGS__)
209#define SHOW(...) _show(__VA_ARGS__)
210
211static int show_config(struct kmod_ctx *ctx)
212{
213	struct config_iterators {
214		const char *name;
215		struct kmod_config_iter *(*get_iter)(const struct kmod_ctx *ctx);
216	} ci[] = {
217		{ "blacklist", kmod_config_get_blacklists },
218		{ "install", kmod_config_get_install_commands },
219		{ "remove", kmod_config_get_remove_commands },
220		{ "alias", kmod_config_get_aliases },
221		{ "options", kmod_config_get_options },
222		{ "softdep", kmod_config_get_softdeps },
223	};
224	size_t i;
225
226	for (i = 0;  i < ARRAY_SIZE(ci); i++) {
227		struct kmod_config_iter *iter = ci[i].get_iter(ctx);
228
229		if (iter == NULL)
230			continue;
231
232		while (kmod_config_iter_next(iter)) {
233			const char *val;
234
235			printf("%s %s", ci[i].name,
236					kmod_config_iter_get_key(iter));
237			val = kmod_config_iter_get_value(iter);
238			if (val != NULL) {
239				putchar(' ');
240				puts(val);
241			} else
242				putchar('\n');
243		}
244
245		kmod_config_iter_free_iter(iter);
246	}
247
248	puts("\n# End of configuration files. Dumping indexes now:\n");
249	fflush(stdout);
250
251	kmod_dump_index(ctx, KMOD_INDEX_MODULES_ALIAS, STDOUT_FILENO);
252	kmod_dump_index(ctx, KMOD_INDEX_MODULES_SYMBOL, STDOUT_FILENO);
253
254	return 0;
255}
256
257static int show_modversions(struct kmod_ctx *ctx, const char *filename)
258{
259	struct kmod_list *l, *list = NULL;
260	struct kmod_module *mod;
261	int err = kmod_module_new_from_path(ctx, filename, &mod);
262	if (err < 0) {
263		LOG("Module %s not found.\n", filename);
264		return err;
265	}
266
267	err = kmod_module_get_versions(mod, &list);
268	if (err < 0) {
269		LOG("could not get modversions of %s: %s\n",
270			filename, strerror(-err));
271		kmod_module_unref(mod);
272		return err;
273	}
274
275	kmod_list_foreach(l, list) {
276		const char *symbol = kmod_module_version_get_symbol(l);
277		uint64_t crc = kmod_module_version_get_crc(l);
278		printf("0x%08"PRIx64"\t%s\n", crc, symbol);
279	}
280	kmod_module_versions_free_list(list);
281	kmod_module_unref(mod);
282	return 0;
283}
284
285static int command_do(struct kmod_module *module, const char *type,
286				const char *command, const char *cmdline_opts)
287{
288	const char *modname = kmod_module_get_name(module);
289	char *p, *cmd = NULL;
290	size_t cmdlen, cmdline_opts_len, varlen;
291	int ret = 0;
292
293	if (cmdline_opts == NULL)
294		cmdline_opts = "";
295	cmdline_opts_len = strlen(cmdline_opts);
296
297	cmd = strdup(command);
298	if (cmd == NULL)
299		return -ENOMEM;
300	cmdlen = strlen(cmd);
301	varlen = sizeof("$CMDLINE_OPTS") - 1;
302	while ((p = strstr(cmd, "$CMDLINE_OPTS")) != NULL) {
303		size_t prefixlen = p - cmd;
304		size_t suffixlen = cmdlen - prefixlen - varlen;
305		size_t slen = cmdlen - varlen + cmdline_opts_len;
306		char *suffix = p + varlen;
307		char *s = malloc(slen + 1);
308		if (s == NULL) {
309			free(cmd);
310			return -ENOMEM;
311		}
312		memcpy(s, cmd, p - cmd);
313		memcpy(s + prefixlen, cmdline_opts, cmdline_opts_len);
314		memcpy(s + prefixlen + cmdline_opts_len, suffix, suffixlen);
315		s[slen] = '\0';
316
317		free(cmd);
318		cmd = s;
319		cmdlen = slen;
320	}
321
322	SHOW("%s %s\n", type, cmd);
323	if (dry_run)
324		goto end;
325
326	setenv("MODPROBE_MODULE", modname, 1);
327	ret = system(cmd);
328	unsetenv("MODPROBE_MODULE");
329	if (ret == -1 || WEXITSTATUS(ret)) {
330		LOG("Error running %s command for %s\n", type, modname);
331		if (ret != -1)
332			ret = -WEXITSTATUS(ret);
333	}
334
335end:
336	free(cmd);
337	return ret;
338}
339
340static int rmmod_do_remove_module(struct kmod_module *mod)
341{
342	const char *modname = kmod_module_get_name(mod);
343	struct kmod_list *deps, *itr;
344	int flags = 0, err;
345
346	SHOW("rmmod %s\n", kmod_module_get_name(mod));
347
348	if (dry_run)
349		return 0;
350
351	if (force)
352		flags |= KMOD_REMOVE_FORCE;
353
354	err = kmod_module_remove_module(mod, flags);
355	if (err == -EEXIST) {
356		if (!first_time)
357			err = 0;
358		else
359			LOG("Module %s is not in kernel.\n", modname);
360	}
361
362	deps = kmod_module_get_dependencies(mod);
363	if (deps != NULL) {
364		kmod_list_foreach(itr, deps) {
365			struct kmod_module *dep = kmod_module_get_module(itr);
366			if (kmod_module_get_refcnt(dep) == 0)
367				rmmod_do_remove_module(dep);
368			kmod_module_unref(dep);
369		}
370		kmod_module_unref_list(deps);
371	}
372
373	return err;
374}
375
376static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies);
377
378static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors)
379{
380	struct kmod_list *l;
381
382	kmod_list_foreach_reverse(l, list) {
383		struct kmod_module *m = kmod_module_get_module(l);
384		int r = rmmod_do_module(m, false);
385		kmod_module_unref(m);
386
387		if (r < 0 && stop_on_errors)
388			return r;
389	}
390
391	return 0;
392}
393
394static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies)
395{
396	const char *modname = kmod_module_get_name(mod);
397	struct kmod_list *pre = NULL, *post = NULL;
398	const char *cmd = NULL;
399	int err;
400
401	if (!ignore_commands) {
402		err = kmod_module_get_softdeps(mod, &pre, &post);
403		if (err < 0) {
404			WRN("could not get softdeps of '%s': %s\n",
405						modname, strerror(-err));
406			return err;
407		}
408
409		cmd = kmod_module_get_remove_commands(mod);
410	}
411
412	if (cmd == NULL && !ignore_loaded) {
413		int state = kmod_module_get_initstate(mod);
414
415		if (state < 0) {
416			if (first_time) {
417				LOG("Module %s is not in kernel.\n", modname);
418				err = -ENOENT;
419			} else {
420				err = 0;
421			}
422			goto error;
423		} else if (state == KMOD_MODULE_BUILTIN) {
424			LOG("Module %s is builtin.\n", modname);
425			err = -ENOENT;
426			goto error;
427		}
428	}
429
430	rmmod_do_deps_list(post, false);
431
432	if (do_dependencies && remove_dependencies) {
433		struct kmod_list *deps = kmod_module_get_dependencies(mod);
434
435		err = rmmod_do_deps_list(deps, true);
436		if (err < 0)
437			goto error;
438	}
439
440	if (!ignore_loaded) {
441		int usage = kmod_module_get_refcnt(mod);
442
443		if (usage > 0) {
444			if (!quiet_inuse)
445				LOG("Module %s is in use.\n", modname);
446
447			err = -EBUSY;
448			goto error;
449		}
450	}
451
452	if (cmd == NULL)
453		err = rmmod_do_remove_module(mod);
454	else
455		err = command_do(mod, "remove", cmd, NULL);
456
457	if (err < 0)
458		goto error;
459
460	rmmod_do_deps_list(pre, false);
461
462error:
463	kmod_module_unref_list(pre);
464	kmod_module_unref_list(post);
465
466	return err;
467}
468
469static int rmmod(struct kmod_ctx *ctx, const char *alias)
470{
471	struct kmod_list *l, *list = NULL;
472	int err;
473
474	err = kmod_module_new_from_lookup(ctx, alias, &list);
475	if (err < 0)
476		return err;
477
478	if (list == NULL) {
479		LOG("Module %s not found.\n", alias);
480		err = -ENOENT;
481	}
482
483	kmod_list_foreach(l, list) {
484		struct kmod_module *mod = kmod_module_get_module(l);
485		err = rmmod_do_module(mod, true);
486		kmod_module_unref(mod);
487		if (err < 0)
488			break;
489	}
490
491	kmod_module_unref_list(list);
492	return err;
493}
494
495static int rmmod_all(struct kmod_ctx *ctx, char **args, int nargs)
496{
497	int i, err = 0;
498
499	for (i = 0; i < nargs; i++) {
500		int r = rmmod(ctx, args[i]);
501		if (r < 0)
502			err = r;
503	}
504
505	return err;
506}
507
508static int handle_failed_lookup(struct kmod_ctx *ctx, const char *alias)
509{
510	struct kmod_module *mod;
511	int state, err;
512
513	DBG("lookup failed - trying to check if it's builtin\n");
514
515	err = kmod_module_new_from_name(ctx, alias, &mod);
516	if (err < 0)
517		return err;
518
519	state = kmod_module_get_initstate(mod);
520	kmod_module_unref(mod);
521
522	if (state != KMOD_MODULE_BUILTIN) {
523		LOG("Module %s not found.\n", alias);
524		return -ENOENT;
525	}
526
527	if (first_time) {
528		LOG("Module %s already in kernel (builtin).\n", alias);
529		return -ENOENT;
530	}
531
532	SHOW("builtin %s\n", alias);
533	return 0;
534}
535
536static void print_action(struct kmod_module *m, bool install,
537							const char *options)
538{
539	const char *path;
540
541	if (install) {
542		printf("install %s %s\n", kmod_module_get_install_commands(m),
543								options);
544		return;
545	}
546
547	path = kmod_module_get_path(m);
548
549	if (path == NULL) {
550		assert(kmod_module_get_initstate(m) == KMOD_MODULE_BUILTIN);
551		printf("builtin %s\n", kmod_module_get_name(m));
552	} else
553		printf("insmod %s %s\n", kmod_module_get_path(m), options);
554}
555
556static int insmod(struct kmod_ctx *ctx, const char *alias,
557						const char *extra_options)
558{
559	struct kmod_list *l, *list = NULL;
560	int err, flags = 0;
561
562	void (*show)(struct kmod_module *m, bool install,
563						const char *options) = NULL;
564
565	err = kmod_module_new_from_lookup(ctx, alias, &list);
566	if (err < 0)
567		return err;
568
569	if (list == NULL)
570		return handle_failed_lookup(ctx, alias);
571
572	if (strip_modversion || force)
573		flags |= KMOD_PROBE_FORCE_MODVERSION;
574	if (strip_vermagic || force)
575		flags |= KMOD_PROBE_FORCE_VERMAGIC;
576	if (ignore_commands)
577		flags |= KMOD_PROBE_IGNORE_COMMAND;
578	if (ignore_loaded)
579		flags |= KMOD_PROBE_IGNORE_LOADED;
580	if (dry_run)
581		flags |= KMOD_PROBE_DRY_RUN;
582	if (do_show || verbose > DEFAULT_VERBOSE)
583		show = &print_action;
584
585	flags |= KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY;
586
587	if (use_blacklist)
588		flags |= KMOD_PROBE_APPLY_BLACKLIST;
589	if (first_time)
590		flags |= KMOD_PROBE_FAIL_ON_LOADED;
591
592	kmod_list_foreach(l, list) {
593		struct kmod_module *mod = kmod_module_get_module(l);
594
595		if (lookup_only)
596			printf("%s\n", kmod_module_get_name(mod));
597		else {
598			err = kmod_module_probe_insert_module(mod, flags,
599					extra_options, NULL, NULL, show);
600		}
601
602		if (err >= 0)
603			/* ignore flag return values such as a mod being blacklisted */
604			err = 0;
605		else {
606			switch (err) {
607			case -EEXIST:
608				ERR("could not insert '%s': Module already in kernel\n",
609							kmod_module_get_name(mod));
610				break;
611			case -ENOENT:
612				ERR("could not insert '%s': Unknown symbol in module, "
613						"or unknown parameter (see dmesg)\n",
614						kmod_module_get_name(mod));
615				break;
616			default:
617				ERR("could not insert '%s': %s\n",
618						kmod_module_get_name(mod),
619						strerror(-err));
620				break;
621			}
622		}
623
624		kmod_module_unref(mod);
625	}
626
627	kmod_module_unref_list(list);
628	return err;
629}
630
631static int insmod_all(struct kmod_ctx *ctx, char **args, int nargs)
632{
633	int i, err = 0;
634
635	for (i = 0; i < nargs; i++) {
636		int r = insmod(ctx, args[i], NULL);
637		if (r < 0)
638			err = r;
639	}
640
641	return err;
642}
643
644static void env_modprobe_options_append(const char *value)
645{
646	const char *old = getenv("MODPROBE_OPTIONS");
647	char *env;
648
649	if (old == NULL) {
650		setenv("MODPROBE_OPTIONS", value, 1);
651		return;
652	}
653
654	if (asprintf(&env, "%s %s", old, value) < 0) {
655		ERR("could not append value to $MODPROBE_OPTIONS\n");
656		return;
657	}
658
659	if (setenv("MODPROBE_OPTIONS", env, 1) < 0)
660		ERR("could not setenv(MODPROBE_OPTIONS, \"%s\")\n", env);
661	free(env);
662}
663
664static int options_from_array(char **args, int nargs, char **output)
665{
666	char *opts = NULL;
667	size_t optslen = 0;
668	int i, err = 0;
669
670	for (i = 1; i < nargs; i++) {
671		size_t len = strlen(args[i]);
672		size_t qlen = 0;
673		const char *value;
674		void *tmp;
675
676		value = strchr(args[i], '=');
677		if (value) {
678			value++;
679			if (*value != '"' && *value != '\'') {
680				if (strchr(value, ' '))
681					qlen = 2;
682			}
683		}
684
685		tmp = realloc(opts, optslen + len + qlen + 2);
686		if (!tmp) {
687			err = -errno;
688			free(opts);
689			opts = NULL;
690			ERR("could not gather module options: out-of-memory\n");
691			break;
692		}
693		opts = tmp;
694		if (optslen > 0) {
695			opts[optslen] = ' ';
696			optslen++;
697		}
698		if (qlen == 0) {
699			memcpy(opts + optslen, args[i], len + 1);
700			optslen += len;
701		} else {
702			size_t keylen = value - args[i];
703			size_t valuelen = len - keylen;
704			memcpy(opts + optslen, args[i], keylen);
705			optslen += keylen;
706			opts[optslen] = '"';
707			optslen++;
708			memcpy(opts + optslen, value, valuelen);
709			optslen += valuelen;
710			opts[optslen] = '"';
711			optslen++;
712			opts[optslen] = '\0';
713		}
714	}
715
716	*output = opts;
717	return err;
718}
719
720static char **prepend_options_from_env(int *p_argc, char **orig_argv)
721{
722	const char *p, *env = getenv("MODPROBE_OPTIONS");
723	char **new_argv, *str_start, *str_end, *str, *s, *quote;
724	int i, argc = *p_argc;
725	size_t envlen, space_count = 0;
726
727	if (env == NULL)
728		return orig_argv;
729
730	for (p = env; *p != '\0'; p++) {
731		if (*p == ' ')
732			space_count++;
733	}
734
735	envlen = p - env;
736	new_argv = malloc(sizeof(char *) * (argc + space_count + 3 + envlen));
737	if (new_argv == NULL)
738		return NULL;
739
740	new_argv[0] = orig_argv[0];
741	str_start = str = (char *) (new_argv + argc + space_count + 3);
742	memcpy(str, env, envlen + 1);
743
744	str_end = str_start + envlen;
745
746	quote = NULL;
747	for (i = 1, s = str; *s != '\0'; s++) {
748		if (quote == NULL) {
749			if (*s == ' ') {
750				new_argv[i] = str;
751				i++;
752				*s = '\0';
753				str = s + 1;
754			} else if (*s == '"' || *s == '\'')
755				quote = s;
756		} else {
757			if (*s == *quote) {
758				if (quote == str) {
759					new_argv[i] = str + 1;
760					i++;
761					*s = '\0';
762					str = s + 1;
763				} else {
764					char *it;
765					for (it = quote; it < s - 1; it++)
766						it[0] = it[1];
767					for (it = s - 1; it < str_end - 2; it++)
768						it[0] = it[2];
769					str_end -= 2;
770					*str_end = '\0';
771					s -= 2;
772				}
773				quote = NULL;
774			}
775		}
776	}
777	if (str < s) {
778		new_argv[i] = str;
779		i++;
780	}
781
782	memcpy(new_argv + i, orig_argv + 1, sizeof(char *) * (argc - 1));
783	new_argv[i + argc] = NULL;
784	*p_argc = i + argc - 1;
785
786	return new_argv;
787}
788
789static void log_syslog(void *data, int priority, const char *file, int line,
790			const char *fn, const char *format, va_list args)
791{
792	char *str, buf[32];
793	const char *prioname;
794
795	switch (priority) {
796	case LOG_CRIT:
797		prioname = "FATAL";
798		break;
799	case LOG_ERR:
800		prioname = "ERROR";
801		break;
802	case LOG_WARNING:
803		prioname = "WARNING";
804		break;
805	case LOG_NOTICE:
806		prioname = "NOTICE";
807		break;
808	case LOG_INFO:
809		prioname = "INFO";
810		break;
811	case LOG_DEBUG:
812		prioname = "DEBUG";
813		break;
814	default:
815		snprintf(buf, sizeof(buf), "LOG-%03d", priority);
816		prioname = buf;
817	}
818
819	if (vasprintf(&str, format, args) < 0)
820		return;
821#ifdef ENABLE_DEBUG
822	syslog(LOG_NOTICE, "%s: %s:%d %s() %s", prioname, file, line, fn, str);
823#else
824	syslog(LOG_NOTICE, "%s: %s", prioname, str);
825#endif
826	free(str);
827	(void)data;
828}
829
830static int do_modprobe(int argc, char **orig_argv)
831{
832	struct kmod_ctx *ctx;
833	char **args = NULL, **argv;
834	const char **config_paths = NULL;
835	int nargs = 0, n_config_paths = 0;
836	char dirname_buf[PATH_MAX];
837	const char *dirname = NULL;
838	const char *root = NULL;
839	const char *kversion = NULL;
840	int use_all = 0;
841	int do_remove = 0;
842	int do_show_config = 0;
843	int do_show_modversions = 0;
844	int err;
845
846	argv = prepend_options_from_env(&argc, orig_argv);
847	if (argv == NULL) {
848		fputs("Error: could not prepend options from command line\n",
849			stderr);
850		return EXIT_FAILURE;
851	}
852
853	for (;;) {
854		int c, idx = 0;
855		c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
856		if (c == -1)
857			break;
858		switch (c) {
859		case 'a':
860			log_priority = LOG_WARNING;
861			use_all = 1;
862			break;
863		case 'r':
864			do_remove = 1;
865			break;
866		case 5:
867			remove_dependencies = 1;
868			break;
869		case 'R':
870			lookup_only = 1;
871			break;
872		case 3:
873			first_time = 1;
874			break;
875		case 'i':
876			ignore_commands = 1;
877			break;
878		case 'b':
879			use_blacklist = 1;
880			break;
881		case 'f':
882			force = 1;
883			break;
884		case 2:
885			strip_modversion = 1;
886			break;
887		case 1:
888			strip_vermagic = 1;
889			break;
890		case 'D':
891			ignore_loaded = 1;
892			dry_run = 1;
893			do_show = 1;
894			break;
895		case 'c':
896			do_show_config = 1;
897			break;
898		case 4:
899			do_show_modversions = 1;
900			break;
901		case 'n':
902			dry_run = 1;
903			break;
904		case 'C': {
905			size_t bytes = sizeof(char *) * (n_config_paths + 2);
906			void *tmp = realloc(config_paths, bytes);
907			if (!tmp) {
908				fputs("Error: out-of-memory\n", stderr);
909				goto cmdline_failed;
910			}
911			config_paths = tmp;
912			config_paths[n_config_paths] = optarg;
913			n_config_paths++;
914			config_paths[n_config_paths] = NULL;
915
916			env_modprobe_options_append("-C");
917			env_modprobe_options_append(optarg);
918			break;
919		}
920		case 'd':
921			root = optarg;
922			break;
923		case 'S':
924			kversion = optarg;
925			break;
926		case 's':
927			env_modprobe_options_append("-s");
928			use_syslog = 1;
929			break;
930		case 'q':
931			env_modprobe_options_append("-q");
932			verbose = LOG_EMERG;
933			break;
934		case 'v':
935			env_modprobe_options_append("-v");
936			verbose++;
937			break;
938		case 'V':
939			puts(PACKAGE " version " VERSION);
940			err = EXIT_SUCCESS;
941			goto done;
942		case 'h':
943			help(basename(argv[0]));
944			err = EXIT_SUCCESS;
945			goto done;
946		case '?':
947			goto cmdline_failed;
948		default:
949			fprintf(stderr, "Error: unexpected getopt_long() value '%c'.\n",
950									c);
951			goto cmdline_failed;
952		}
953	}
954
955	args = argv + optind;
956	nargs = argc - optind;
957
958	if (!do_show_config) {
959		if (nargs == 0) {
960			fputs("Error: missing parameters. See -h.\n", stderr);
961			goto cmdline_failed;
962		}
963	}
964
965	if (root != NULL || kversion != NULL) {
966		struct utsname u;
967		if (root == NULL)
968			root = "";
969		if (kversion == NULL) {
970			if (uname(&u) < 0) {
971				fprintf(stderr, "Error: uname() failed: %s\n",
972					strerror(errno));
973				goto cmdline_failed;
974			}
975			kversion = u.release;
976		}
977		snprintf(dirname_buf, sizeof(dirname_buf),
978				"%s/lib/modules/%s", root,
979				kversion);
980		dirname = dirname_buf;
981	}
982
983	ctx = kmod_new(dirname, config_paths);
984	if (!ctx) {
985		fputs("Error: kmod_new() failed!\n", stderr);
986		goto cmdline_failed;
987	}
988	kmod_load_resources(ctx);
989
990	kmod_set_log_priority(ctx, verbose);
991	if (use_syslog) {
992		openlog("modprobe", LOG_CONS, LOG_DAEMON);
993		kmod_set_log_fn(ctx, log_syslog, NULL);
994	}
995
996	if (do_show_config)
997		err = show_config(ctx);
998	else if (do_show_modversions)
999		err = show_modversions(ctx, args[0]);
1000	else if (do_remove)
1001		err = rmmod_all(ctx, args, nargs);
1002	else if (use_all)
1003		err = insmod_all(ctx, args, nargs);
1004	else {
1005		char *opts;
1006		err = options_from_array(args, nargs, &opts);
1007		if (err == 0) {
1008			err = insmod(ctx, args[0], opts);
1009			free(opts);
1010		}
1011	}
1012
1013	kmod_unref(ctx);
1014
1015	if (use_syslog)
1016		closelog();
1017
1018done:
1019	if (argv != orig_argv)
1020		free(argv);
1021
1022	free(config_paths);
1023	return err >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1024
1025cmdline_failed:
1026	if (argv != orig_argv)
1027		free(argv);
1028	free(config_paths);
1029	return EXIT_FAILURE;
1030}
1031
1032#include "kmod.h"
1033
1034const struct kmod_cmd kmod_cmd_compat_modprobe = {
1035	.name = "modprobe",
1036	.cmd = do_modprobe,
1037	.help = "compat modprobe command",
1038};
1039