1/* vi: set sw=4 ts=4: */
2/*
3 * Mini rmmod implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include "libbb.h"
11#include <sys/syscall.h>
12
13#if ENABLE_FEATURE_2_6_MODULES
14static inline void filename2modname(char *modname, const char *afterslash)
15{
16	unsigned int i;
17	int kr_chk = 1;
18
19	if (ENABLE_FEATURE_2_4_MODULES
20			&& get_linux_version_code() <= KERNEL_VERSION(2,6,0))
21				kr_chk = 0;
22
23	/* Convert to underscores, stop at first . */
24	for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
25		if (kr_chk && (afterslash[i] == '-'))
26			modname[i] = '_';
27		else
28			modname[i] = afterslash[i];
29	}
30	modname[i] = '\0';
31}
32#else
33void filename2modname(char *modname, const char *afterslash);
34#endif
35
36// There really should be a header file for this...
37
38int query_module(const char *name, int which, void *buf,
39			size_t bufsize, size_t *ret);
40
41int rmmod_main(int argc, char **argv);
42int rmmod_main(int argc, char **argv)
43{
44	int n, ret = EXIT_SUCCESS;
45	unsigned int flags = O_NONBLOCK|O_EXCL;
46
47#define misc_buf bb_common_bufsiz1
48
49	/* Parse command line. */
50	n = getopt32(argv, "wfa");
51	if (n & 1)	// --wait
52		flags &= ~O_NONBLOCK;
53	if (n & 2)	// --force
54		flags |= O_TRUNC;
55	if (n & 4) {
56		/* Unload _all_ unused modules via NULL delete_module() call */
57		/* until the number of modules does not change */
58		size_t nmod = 0; /* number of modules */
59		size_t pnmod = -1; /* previous number of modules */
60
61		while (nmod != pnmod) {
62			if (syscall(__NR_delete_module, NULL, flags) != 0) {
63				if (errno == EFAULT)
64					return ret;
65				bb_perror_msg_and_die("rmmod");
66			}
67			pnmod = nmod;
68			// the 1 here is QM_MODULES.
69			if (ENABLE_FEATURE_QUERY_MODULE_INTERFACE && query_module(NULL,
70					1, misc_buf, sizeof(misc_buf),
71					&nmod))
72			{
73				bb_perror_msg_and_die("QM_MODULES");
74			}
75		}
76		return EXIT_SUCCESS;
77	}
78
79	if (optind == argc)
80		bb_show_usage();
81
82	for (n = optind; n < argc; n++) {
83		if (ENABLE_FEATURE_2_6_MODULES) {
84			filename2modname(misc_buf, bb_basename(argv[n]));
85		}
86
87		if (syscall(__NR_delete_module, ENABLE_FEATURE_2_6_MODULES ? misc_buf : argv[n], flags)) {
88			bb_perror_msg("%s", argv[n]);
89			ret = EXIT_FAILURE;
90		}
91	}
92
93	return ret;
94}
95