blob: 0aee3eef903fb83c1a74f5c99ff0b727fc9cd1c2 [file] [log] [blame]
Lucas De Marchi8f788d52011-11-25 01:22:56 -02001/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2011 ProFUSION embedded systems
Lucas De Marchi8f788d52011-11-25 01:22:56 -02005 *
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
Lucas De Marchi7636e722011-12-01 17:56:03 -020020#include <assert.h>
Lucas De Marchi8f788d52011-11-25 01:22:56 -020021#include <stdio.h>
22#include <stdlib.h>
23#include <stddef.h>
24#include <stdarg.h>
25#include <unistd.h>
26#include <errno.h>
27#include <string.h>
28#include <ctype.h>
29#include <inttypes.h>
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -020030#include <limits.h>
31#include <dirent.h>
Lucas De Marchi8f788d52011-11-25 01:22:56 -020032#include <sys/stat.h>
33#include <sys/types.h>
34#include <sys/mman.h>
35#include <string.h>
36
37#include "libkmod.h"
38#include "libkmod-private.h"
39
40/**
41 * kmod_module:
42 *
43 * Opaque object representing a module.
44 */
45struct kmod_module {
46 struct kmod_ctx *ctx;
Lucas De Marchi8f788d52011-11-25 01:22:56 -020047 const char *path;
Lucas De Marchi7636e722011-12-01 17:56:03 -020048 struct kmod_list *dep;
Gustavo Sverzut Barbieri8d3f3ef2011-12-02 21:10:24 -020049 int refcount;
Lucas De Marchi7636e722011-12-01 17:56:03 -020050 struct {
51 bool dep : 1;
52 } init;
Lucas De Marchid753b8c2011-12-05 18:14:51 -020053 char name[];
Lucas De Marchi8f788d52011-11-25 01:22:56 -020054};
55
Lucas De Marchi6c343b12011-12-06 09:01:01 -020056static inline char *modname_normalize(char *modname, char buf[NAME_MAX],
57 size_t *len)
Lucas De Marchi8f788d52011-11-25 01:22:56 -020058{
Lucas De Marchi8f788d52011-11-25 01:22:56 -020059 char *c;
Lucas De Marchid753b8c2011-12-05 18:14:51 -020060 size_t s;
Lucas De Marchi8f788d52011-11-25 01:22:56 -020061
Lucas De Marchid753b8c2011-12-05 18:14:51 -020062 if (buf) {
63 buf[NAME_MAX] = '\0';
64 modname = strncpy(buf, modname, NAME_MAX - 1);
Lucas De Marchi8f788d52011-11-25 01:22:56 -020065 }
66
Lucas De Marchid753b8c2011-12-05 18:14:51 -020067 for (c = modname, s = 0; *c != '\0' && *c != '.'; c++) {
68 if (*c == '-')
69 *c = '_';
70 s++;
71 }
72
73 if (len)
74 *len = s;
75
Lucas De Marchi8f788d52011-11-25 01:22:56 -020076 *c = '\0';
Lucas De Marchid753b8c2011-12-05 18:14:51 -020077
Lucas De Marchi8f788d52011-11-25 01:22:56 -020078 return modname;
79}
80
Lucas De Marchi6c343b12011-12-06 09:01:01 -020081static char *path_to_modname(const char *path, char buf[NAME_MAX], size_t *len)
82{
83 char *modname;
84
85 modname = basename(path);
86 if (modname == NULL || modname[0] == '\0')
87 return NULL;
88
89 return modname_normalize(modname, buf, len);
90}
91
Lucas De Marchi671d4892011-12-05 20:23:05 -020092int kmod_module_parse_depline(struct kmod_module *mod, char *line)
Lucas De Marchi7636e722011-12-01 17:56:03 -020093{
94 struct kmod_ctx *ctx = mod->ctx;
95 struct kmod_list *list = NULL;
96 char *p, *saveptr;
97 int err, n = 0;
98
99 assert(!mod->init.dep && mod->dep == NULL);
100 mod->init.dep = true;
101
102 p = strchr(line, ':');
103 if (p == NULL)
104 return 0;
105
Lucas De Marchi671d4892011-12-05 20:23:05 -0200106 *p = '\0';
107 if (mod->path == NULL)
108 mod->path = strdup(line);
109
Lucas De Marchi7636e722011-12-01 17:56:03 -0200110 p++;
111
112 for (p = strtok_r(p, " \t", &saveptr); p != NULL;
113 p = strtok_r(NULL, " \t", &saveptr)) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200114 const char *modname = path_to_modname(p, NULL, NULL);
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200115 struct kmod_module *depmod;
Lucas De Marchi7636e722011-12-01 17:56:03 -0200116
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200117 err = kmod_module_new_from_name(ctx, modname, &depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200118 if (err < 0) {
119 ERR(ctx, "ctx=%p modname=%s error=%s\n",
120 ctx, modname, strerror(-err));
121 goto fail;
122 }
123
124 DBG(ctx, "add dep: %s\n", modname);
125
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200126 list = kmod_list_append(list, depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200127 n++;
128 }
129
130 DBG(ctx, "%d dependencies for %s\n", n, mod->name);
131
132 mod->dep = list;
133 return n;
134
135fail:
136 kmod_module_unref_list(list);
137 mod->init.dep = false;
138 return err;
139}
140
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200141KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
142 const char *name,
143 struct kmod_module **mod)
144{
145 struct kmod_module *m;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200146 size_t namelen;
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200147 char name_norm[NAME_MAX];
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200148
149 if (ctx == NULL || name == NULL)
150 return -ENOENT;
151
Lucas De Marchi6c343b12011-12-06 09:01:01 -0200152 modname_normalize((char *)name, name_norm, &namelen);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200153
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200154 m = kmod_pool_get_module(ctx, name_norm);
155 if (m != NULL) {
156 *mod = kmod_module_ref(m);
157 return 0;
158 }
159
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200160 m = calloc(1, sizeof(*m) + namelen + 1);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200161 if (m == NULL) {
162 free(m);
163 return -ENOMEM;
164 }
165
166 m->ctx = kmod_ref(ctx);
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200167 memcpy(m->name, name_norm, namelen + 1);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200168 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200169
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200170 kmod_pool_add_module(ctx, m);
171
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200172 *mod = m;
173
174 return 0;
175}
176
177KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
178 const char *path,
179 struct kmod_module **mod)
180{
181 struct kmod_module *m;
182 int err;
183 struct stat st;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200184 char name[NAME_MAX];
Lucas De Marchi71e975c2011-12-07 13:53:53 -0200185 char *abspath;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200186 size_t namelen;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200187
188 if (ctx == NULL || path == NULL)
189 return -ENOENT;
190
Lucas De Marchi71e975c2011-12-07 13:53:53 -0200191 abspath = path_make_absolute_cwd(path);
192 if (abspath == NULL)
193 return -ENOMEM;
194
195 err = stat(abspath, &st);
196 if (err < 0) {
197 free(abspath);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200198 return -errno;
Lucas De Marchi71e975c2011-12-07 13:53:53 -0200199 }
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200200
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200201 path_to_modname(path, name, &namelen);
202
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200203 m = kmod_pool_get_module(ctx, name);
204 if (m != NULL) {
Lucas De Marchi71e975c2011-12-07 13:53:53 -0200205 free(abspath);
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200206 *mod = kmod_module_ref(m);
207 return 0;
208 }
209
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200210 m = calloc(1, sizeof(*m) + namelen + 1);
211 if (m == NULL)
212 return -errno;
213
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200214 m->ctx = kmod_ref(ctx);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200215 memcpy(m->name, name, namelen);
Lucas De Marchi71e975c2011-12-07 13:53:53 -0200216 m->path = abspath;
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200217 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200218
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200219 kmod_pool_add_module(ctx, m);
220
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200221 *mod = m;
222
223 return 0;
224}
225
226KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
227{
228 if (mod == NULL)
229 return NULL;
230
231 if (--mod->refcount > 0)
232 return mod;
233
234 DBG(mod->ctx, "kmod_module %p released\n", mod);
235
Lucas De Marchi7636e722011-12-01 17:56:03 -0200236 kmod_module_unref_list(mod->dep);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200237 kmod_unref(mod->ctx);
238 free((char *) mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200239 free(mod);
240 return NULL;
241}
242
243KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
244{
245 if (mod == NULL)
246 return NULL;
247
248 mod->refcount++;
249
250 return mod;
251}
252
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200253#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
254 do { \
255 if ((_err) < 0) \
256 goto _label_err; \
257 if (*(_list) != NULL) \
258 goto finish; \
259 } while (0)
260
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200261KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
262 const char *alias,
263 struct kmod_list **list)
264{
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200265 int err;
266
267 if (ctx == NULL || alias == NULL)
268 return -ENOENT;
269
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200270 if (list == NULL || *list != NULL) {
271 ERR(ctx, "An empty list is needed to create lookup\n");
272 return -ENOSYS;
273 }
274
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200275 /* Aliases from config file override all the others */
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200276 err = kmod_lookup_alias_from_config(ctx, alias, list);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200277 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200278
Lucas De Marchi64700e42011-12-01 15:57:53 -0200279 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
280 CHECK_ERR_AND_FINISH(err, fail, list, finish);
281
Lucas De Marchi9ba6f572011-11-30 20:31:45 -0200282 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
283 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200284
Lucas De Marchi49e61ca2011-12-01 16:27:04 -0200285 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
286 CHECK_ERR_AND_FINISH(err, fail, list, finish);
287
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200288finish:
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200289
290 return err;
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200291fail:
292 kmod_module_unref_list(*list);
293 *list = NULL;
Lucas De Marchi84f42202011-12-02 10:03:34 -0200294 return err;
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200295}
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200296#undef CHECK_ERR_AND_FINISH
297
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200298
299KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
300{
301 for (; list != NULL; list = kmod_list_remove(list))
302 kmod_module_unref(list->data);
303
304 return 0;
305}
306
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200307KMOD_EXPORT struct kmod_list *kmod_module_get_dependencies(const struct kmod_module *mod)
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200308{
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200309 struct kmod_list *l, *l_new, *list_new = NULL;
310
311 if (mod == NULL)
312 return NULL;
313
Lucas De Marchi671d4892011-12-05 20:23:05 -0200314 if (!mod->init.dep) {
315 /* lazy init */
316 char *line = kmod_search_moddep(mod->ctx, mod->name);
317
318 if (line == NULL)
319 return NULL;
320
321 kmod_module_parse_depline((struct kmod_module *)mod, line);
322 free(line);
323
324 if (!mod->init.dep)
325 return NULL;
326 }
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200327
328 kmod_list_foreach(l, mod->dep) {
329 l_new = kmod_list_append(list_new, kmod_module_ref(l->data));
330 if (l_new == NULL) {
331 kmod_module_unref(l->data);
332 goto fail;
333 }
334
335 list_new = l_new;
336 }
337
338 return list_new;
339
340fail:
341 ERR(mod->ctx, "out of memory\n");
342 kmod_module_unref_list(list_new);
343 return NULL;
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200344}
345
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200346KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *entry)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200347{
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200348 if (entry == NULL)
349 return NULL;
350 return kmod_module_ref(entry->data);
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200351}
352
Gustavo Sverzut Barbieri69f9dd42011-12-04 14:02:30 -0200353KMOD_EXPORT long kmod_module_get_size(const struct kmod_module *mod)
354{
355 // FIXME TODO: this should be available from /sys/module/foo
356 FILE *fp;
357 char line[4096];
358 int lineno = 0;
359 long size = -ENOENT;
360
361 if (mod == NULL)
362 return -ENOENT;
363
364 fp = fopen("/proc/modules", "r");
365 if (fp == NULL) {
366 int err = -errno;
367 ERR(mod->ctx,
368 "could not open /proc/modules: %s\n", strerror(errno));
369 return err;
370 }
371
372 while (fgets(line, sizeof(line), fp)) {
373 char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
374 long value;
375
376 lineno++;
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200377 if (tok == NULL || !streq(tok, mod->name))
Gustavo Sverzut Barbieri69f9dd42011-12-04 14:02:30 -0200378 continue;
379
380 tok = strtok_r(NULL, " \t", &saveptr);
381 if (tok == NULL) {
382 ERR(mod->ctx,
383 "invalid line format at /proc/modules:%d\n", lineno);
384 break;
385 }
386
387 value = strtol(tok, &endptr, 10);
388 if (endptr == tok || *endptr != '\0') {
389 ERR(mod->ctx,
390 "invalid line format at /proc/modules:%d\n", lineno);
391 break;
392 }
393
394 size = value;
395 break;
396 }
397 fclose(fp);
398 return size;
399}
400
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200401KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200402{
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200403 return mod->name;
404}
405
Lucas De Marchic5e7b1f2011-12-05 20:28:13 -0200406/*
407 * Relative paths are relative to dirname. Absolute paths are only used when
408 * user created kmod_module by giving a path
409 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200410KMOD_EXPORT const char *kmod_module_get_path(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200411{
Lucas De Marchic5e7b1f2011-12-05 20:28:13 -0200412 if (!mod->init.dep) {
413 /* lazy init */
414 char *line = kmod_search_moddep(mod->ctx, mod->name);
415
416 if (line == NULL)
417 return NULL;
418
419 kmod_module_parse_depline((struct kmod_module *) mod, line);
420 free(line);
421
422 if (!mod->init.dep)
423 return NULL;
424 }
425
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200426 return mod->path;
427}
428
429
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200430extern long delete_module(const char *name, unsigned int flags);
431
432KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
433 unsigned int flags)
434{
435 int err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200436
437 if (mod == NULL)
438 return -ENOENT;
439
440 /* Filter out other flags */
441 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
442
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200443 err = delete_module(mod->name, flags);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200444 if (err != 0) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200445 ERR(mod->ctx, "Removing '%s': %s\n", mod->name,
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200446 strerror(-err));
447 return err;
448 }
449
450 return 0;
451}
452
453extern long init_module(void *mem, unsigned long len, const char *args);
454
455KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
456 unsigned int flags)
457{
458 int err;
459 void *mmaped_file;
460 struct stat st;
461 int fd;
462 const char *args = "";
463
464 if (mod == NULL)
465 return -ENOENT;
466
467 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200468 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200469 return -ENOSYS;
470 }
471
472 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200473 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200474
475 if ((fd = open(mod->path, O_RDONLY)) < 0) {
476 err = -errno;
477 return err;
478 }
479
Lucas De Marchib418a822011-12-01 23:13:27 -0200480 fstat(fd, &st);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200481
482 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
483 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
484 close(fd);
485 return -errno;
486 }
487
488 err = init_module(mmaped_file, st.st_size, args);
489 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200490 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200491
492 munmap(mmaped_file, st.st_size);
493 close(fd);
494
495 return err;
496}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200497
498KMOD_EXPORT const char *kmod_module_initstate_str(enum kmod_module_initstate state)
499{
500 switch (state) {
501 case KMOD_MODULE_BUILTIN:
502 return "builtin";
503 case KMOD_MODULE_LIVE:
504 return "live";
505 case KMOD_MODULE_COMING:
506 return "coming";
507 case KMOD_MODULE_GOING:
508 return "going";
509 default:
510 return NULL;
511 }
512}
513
514KMOD_EXPORT int kmod_module_get_initstate(const struct kmod_module *mod)
515{
516 char path[PATH_MAX], buf[32];
517 int fd, err, pathlen;
518
519 pathlen = snprintf(path, sizeof(path),
520 "/sys/module/%s/initstate", mod->name);
521 fd = open(path, O_RDONLY);
522 if (fd < 0) {
523 err = -errno;
524
525 if (pathlen > (int)sizeof("/initstate") - 1) {
526 struct stat st;
527 path[pathlen - (sizeof("/initstate") - 1)] = '\0';
528 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
529 return KMOD_MODULE_BUILTIN;
530 }
531
532 ERR(mod->ctx, "could not open '%s': %s\n",
533 path, strerror(-err));
534 return err;
535 }
536
537 err = read_str_safe(fd, buf, sizeof(buf));
538 close(fd);
539 if (err < 0) {
540 ERR(mod->ctx, "could not read from '%s': %s\n",
541 path, strerror(-err));
542 return err;
543 }
544
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200545 if (streq(buf, "live\n"))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200546 return KMOD_MODULE_LIVE;
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200547 else if (streq(buf, "coming\n"))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200548 return KMOD_MODULE_COMING;
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200549 else if (streq(buf, "going\n"))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200550 return KMOD_MODULE_GOING;
551
552 ERR(mod->ctx, "unknown %s: '%s'\n", path, buf);
553 return -EINVAL;
554}
555
556KMOD_EXPORT int kmod_module_get_refcnt(const struct kmod_module *mod)
557{
558 char path[PATH_MAX];
559 long refcnt;
560 int fd, err;
561
562 snprintf(path, sizeof(path), "/sys/module/%s/refcnt", mod->name);
563 fd = open(path, O_RDONLY);
564 if (fd < 0) {
565 err = -errno;
566 ERR(mod->ctx, "could not open '%s': %s\n",
567 path, strerror(errno));
568 return err;
569 }
570
571 err = read_str_long(fd, &refcnt, 10);
572 close(fd);
573 if (err < 0) {
574 ERR(mod->ctx, "could not read integer from '%s': '%s'\n",
575 path, strerror(-err));
576 return err;
577 }
578
579 return (int)refcnt;
580}
581
582KMOD_EXPORT struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod)
583{
584 char dname[PATH_MAX];
585 struct kmod_list *list = NULL;
586 DIR *d;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200587
588 if (mod == NULL)
589 return NULL;
590 snprintf(dname, sizeof(dname), "/sys/module/%s/holders", mod->name);
591
592 d = opendir(dname);
593 if (d == NULL) {
594 ERR(mod->ctx, "could not open '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200595 dname, strerror(errno));
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200596 return NULL;
597 }
598
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200599 for (;;) {
600 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200601 struct kmod_module *holder;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200602 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200603 int err;
604
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200605 err = readdir_r(d, &de, &entp);
606 if (err != 0) {
607 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
608 mod->name, strerror(-err));
609 goto fail;
610 }
611
612 if (entp == NULL)
613 break;
614
615 if (de.d_name[0] == '.') {
616 if (de.d_name[1] == '\0' ||
617 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200618 continue;
619 }
620
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200621 err = kmod_module_new_from_name(mod->ctx, de.d_name, &holder);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200622 if (err < 0) {
623 ERR(mod->ctx, "could not create module for '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200624 de.d_name, strerror(-err));
625 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200626 }
627
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200628 l = kmod_list_append(list, holder);
629 if (l != NULL) {
630 list = l;
631 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200632 ERR(mod->ctx, "out of memory\n");
633 kmod_module_unref(holder);
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200634 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200635 }
636 }
637
638 closedir(d);
639 return list;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200640
641fail:
642 closedir(d);
643 kmod_module_unref_list(list);
644 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200645}
646
647struct kmod_module_section {
648 unsigned long address;
649 char name[];
650};
651
652static void kmod_module_section_free(struct kmod_module_section *section)
653{
654 free(section);
655}
656
657KMOD_EXPORT struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod)
658{
659 char dname[PATH_MAX];
660 struct kmod_list *list = NULL;
661 DIR *d;
662 int dfd;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200663
664 if (mod == NULL)
665 return NULL;
666 snprintf(dname, sizeof(dname), "/sys/module/%s/sections", mod->name);
667
668 d = opendir(dname);
669 if (d == NULL) {
670 ERR(mod->ctx, "could not open '%s': %s\n",
671 dname, strerror(errno));
672 return NULL;
673 }
674
675 dfd = dirfd(d);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200676
677 for (;;) {
678 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200679 struct kmod_module_section *section;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200680 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200681 unsigned long address;
682 size_t namesz;
683 int fd, err;
684
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200685 err = readdir_r(d, &de, &entp);
686 if (err != 0) {
687 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
688 mod->name, strerror(-err));
689 goto fail;
690 }
691
692 if (de.d_name[0] == '.') {
693 if (de.d_name[1] == '\0' ||
694 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200695 continue;
696 }
697
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200698 fd = openat(dfd, de.d_name, O_RDONLY);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200699 if (fd < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200700 ERR(mod->ctx, "could not open '%s/%s': %m\n",
701 dname, de.d_name);
702 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200703 }
704
705 err = read_str_ulong(fd, &address, 16);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200706 close(fd);
707
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200708 if (err < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200709 ERR(mod->ctx, "could not read long from '%s/%s': %m\n",
710 dname, de.d_name);
711 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200712 }
713
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200714 namesz = strlen(de.d_name) + 1;
715 section = malloc(sizeof(*section) + namesz);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200716
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200717 if (section == NULL) {
718 ERR(mod->ctx, "out of memory\n");
719 goto fail;
720 }
721
722 section->address = address;
723 memcpy(section->name, de.d_name, namesz);
724
725 l = kmod_list_append(list, section);
726 if (l != NULL) {
727 list = l;
728 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200729 ERR(mod->ctx, "out of memory\n");
730 free(section);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200731 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200732 }
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200733 }
734
735 closedir(d);
736 return list;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200737
738fail:
739 closedir(d);
740 kmod_module_unref_list(list);
741 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200742}
743
744KMOD_EXPORT const char *kmod_module_section_get_name(const struct kmod_list *entry)
745{
746 struct kmod_module_section *section;
747 if (entry == NULL)
748 return NULL;
749 section = entry->data;
750 return section->name;
751}
752
753KMOD_EXPORT unsigned long kmod_module_section_get_address(const struct kmod_list *entry)
754{
755 struct kmod_module_section *section;
756 if (entry == NULL)
757 return (unsigned long)-1;
758 section = entry->data;
759 return section->address;
760}
761
762KMOD_EXPORT void kmod_module_section_free_list(struct kmod_list *list)
763{
764 while (list) {
765 kmod_module_section_free(list->data);
766 list = kmod_list_remove(list);
767 }
768}