libkmod-module: convert return value from system() to errno
[platform/upstream/kmod.git] / tools / remove.c
1 /*
2  * kmod-remove - remove modules from the kernel.
3  *
4  * Copyright (C) 2015 Intel Corporation. All rights reserved.
5  * Copyright (C) 2011-2013  ProFUSION embedded systems
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <errno.h>
22 #include <getopt.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <libkmod/libkmod.h>
27
28 #include "kmod.h"
29
30 static const char cmdopts_s[] = "h";
31 static const struct option cmdopts[] = {
32         {"help", no_argument, 0, 'h'},
33         { }
34 };
35
36 static void help(void)
37 {
38         printf("Usage:\n"
39                "\t%s remove [options] module\n"
40                "Options:\n"
41                "\t-h, --help        show this help\n",
42                program_invocation_short_name);
43 }
44
45 static int check_module_inuse(struct kmod_module *mod) {
46         struct kmod_list *holders;
47         int state, ret;
48
49         state = kmod_module_get_initstate(mod);
50
51         if (state == KMOD_MODULE_BUILTIN) {
52                 ERR("Module %s is builtin.\n", kmod_module_get_name(mod));
53                 return -ENOENT;
54         } else if (state < 0) {
55                 ERR("Module %s is not currently loaded\n",
56                                 kmod_module_get_name(mod));
57                 return -ENOENT;
58         }
59
60         holders = kmod_module_get_holders(mod);
61         if (holders != NULL) {
62                 struct kmod_list *itr;
63
64                 ERR("Module %s is in use by:", kmod_module_get_name(mod));
65
66                 kmod_list_foreach(itr, holders) {
67                         struct kmod_module *hm = kmod_module_get_module(itr);
68                         fprintf(stderr, " %s", kmod_module_get_name(hm));
69                         kmod_module_unref(hm);
70                 }
71                 fputc('\n', stderr);
72
73                 kmod_module_unref_list(holders);
74                 return -EBUSY;
75         }
76
77         ret = kmod_module_get_refcnt(mod);
78         if (ret > 0) {
79                 ERR("Module %s is in use\n", kmod_module_get_name(mod));
80                 return -EBUSY;
81         } else if (ret == -ENOENT) {
82                 ERR("Module unloading is not supported\n");
83         }
84
85         return ret;
86 }
87
88 static int do_remove(int argc, char *argv[])
89 {
90         struct kmod_ctx *ctx;
91         struct kmod_module *mod;
92         const char *name;
93         int err, r = EXIT_SUCCESS;
94
95         for (;;) {
96                 int c, idx =0;
97                 c = getopt_long(argc, argv, cmdopts_s, cmdopts, &idx);
98                 if (c == -1)
99                         break;
100                 switch (c) {
101                 case 'h':
102                         help();
103                         return EXIT_SUCCESS;
104
105                 default:
106                         ERR("Unexpected getopt_long() value '%c'.\n", c);
107                         return EXIT_FAILURE;
108                 }
109         }
110
111         if (optind >= argc) {
112                 ERR("Missing module name\n");
113                 return EXIT_FAILURE;
114         }
115
116         ctx = kmod_new(NULL, NULL);
117         if (!ctx) {
118                 ERR("kmod_new() failed!\n");
119                 return EXIT_FAILURE;
120         }
121
122         name = argv[optind];
123         err = kmod_module_new_from_name(ctx, name, &mod);
124         if (err < 0) {
125                 ERR("Could not remove module %s: %s\n", name, strerror(-err));
126                 goto end;
127         }
128
129         err = check_module_inuse(mod);
130         if (err < 0)
131                 goto unref;
132
133         err = kmod_module_remove_module(mod, 0);
134         if (err < 0)
135                 goto unref;
136
137 unref:
138         kmod_module_unref(mod);
139
140 end:
141         kmod_unref(ctx);
142         if (err < 0) {
143                 r = EXIT_FAILURE;
144                 ERR("Could not remove module %s: %s\n", name, strerror(-err));
145         }
146         return r;
147 }
148
149 const struct kmod_cmd kmod_cmd_remove = {
150         .name = "remove",
151         .cmd = do_remove,
152         .help = "remove module from kernel",
153 };