- move #include busybox.h to the very top so we pull in the config
[oweals/busybox.git] / modutils / rmmod.c
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 "busybox.h"
11 #include <stdio.h>
12 #include <errno.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <getopt.h>
16 #include <fcntl.h>
17 #include <string.h>
18 #include <sys/utsname.h>
19 #include <sys/syscall.h>
20
21 #ifdef CONFIG_FEATURE_2_6_MODULES
22 static inline void filename2modname(char *modname, const char *afterslash)
23 {
24         unsigned int i;
25
26 #if ENABLE_FEATURE_2_4_MODULES
27         int kr_chk = 1;
28         if (get_linux_version_code() <= KERNEL_VERSION(2,6,0))
29                 kr_chk = 0;
30 #else
31 #define kr_chk 1
32 #endif
33
34         /* Convert to underscores, stop at first . */
35         for (i = 0; afterslash[i] && afterslash[i] != '.'; i++) {
36                 if (kr_chk && (afterslash[i] == '-'))
37                         modname[i] = '_';
38                 else
39                         modname[i] = afterslash[i];
40         }
41         modname[i] = '\0';
42 }
43 #endif
44
45 int rmmod_main(int argc, char **argv)
46 {
47         int n, ret = EXIT_SUCCESS;
48         unsigned int flags = O_NONBLOCK|O_EXCL;
49 #ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE
50         /* bb_common_bufsiz1 hold the module names which we ignore
51            but must get */
52         size_t bufsize = sizeof(bb_common_bufsiz1);
53 #endif
54
55         /* Parse command line. */
56         n = bb_getopt_ulflags(argc, argv, "wfa");
57         if((n & 1))     // --wait
58                 flags &= ~O_NONBLOCK;
59         if((n & 2))     // --force
60                 flags |= O_TRUNC;
61         if((n & 4)) {
62                 /* Unload _all_ unused modules via NULL delete_module() call */
63                 /* until the number of modules does not change */
64                 size_t nmod = 0; /* number of modules */
65                 size_t pnmod = -1; /* previous number of modules */
66
67                 while (nmod != pnmod) {
68                         if (syscall(__NR_delete_module, NULL, flags) != 0) {
69                                 if (errno==EFAULT)
70                                         return(ret);
71                                 bb_perror_msg_and_die("rmmod");
72                         }
73                         pnmod = nmod;
74 #ifdef CONFIG_FEATURE_QUERY_MODULE_INTERFACE
75                         /* 1 == QM_MODULES */
76                         if (my_query_module(NULL, 1, &bb_common_bufsiz1, &bufsize, &nmod)) {
77                                 bb_perror_msg_and_die("QM_MODULES");
78                         }
79 #endif
80                 }
81                 return EXIT_SUCCESS;
82         }
83
84         if (optind == argc)
85                 bb_show_usage();
86
87         for (n = optind; n < argc; n++) {
88 #ifdef CONFIG_FEATURE_2_6_MODULES
89                 const char *afterslash;
90                 char *module_name;
91
92                 afterslash = strrchr(argv[n], '/');
93                 if (!afterslash)
94                         afterslash = argv[n];
95                 else
96                         afterslash++;
97                 module_name = alloca(strlen(afterslash) + 1);
98                 filename2modname(module_name, afterslash);
99 #else
100 #define module_name             argv[n]
101 #endif
102                 if (syscall(__NR_delete_module, module_name, flags) != 0) {
103                         bb_perror_msg("%s", argv[n]);
104                         ret = EXIT_FAILURE;
105                 }
106         }
107
108         return(ret);
109 }