blob: 48548868ce426304eb9c8fd9040f26535210d88e [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 Marchid753b8c2011-12-05 18:14:51 -020056static char *path_to_modname(const char *path, char buf[NAME_MAX], size_t *len)
Lucas De Marchi8f788d52011-11-25 01:22:56 -020057{
58 char *modname;
59 char *c;
Lucas De Marchid753b8c2011-12-05 18:14:51 -020060 size_t s;
Lucas De Marchi8f788d52011-11-25 01:22:56 -020061
62 modname = basename(path);
63 if (modname == NULL || modname[0] == '\0')
64 return NULL;
65
Lucas De Marchid753b8c2011-12-05 18:14:51 -020066 if (buf) {
67 buf[NAME_MAX] = '\0';
68 modname = strncpy(buf, modname, NAME_MAX - 1);
Lucas De Marchi8f788d52011-11-25 01:22:56 -020069 }
70
Lucas De Marchid753b8c2011-12-05 18:14:51 -020071 for (c = modname, s = 0; *c != '\0' && *c != '.'; c++) {
72 if (*c == '-')
73 *c = '_';
74 s++;
75 }
76
77 if (len)
78 *len = s;
79
Lucas De Marchi8f788d52011-11-25 01:22:56 -020080 *c = '\0';
Lucas De Marchid753b8c2011-12-05 18:14:51 -020081
Lucas De Marchi8f788d52011-11-25 01:22:56 -020082 return modname;
83}
84
Lucas De Marchi7636e722011-12-01 17:56:03 -020085int kmod_module_parse_dep(struct kmod_module *mod, char *line)
86{
87 struct kmod_ctx *ctx = mod->ctx;
88 struct kmod_list *list = NULL;
89 char *p, *saveptr;
90 int err, n = 0;
91
92 assert(!mod->init.dep && mod->dep == NULL);
93 mod->init.dep = true;
94
95 p = strchr(line, ':');
96 if (p == NULL)
97 return 0;
98
99 p++;
100
101 for (p = strtok_r(p, " \t", &saveptr); p != NULL;
102 p = strtok_r(NULL, " \t", &saveptr)) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200103 const char *modname = path_to_modname(p, NULL, NULL);
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200104 struct kmod_module *depmod;
Lucas De Marchi7636e722011-12-01 17:56:03 -0200105
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200106 err = kmod_module_new_from_name(ctx, modname, &depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200107 if (err < 0) {
108 ERR(ctx, "ctx=%p modname=%s error=%s\n",
109 ctx, modname, strerror(-err));
110 goto fail;
111 }
112
113 DBG(ctx, "add dep: %s\n", modname);
114
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200115 list = kmod_list_append(list, depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200116 n++;
117 }
118
119 DBG(ctx, "%d dependencies for %s\n", n, mod->name);
120
121 mod->dep = list;
122 return n;
123
124fail:
125 kmod_module_unref_list(list);
126 mod->init.dep = false;
127 return err;
128}
129
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200130KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
131 const char *name,
132 struct kmod_module **mod)
133{
134 struct kmod_module *m;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200135 size_t namelen;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200136
137 if (ctx == NULL || name == NULL)
138 return -ENOENT;
139
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200140 namelen = strlen(name) + 1;
141
142 m = calloc(1, sizeof(*m) + namelen);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200143 if (m == NULL) {
144 free(m);
145 return -ENOMEM;
146 }
147
148 m->ctx = kmod_ref(ctx);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200149 memcpy(m->name, name, namelen);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200150 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200151
152 *mod = m;
153
154 return 0;
155}
156
157KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
158 const char *path,
159 struct kmod_module **mod)
160{
161 struct kmod_module *m;
162 int err;
163 struct stat st;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200164 char name[NAME_MAX];
165 size_t namelen;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200166
167 if (ctx == NULL || path == NULL)
168 return -ENOENT;
169
170 err = stat(path, &st);
171 if (err < 0)
172 return -errno;
173
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200174 path_to_modname(path, name, &namelen);
175
176 m = calloc(1, sizeof(*m) + namelen + 1);
177 if (m == NULL)
178 return -errno;
179
180 m->path = strdup(path);
181 if (m->path == NULL) {
182 err = -errno;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200183 free(m);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200184 return err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200185 }
186
187 m->ctx = kmod_ref(ctx);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200188 memcpy(m->name, name, namelen);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200189 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200190
191 *mod = m;
192
193 return 0;
194}
195
196KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
197{
198 if (mod == NULL)
199 return NULL;
200
201 if (--mod->refcount > 0)
202 return mod;
203
204 DBG(mod->ctx, "kmod_module %p released\n", mod);
205
Lucas De Marchi7636e722011-12-01 17:56:03 -0200206 kmod_module_unref_list(mod->dep);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200207 kmod_unref(mod->ctx);
208 free((char *) mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200209 free(mod);
210 return NULL;
211}
212
213KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
214{
215 if (mod == NULL)
216 return NULL;
217
218 mod->refcount++;
219
220 return mod;
221}
222
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200223#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
224 do { \
225 if ((_err) < 0) \
226 goto _label_err; \
227 if (*(_list) != NULL) \
228 goto finish; \
229 } while (0)
230
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200231KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
232 const char *alias,
233 struct kmod_list **list)
234{
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200235 int err;
236
237 if (ctx == NULL || alias == NULL)
238 return -ENOENT;
239
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200240 if (list == NULL || *list != NULL) {
241 ERR(ctx, "An empty list is needed to create lookup\n");
242 return -ENOSYS;
243 }
244
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200245 /* Aliases from config file override all the others */
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200246 err = kmod_lookup_alias_from_config(ctx, alias, list);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200247 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200248
Lucas De Marchi64700e42011-12-01 15:57:53 -0200249 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
250 CHECK_ERR_AND_FINISH(err, fail, list, finish);
251
Lucas De Marchi9ba6f572011-11-30 20:31:45 -0200252 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
253 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200254
Lucas De Marchi49e61ca2011-12-01 16:27:04 -0200255 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
256 CHECK_ERR_AND_FINISH(err, fail, list, finish);
257
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200258finish:
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200259
260 return err;
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200261fail:
262 kmod_module_unref_list(*list);
263 *list = NULL;
Lucas De Marchi84f42202011-12-02 10:03:34 -0200264 return err;
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200265}
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200266#undef CHECK_ERR_AND_FINISH
267
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200268
269KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
270{
271 for (; list != NULL; list = kmod_list_remove(list))
272 kmod_module_unref(list->data);
273
274 return 0;
275}
276
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200277/*
278 * We don't increase the refcount. Maybe we should.
279 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200280KMOD_EXPORT struct kmod_list *kmod_module_get_dependency(const struct kmod_module *mod)
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200281{
282 // FIXME calculate dependency if it's not initialized
283 return mod->dep;
284}
285
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200286KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *entry)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200287{
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200288 if (entry == NULL)
289 return NULL;
290 return kmod_module_ref(entry->data);
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200291}
292
Gustavo Sverzut Barbieri69f9dd42011-12-04 14:02:30 -0200293KMOD_EXPORT long kmod_module_get_size(const struct kmod_module *mod)
294{
295 // FIXME TODO: this should be available from /sys/module/foo
296 FILE *fp;
297 char line[4096];
298 int lineno = 0;
299 long size = -ENOENT;
300
301 if (mod == NULL)
302 return -ENOENT;
303
304 fp = fopen("/proc/modules", "r");
305 if (fp == NULL) {
306 int err = -errno;
307 ERR(mod->ctx,
308 "could not open /proc/modules: %s\n", strerror(errno));
309 return err;
310 }
311
312 while (fgets(line, sizeof(line), fp)) {
313 char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
314 long value;
315
316 lineno++;
317 if (tok == NULL || strcmp(tok, mod->name) != 0)
318 continue;
319
320 tok = strtok_r(NULL, " \t", &saveptr);
321 if (tok == NULL) {
322 ERR(mod->ctx,
323 "invalid line format at /proc/modules:%d\n", lineno);
324 break;
325 }
326
327 value = strtol(tok, &endptr, 10);
328 if (endptr == tok || *endptr != '\0') {
329 ERR(mod->ctx,
330 "invalid line format at /proc/modules:%d\n", lineno);
331 break;
332 }
333
334 size = value;
335 break;
336 }
337 fclose(fp);
338 return size;
339}
340
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200341KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200342{
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200343 return mod->name;
344}
345
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200346KMOD_EXPORT const char *kmod_module_get_path(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200347{
348 // FIXME calculate path if path == NULL
349 return mod->path;
350}
351
352
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200353extern long delete_module(const char *name, unsigned int flags);
354
355KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
356 unsigned int flags)
357{
358 int err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200359
360 if (mod == NULL)
361 return -ENOENT;
362
363 /* Filter out other flags */
364 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
365
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200366 err = delete_module(mod->name, flags);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200367 if (err != 0) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200368 ERR(mod->ctx, "Removing '%s': %s\n", mod->name,
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200369 strerror(-err));
370 return err;
371 }
372
373 return 0;
374}
375
376extern long init_module(void *mem, unsigned long len, const char *args);
377
378KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
379 unsigned int flags)
380{
381 int err;
382 void *mmaped_file;
383 struct stat st;
384 int fd;
385 const char *args = "";
386
387 if (mod == NULL)
388 return -ENOENT;
389
390 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200391 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200392 return -ENOSYS;
393 }
394
395 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200396 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200397
398 if ((fd = open(mod->path, O_RDONLY)) < 0) {
399 err = -errno;
400 return err;
401 }
402
Lucas De Marchib418a822011-12-01 23:13:27 -0200403 fstat(fd, &st);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200404
405 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
406 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
407 close(fd);
408 return -errno;
409 }
410
411 err = init_module(mmaped_file, st.st_size, args);
412 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200413 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200414
415 munmap(mmaped_file, st.st_size);
416 close(fd);
417
418 return err;
419}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200420
421KMOD_EXPORT const char *kmod_module_initstate_str(enum kmod_module_initstate state)
422{
423 switch (state) {
424 case KMOD_MODULE_BUILTIN:
425 return "builtin";
426 case KMOD_MODULE_LIVE:
427 return "live";
428 case KMOD_MODULE_COMING:
429 return "coming";
430 case KMOD_MODULE_GOING:
431 return "going";
432 default:
433 return NULL;
434 }
435}
436
437KMOD_EXPORT int kmod_module_get_initstate(const struct kmod_module *mod)
438{
439 char path[PATH_MAX], buf[32];
440 int fd, err, pathlen;
441
442 pathlen = snprintf(path, sizeof(path),
443 "/sys/module/%s/initstate", mod->name);
444 fd = open(path, O_RDONLY);
445 if (fd < 0) {
446 err = -errno;
447
448 if (pathlen > (int)sizeof("/initstate") - 1) {
449 struct stat st;
450 path[pathlen - (sizeof("/initstate") - 1)] = '\0';
451 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
452 return KMOD_MODULE_BUILTIN;
453 }
454
455 ERR(mod->ctx, "could not open '%s': %s\n",
456 path, strerror(-err));
457 return err;
458 }
459
460 err = read_str_safe(fd, buf, sizeof(buf));
461 close(fd);
462 if (err < 0) {
463 ERR(mod->ctx, "could not read from '%s': %s\n",
464 path, strerror(-err));
465 return err;
466 }
467
468 if (strcmp(buf, "live\n") == 0)
469 return KMOD_MODULE_LIVE;
470 else if (strcmp(buf, "coming\n") == 0)
471 return KMOD_MODULE_COMING;
472 else if (strcmp(buf, "going\n") == 0)
473 return KMOD_MODULE_GOING;
474
475 ERR(mod->ctx, "unknown %s: '%s'\n", path, buf);
476 return -EINVAL;
477}
478
479KMOD_EXPORT int kmod_module_get_refcnt(const struct kmod_module *mod)
480{
481 char path[PATH_MAX];
482 long refcnt;
483 int fd, err;
484
485 snprintf(path, sizeof(path), "/sys/module/%s/refcnt", mod->name);
486 fd = open(path, O_RDONLY);
487 if (fd < 0) {
488 err = -errno;
489 ERR(mod->ctx, "could not open '%s': %s\n",
490 path, strerror(errno));
491 return err;
492 }
493
494 err = read_str_long(fd, &refcnt, 10);
495 close(fd);
496 if (err < 0) {
497 ERR(mod->ctx, "could not read integer from '%s': '%s'\n",
498 path, strerror(-err));
499 return err;
500 }
501
502 return (int)refcnt;
503}
504
505KMOD_EXPORT struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod)
506{
507 char dname[PATH_MAX];
508 struct kmod_list *list = NULL;
509 DIR *d;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200510
511 if (mod == NULL)
512 return NULL;
513 snprintf(dname, sizeof(dname), "/sys/module/%s/holders", mod->name);
514
515 d = opendir(dname);
516 if (d == NULL) {
517 ERR(mod->ctx, "could not open '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200518 dname, strerror(errno));
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200519 return NULL;
520 }
521
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200522 for (;;) {
523 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200524 struct kmod_module *holder;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200525 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200526 int err;
527
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200528 err = readdir_r(d, &de, &entp);
529 if (err != 0) {
530 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
531 mod->name, strerror(-err));
532 goto fail;
533 }
534
535 if (entp == NULL)
536 break;
537
538 if (de.d_name[0] == '.') {
539 if (de.d_name[1] == '\0' ||
540 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200541 continue;
542 }
543
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200544 err = kmod_module_new_from_name(mod->ctx, de.d_name, &holder);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200545 if (err < 0) {
546 ERR(mod->ctx, "could not create module for '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200547 de.d_name, strerror(-err));
548 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200549 }
550
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200551 l = kmod_list_append(list, holder);
552 if (l != NULL) {
553 list = l;
554 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200555 ERR(mod->ctx, "out of memory\n");
556 kmod_module_unref(holder);
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200557 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200558 }
559 }
560
561 closedir(d);
562 return list;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200563
564fail:
565 closedir(d);
566 kmod_module_unref_list(list);
567 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200568}
569
570struct kmod_module_section {
571 unsigned long address;
572 char name[];
573};
574
575static void kmod_module_section_free(struct kmod_module_section *section)
576{
577 free(section);
578}
579
580KMOD_EXPORT struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod)
581{
582 char dname[PATH_MAX];
583 struct kmod_list *list = NULL;
584 DIR *d;
585 int dfd;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200586
587 if (mod == NULL)
588 return NULL;
589 snprintf(dname, sizeof(dname), "/sys/module/%s/sections", mod->name);
590
591 d = opendir(dname);
592 if (d == NULL) {
593 ERR(mod->ctx, "could not open '%s': %s\n",
594 dname, strerror(errno));
595 return NULL;
596 }
597
598 dfd = dirfd(d);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200599
600 for (;;) {
601 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200602 struct kmod_module_section *section;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200603 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200604 unsigned long address;
605 size_t namesz;
606 int fd, err;
607
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200608 err = readdir_r(d, &de, &entp);
609 if (err != 0) {
610 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
611 mod->name, strerror(-err));
612 goto fail;
613 }
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 Marchi40923bd2011-12-05 13:40:16 -0200621 fd = openat(dfd, de.d_name, O_RDONLY);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200622 if (fd < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200623 ERR(mod->ctx, "could not open '%s/%s': %m\n",
624 dname, de.d_name);
625 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200626 }
627
628 err = read_str_ulong(fd, &address, 16);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200629 close(fd);
630
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200631 if (err < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200632 ERR(mod->ctx, "could not read long from '%s/%s': %m\n",
633 dname, de.d_name);
634 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200635 }
636
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200637 namesz = strlen(de.d_name) + 1;
638 section = malloc(sizeof(*section) + namesz);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200639
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200640 if (section == NULL) {
641 ERR(mod->ctx, "out of memory\n");
642 goto fail;
643 }
644
645 section->address = address;
646 memcpy(section->name, de.d_name, namesz);
647
648 l = kmod_list_append(list, section);
649 if (l != NULL) {
650 list = l;
651 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200652 ERR(mod->ctx, "out of memory\n");
653 free(section);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200654 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200655 }
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200656 }
657
658 closedir(d);
659 return list;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200660
661fail:
662 closedir(d);
663 kmod_module_unref_list(list);
664 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200665}
666
667KMOD_EXPORT const char *kmod_module_section_get_name(const struct kmod_list *entry)
668{
669 struct kmod_module_section *section;
670 if (entry == NULL)
671 return NULL;
672 section = entry->data;
673 return section->name;
674}
675
676KMOD_EXPORT unsigned long kmod_module_section_get_address(const struct kmod_list *entry)
677{
678 struct kmod_module_section *section;
679 if (entry == NULL)
680 return (unsigned long)-1;
681 section = entry->data;
682 return section->address;
683}
684
685KMOD_EXPORT void kmod_module_section_free_list(struct kmod_list *list)
686{
687 while (list) {
688 kmod_module_section_free(list->data);
689 list = kmod_list_remove(list);
690 }
691}