blob: 432f453f713b96fd6dd7926dd09a2d1da892f2be [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 Marchi671d4892011-12-05 20:23:05 -020085int kmod_module_parse_depline(struct kmod_module *mod, char *line)
Lucas De Marchi7636e722011-12-01 17:56:03 -020086{
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
Lucas De Marchi671d4892011-12-05 20:23:05 -020099 *p = '\0';
100 if (mod->path == NULL)
101 mod->path = strdup(line);
102
Lucas De Marchi7636e722011-12-01 17:56:03 -0200103 p++;
104
105 for (p = strtok_r(p, " \t", &saveptr); p != NULL;
106 p = strtok_r(NULL, " \t", &saveptr)) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200107 const char *modname = path_to_modname(p, NULL, NULL);
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200108 struct kmod_module *depmod;
Lucas De Marchi7636e722011-12-01 17:56:03 -0200109
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200110 err = kmod_module_new_from_name(ctx, modname, &depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200111 if (err < 0) {
112 ERR(ctx, "ctx=%p modname=%s error=%s\n",
113 ctx, modname, strerror(-err));
114 goto fail;
115 }
116
117 DBG(ctx, "add dep: %s\n", modname);
118
Lucas De Marchi1fc1c9a2011-12-02 10:00:03 -0200119 list = kmod_list_append(list, depmod);
Lucas De Marchi7636e722011-12-01 17:56:03 -0200120 n++;
121 }
122
123 DBG(ctx, "%d dependencies for %s\n", n, mod->name);
124
125 mod->dep = list;
126 return n;
127
128fail:
129 kmod_module_unref_list(list);
130 mod->init.dep = false;
131 return err;
132}
133
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200134KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx,
135 const char *name,
136 struct kmod_module **mod)
137{
138 struct kmod_module *m;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200139 size_t namelen;
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200140 char name_norm[NAME_MAX];
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200141
142 if (ctx == NULL || name == NULL)
143 return -ENOENT;
144
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200145 path_to_modname(name, name_norm, &namelen);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200146
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200147 m = kmod_pool_get_module(ctx, name_norm);
148 if (m != NULL) {
149 *mod = kmod_module_ref(m);
150 return 0;
151 }
152
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200153 m = calloc(1, sizeof(*m) + namelen + 1);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200154 if (m == NULL) {
155 free(m);
156 return -ENOMEM;
157 }
158
159 m->ctx = kmod_ref(ctx);
Lucas De Marchi4f2bb7c2011-12-06 02:46:22 -0200160 memcpy(m->name, name_norm, namelen + 1);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200161 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200162
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200163 kmod_pool_add_module(ctx, m);
164
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200165 *mod = m;
166
167 return 0;
168}
169
170KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
171 const char *path,
172 struct kmod_module **mod)
173{
174 struct kmod_module *m;
175 int err;
176 struct stat st;
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200177 char name[NAME_MAX];
178 size_t namelen;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200179
180 if (ctx == NULL || path == NULL)
181 return -ENOENT;
182
183 err = stat(path, &st);
184 if (err < 0)
185 return -errno;
186
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200187 path_to_modname(path, name, &namelen);
188
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200189 m = kmod_pool_get_module(ctx, name);
190 if (m != NULL) {
191 *mod = kmod_module_ref(m);
192 return 0;
193 }
194
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200195 m = calloc(1, sizeof(*m) + namelen + 1);
196 if (m == NULL)
197 return -errno;
198
199 m->path = strdup(path);
200 if (m->path == NULL) {
201 err = -errno;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200202 free(m);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200203 return err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200204 }
205
206 m->ctx = kmod_ref(ctx);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200207 memcpy(m->name, name, namelen);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200208 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200209
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200210 kmod_pool_add_module(ctx, m);
211
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200212 *mod = m;
213
214 return 0;
215}
216
217KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
218{
219 if (mod == NULL)
220 return NULL;
221
222 if (--mod->refcount > 0)
223 return mod;
224
225 DBG(mod->ctx, "kmod_module %p released\n", mod);
226
Lucas De Marchi7636e722011-12-01 17:56:03 -0200227 kmod_module_unref_list(mod->dep);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200228 kmod_unref(mod->ctx);
229 free((char *) mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200230 free(mod);
231 return NULL;
232}
233
234KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
235{
236 if (mod == NULL)
237 return NULL;
238
239 mod->refcount++;
240
241 return mod;
242}
243
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200244#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
245 do { \
246 if ((_err) < 0) \
247 goto _label_err; \
248 if (*(_list) != NULL) \
249 goto finish; \
250 } while (0)
251
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200252KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
253 const char *alias,
254 struct kmod_list **list)
255{
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200256 int err;
257
258 if (ctx == NULL || alias == NULL)
259 return -ENOENT;
260
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200261 if (list == NULL || *list != NULL) {
262 ERR(ctx, "An empty list is needed to create lookup\n");
263 return -ENOSYS;
264 }
265
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200266 /* Aliases from config file override all the others */
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200267 err = kmod_lookup_alias_from_config(ctx, alias, list);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200268 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200269
Lucas De Marchi64700e42011-12-01 15:57:53 -0200270 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
271 CHECK_ERR_AND_FINISH(err, fail, list, finish);
272
Lucas De Marchi9ba6f572011-11-30 20:31:45 -0200273 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
274 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200275
Lucas De Marchi49e61ca2011-12-01 16:27:04 -0200276 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
277 CHECK_ERR_AND_FINISH(err, fail, list, finish);
278
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200279finish:
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200280
281 return err;
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200282fail:
283 kmod_module_unref_list(*list);
284 *list = NULL;
Lucas De Marchi84f42202011-12-02 10:03:34 -0200285 return err;
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200286}
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200287#undef CHECK_ERR_AND_FINISH
288
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200289
290KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
291{
292 for (; list != NULL; list = kmod_list_remove(list))
293 kmod_module_unref(list->data);
294
295 return 0;
296}
297
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200298KMOD_EXPORT struct kmod_list *kmod_module_get_dependencies(const struct kmod_module *mod)
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200299{
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200300 struct kmod_list *l, *l_new, *list_new = NULL;
301
302 if (mod == NULL)
303 return NULL;
304
Lucas De Marchi671d4892011-12-05 20:23:05 -0200305 if (!mod->init.dep) {
306 /* lazy init */
307 char *line = kmod_search_moddep(mod->ctx, mod->name);
308
309 if (line == NULL)
310 return NULL;
311
312 kmod_module_parse_depline((struct kmod_module *)mod, line);
313 free(line);
314
315 if (!mod->init.dep)
316 return NULL;
317 }
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200318
319 kmod_list_foreach(l, mod->dep) {
320 l_new = kmod_list_append(list_new, kmod_module_ref(l->data));
321 if (l_new == NULL) {
322 kmod_module_unref(l->data);
323 goto fail;
324 }
325
326 list_new = l_new;
327 }
328
329 return list_new;
330
331fail:
332 ERR(mod->ctx, "out of memory\n");
333 kmod_module_unref_list(list_new);
334 return NULL;
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200335}
336
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200337KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *entry)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200338{
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200339 if (entry == NULL)
340 return NULL;
341 return kmod_module_ref(entry->data);
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200342}
343
Gustavo Sverzut Barbieri69f9dd42011-12-04 14:02:30 -0200344KMOD_EXPORT long kmod_module_get_size(const struct kmod_module *mod)
345{
346 // FIXME TODO: this should be available from /sys/module/foo
347 FILE *fp;
348 char line[4096];
349 int lineno = 0;
350 long size = -ENOENT;
351
352 if (mod == NULL)
353 return -ENOENT;
354
355 fp = fopen("/proc/modules", "r");
356 if (fp == NULL) {
357 int err = -errno;
358 ERR(mod->ctx,
359 "could not open /proc/modules: %s\n", strerror(errno));
360 return err;
361 }
362
363 while (fgets(line, sizeof(line), fp)) {
364 char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
365 long value;
366
367 lineno++;
368 if (tok == NULL || strcmp(tok, mod->name) != 0)
369 continue;
370
371 tok = strtok_r(NULL, " \t", &saveptr);
372 if (tok == NULL) {
373 ERR(mod->ctx,
374 "invalid line format at /proc/modules:%d\n", lineno);
375 break;
376 }
377
378 value = strtol(tok, &endptr, 10);
379 if (endptr == tok || *endptr != '\0') {
380 ERR(mod->ctx,
381 "invalid line format at /proc/modules:%d\n", lineno);
382 break;
383 }
384
385 size = value;
386 break;
387 }
388 fclose(fp);
389 return size;
390}
391
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200392KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200393{
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200394 return mod->name;
395}
396
Lucas De Marchic5e7b1f2011-12-05 20:28:13 -0200397/*
398 * Relative paths are relative to dirname. Absolute paths are only used when
399 * user created kmod_module by giving a path
400 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200401KMOD_EXPORT const char *kmod_module_get_path(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200402{
Lucas De Marchic5e7b1f2011-12-05 20:28:13 -0200403 if (!mod->init.dep) {
404 /* lazy init */
405 char *line = kmod_search_moddep(mod->ctx, mod->name);
406
407 if (line == NULL)
408 return NULL;
409
410 kmod_module_parse_depline((struct kmod_module *) mod, line);
411 free(line);
412
413 if (!mod->init.dep)
414 return NULL;
415 }
416
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200417 return mod->path;
418}
419
420
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200421extern long delete_module(const char *name, unsigned int flags);
422
423KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
424 unsigned int flags)
425{
426 int err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200427
428 if (mod == NULL)
429 return -ENOENT;
430
431 /* Filter out other flags */
432 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
433
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200434 err = delete_module(mod->name, flags);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200435 if (err != 0) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200436 ERR(mod->ctx, "Removing '%s': %s\n", mod->name,
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200437 strerror(-err));
438 return err;
439 }
440
441 return 0;
442}
443
444extern long init_module(void *mem, unsigned long len, const char *args);
445
446KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
447 unsigned int flags)
448{
449 int err;
450 void *mmaped_file;
451 struct stat st;
452 int fd;
453 const char *args = "";
454
455 if (mod == NULL)
456 return -ENOENT;
457
458 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200459 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200460 return -ENOSYS;
461 }
462
463 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200464 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200465
466 if ((fd = open(mod->path, O_RDONLY)) < 0) {
467 err = -errno;
468 return err;
469 }
470
Lucas De Marchib418a822011-12-01 23:13:27 -0200471 fstat(fd, &st);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200472
473 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
474 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
475 close(fd);
476 return -errno;
477 }
478
479 err = init_module(mmaped_file, st.st_size, args);
480 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200481 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200482
483 munmap(mmaped_file, st.st_size);
484 close(fd);
485
486 return err;
487}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200488
489KMOD_EXPORT const char *kmod_module_initstate_str(enum kmod_module_initstate state)
490{
491 switch (state) {
492 case KMOD_MODULE_BUILTIN:
493 return "builtin";
494 case KMOD_MODULE_LIVE:
495 return "live";
496 case KMOD_MODULE_COMING:
497 return "coming";
498 case KMOD_MODULE_GOING:
499 return "going";
500 default:
501 return NULL;
502 }
503}
504
505KMOD_EXPORT int kmod_module_get_initstate(const struct kmod_module *mod)
506{
507 char path[PATH_MAX], buf[32];
508 int fd, err, pathlen;
509
510 pathlen = snprintf(path, sizeof(path),
511 "/sys/module/%s/initstate", mod->name);
512 fd = open(path, O_RDONLY);
513 if (fd < 0) {
514 err = -errno;
515
516 if (pathlen > (int)sizeof("/initstate") - 1) {
517 struct stat st;
518 path[pathlen - (sizeof("/initstate") - 1)] = '\0';
519 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
520 return KMOD_MODULE_BUILTIN;
521 }
522
523 ERR(mod->ctx, "could not open '%s': %s\n",
524 path, strerror(-err));
525 return err;
526 }
527
528 err = read_str_safe(fd, buf, sizeof(buf));
529 close(fd);
530 if (err < 0) {
531 ERR(mod->ctx, "could not read from '%s': %s\n",
532 path, strerror(-err));
533 return err;
534 }
535
536 if (strcmp(buf, "live\n") == 0)
537 return KMOD_MODULE_LIVE;
538 else if (strcmp(buf, "coming\n") == 0)
539 return KMOD_MODULE_COMING;
540 else if (strcmp(buf, "going\n") == 0)
541 return KMOD_MODULE_GOING;
542
543 ERR(mod->ctx, "unknown %s: '%s'\n", path, buf);
544 return -EINVAL;
545}
546
547KMOD_EXPORT int kmod_module_get_refcnt(const struct kmod_module *mod)
548{
549 char path[PATH_MAX];
550 long refcnt;
551 int fd, err;
552
553 snprintf(path, sizeof(path), "/sys/module/%s/refcnt", mod->name);
554 fd = open(path, O_RDONLY);
555 if (fd < 0) {
556 err = -errno;
557 ERR(mod->ctx, "could not open '%s': %s\n",
558 path, strerror(errno));
559 return err;
560 }
561
562 err = read_str_long(fd, &refcnt, 10);
563 close(fd);
564 if (err < 0) {
565 ERR(mod->ctx, "could not read integer from '%s': '%s'\n",
566 path, strerror(-err));
567 return err;
568 }
569
570 return (int)refcnt;
571}
572
573KMOD_EXPORT struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod)
574{
575 char dname[PATH_MAX];
576 struct kmod_list *list = NULL;
577 DIR *d;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200578
579 if (mod == NULL)
580 return NULL;
581 snprintf(dname, sizeof(dname), "/sys/module/%s/holders", mod->name);
582
583 d = opendir(dname);
584 if (d == NULL) {
585 ERR(mod->ctx, "could not open '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200586 dname, strerror(errno));
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200587 return NULL;
588 }
589
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200590 for (;;) {
591 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200592 struct kmod_module *holder;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200593 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200594 int err;
595
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200596 err = readdir_r(d, &de, &entp);
597 if (err != 0) {
598 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
599 mod->name, strerror(-err));
600 goto fail;
601 }
602
603 if (entp == NULL)
604 break;
605
606 if (de.d_name[0] == '.') {
607 if (de.d_name[1] == '\0' ||
608 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200609 continue;
610 }
611
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200612 err = kmod_module_new_from_name(mod->ctx, de.d_name, &holder);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200613 if (err < 0) {
614 ERR(mod->ctx, "could not create module for '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200615 de.d_name, strerror(-err));
616 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200617 }
618
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200619 l = kmod_list_append(list, holder);
620 if (l != NULL) {
621 list = l;
622 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200623 ERR(mod->ctx, "out of memory\n");
624 kmod_module_unref(holder);
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200625 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200626 }
627 }
628
629 closedir(d);
630 return list;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200631
632fail:
633 closedir(d);
634 kmod_module_unref_list(list);
635 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200636}
637
638struct kmod_module_section {
639 unsigned long address;
640 char name[];
641};
642
643static void kmod_module_section_free(struct kmod_module_section *section)
644{
645 free(section);
646}
647
648KMOD_EXPORT struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod)
649{
650 char dname[PATH_MAX];
651 struct kmod_list *list = NULL;
652 DIR *d;
653 int dfd;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200654
655 if (mod == NULL)
656 return NULL;
657 snprintf(dname, sizeof(dname), "/sys/module/%s/sections", mod->name);
658
659 d = opendir(dname);
660 if (d == NULL) {
661 ERR(mod->ctx, "could not open '%s': %s\n",
662 dname, strerror(errno));
663 return NULL;
664 }
665
666 dfd = dirfd(d);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200667
668 for (;;) {
669 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200670 struct kmod_module_section *section;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200671 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200672 unsigned long address;
673 size_t namesz;
674 int fd, err;
675
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200676 err = readdir_r(d, &de, &entp);
677 if (err != 0) {
678 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
679 mod->name, strerror(-err));
680 goto fail;
681 }
682
683 if (de.d_name[0] == '.') {
684 if (de.d_name[1] == '\0' ||
685 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200686 continue;
687 }
688
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200689 fd = openat(dfd, de.d_name, O_RDONLY);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200690 if (fd < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200691 ERR(mod->ctx, "could not open '%s/%s': %m\n",
692 dname, de.d_name);
693 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200694 }
695
696 err = read_str_ulong(fd, &address, 16);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200697 close(fd);
698
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200699 if (err < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200700 ERR(mod->ctx, "could not read long from '%s/%s': %m\n",
701 dname, de.d_name);
702 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200703 }
704
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200705 namesz = strlen(de.d_name) + 1;
706 section = malloc(sizeof(*section) + namesz);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200707
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200708 if (section == NULL) {
709 ERR(mod->ctx, "out of memory\n");
710 goto fail;
711 }
712
713 section->address = address;
714 memcpy(section->name, de.d_name, namesz);
715
716 l = kmod_list_append(list, section);
717 if (l != NULL) {
718 list = l;
719 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200720 ERR(mod->ctx, "out of memory\n");
721 free(section);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200722 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200723 }
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200724 }
725
726 closedir(d);
727 return list;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200728
729fail:
730 closedir(d);
731 kmod_module_unref_list(list);
732 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200733}
734
735KMOD_EXPORT const char *kmod_module_section_get_name(const struct kmod_list *entry)
736{
737 struct kmod_module_section *section;
738 if (entry == NULL)
739 return NULL;
740 section = entry->data;
741 return section->name;
742}
743
744KMOD_EXPORT unsigned long kmod_module_section_get_address(const struct kmod_list *entry)
745{
746 struct kmod_module_section *section;
747 if (entry == NULL)
748 return (unsigned long)-1;
749 section = entry->data;
750 return section->address;
751}
752
753KMOD_EXPORT void kmod_module_section_free_list(struct kmod_list *list)
754{
755 while (list) {
756 kmod_module_section_free(list->data);
757 list = kmod_list_remove(list);
758 }
759}