]> git.ipfire.org Git - thirdparty/kmod.git/blob - libkmod/libkmod-loaded.c
improve "const" keyword usage.
[thirdparty/kmod.git] / libkmod / libkmod-loaded.c
1 /*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation version 2.1.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stddef.h>
23 #include <stdarg.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <inttypes.h>
29
30 #include "libkmod.h"
31 #include "libkmod-private.h"
32
33 /**
34 * SECTION:libkmod-loaded
35 * @short_description: currently loaded modules
36 *
37 * Information about currently loaded modules, as reported by Linux kernel
38 */
39
40 /**
41 * kmod_loaded:
42 *
43 * Opaque object representing a loaded module.
44 */
45 struct kmod_loaded {
46 struct kmod_ctx *ctx;
47 int refcount;
48 struct kmod_list *modules;
49 bool parsed;
50 };
51
52 struct kmod_loaded_module {
53 char *name;
54 long size;
55 int use_count;
56 char *deps;
57 uintptr_t addr;
58 };
59
60 KMOD_EXPORT int kmod_loaded_new(struct kmod_ctx *ctx, struct kmod_loaded **mod)
61 {
62 struct kmod_loaded *m;
63
64 m = calloc(1, sizeof(*m));
65 if (m == NULL)
66 return -ENOMEM;
67
68 m->refcount = 1;
69 m->ctx = kmod_ref(ctx);
70 *mod = m;
71 return 0;
72 }
73
74 KMOD_EXPORT struct kmod_loaded *kmod_loaded_ref(struct kmod_loaded *mod)
75 {
76 if (mod == NULL)
77 return NULL;
78 mod->refcount++;
79 return mod;
80 }
81
82 static void loaded_modules_free_module(struct kmod_loaded_module *m)
83 {
84 free(m->name);
85 free(m->deps);
86 free(m);
87 }
88
89 static void loaded_modules_free(struct kmod_loaded *mod)
90 {
91 while (mod->modules != NULL) {
92 loaded_modules_free_module(mod->modules->data);
93 mod->modules = kmod_list_remove(mod->modules);
94 }
95 }
96
97 KMOD_EXPORT struct kmod_loaded *kmod_loaded_unref(struct kmod_loaded *mod)
98 {
99 if (mod == NULL)
100 return NULL;
101
102 if (--mod->refcount > 0)
103 return mod;
104
105 DBG(mod->ctx, "kmod_loaded %p released\n", mod);
106
107 kmod_unref(mod->ctx);
108 loaded_modules_free(mod);
109 free(mod);
110 return NULL;
111 }
112
113 static int loaded_modules_parse(struct kmod_loaded *mod,
114 struct kmod_list **list)
115 {
116 struct kmod_list *l = NULL;
117 FILE *fp;
118 char line[4096];
119
120 fp = fopen("/proc/modules", "r");
121 if (fp == NULL)
122 return -errno;
123
124 while (fgets(line, sizeof(line), fp)) {
125 char *tok;
126 struct kmod_loaded_module *m;
127
128 m = calloc(1, sizeof(*m));
129 if (m == NULL)
130 goto err;
131
132 tok = strtok(line, " \t");
133 m->name = strdup(tok);
134
135 tok = strtok(NULL, " \t\n");
136 m->size = atoi(tok);
137
138 /* Null if no module unloading is supported */
139 tok = strtok(NULL, " \t\n");
140 if (tok == NULL)
141 goto done;
142
143 m->use_count = atoi(tok);
144 tok = strtok(NULL, "\n");
145 if (tok == NULL)
146 goto done;
147
148 /* Strip trailing comma */
149 if (strchr(tok, ',')) {
150 char *end;
151 tok = strtok(tok, " \t");
152 end = &tok[strlen(tok) - 1];
153 if (*end == ',')
154 *end = '\0';
155 m->deps = strdup(tok);
156 tok = &end[2];
157 } else if (tok[0] == '-' && tok[1] == '\0')
158 goto done;
159 else if (tok[0] == '-' && isspace(tok[1]))
160 tok = &tok[3];
161
162 tok = strtok(tok, " \t\n");
163 if (tok == NULL)
164 goto done;
165
166 tok = strtok(NULL, " \t\n");
167 if (tok == NULL)
168 goto done;
169
170 m->addr = strtoull(tok, NULL, 16);
171
172 done:
173 l = kmod_list_append(l, m);
174 }
175
176 fclose(fp);
177 mod->parsed = 1;
178 *list = l;
179
180 return 0;
181
182 err:
183 fclose(fp);
184 mod->modules = l;
185 loaded_modules_free(mod);
186 mod->modules = NULL;
187 return -ENOMEM;
188 }
189
190 KMOD_EXPORT int kmod_loaded_get_list(struct kmod_loaded *mod,
191 struct kmod_list **list)
192 {
193 if (mod == NULL)
194 return -ENOENT;
195
196 if (!mod->parsed) {
197 int err = loaded_modules_parse(mod, &mod->modules);
198 if (err < 0)
199 return err;
200 }
201
202 *list = mod->modules;
203
204 return 0;
205 }
206
207 KMOD_EXPORT int kmod_loaded_get_module_info(const struct kmod_list *entry,
208 const char **name,
209 long *size, int *use_count,
210 const char **deps,
211 uintptr_t *addr)
212 {
213 const struct kmod_loaded_module *m;
214
215 if (entry == NULL)
216 return -ENOENT;
217
218 m = entry->data;
219
220 if (name)
221 *name = m->name;
222 if (size)
223 *size = m->size;
224 if (use_count)
225 *use_count = m->use_count;
226 if (addr)
227 *addr = m->addr;
228 if (deps)
229 *deps = m->deps;
230
231 return 0;
232 }
233
234 extern long delete_module(const char *name, unsigned int flags);
235
236 KMOD_EXPORT int kmod_loaded_remove_module(struct kmod_loaded *mod,
237 struct kmod_list *entry,
238 unsigned int flags)
239 {
240 struct kmod_loaded_module *m;
241 int err;
242
243 if (mod == NULL)
244 return -ENOSYS;
245
246 if (entry == NULL)
247 return -ENOENT;
248
249 m = entry->data;
250
251 /* Filter out other flags */
252 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
253
254 err = delete_module(m->name, flags);
255 if (err != 0) {
256 ERR(mod->ctx, "Removing '%s': %s\n", m->name,
257 strerror(-err));
258 return err;
259 }
260
261 loaded_modules_free_module(m);
262 kmod_list_remove(entry);
263
264 return 0;
265 }