blob: e7a71503c00dd53c8e2329a7bc9f0f14d86a3b8a [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];
185 size_t namelen;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200186
187 if (ctx == NULL || path == NULL)
188 return -ENOENT;
189
190 err = stat(path, &st);
191 if (err < 0)
192 return -errno;
193
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200194 path_to_modname(path, name, &namelen);
195
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200196 m = kmod_pool_get_module(ctx, name);
197 if (m != NULL) {
198 *mod = kmod_module_ref(m);
199 return 0;
200 }
201
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200202 m = calloc(1, sizeof(*m) + namelen + 1);
203 if (m == NULL)
204 return -errno;
205
206 m->path = strdup(path);
207 if (m->path == NULL) {
208 err = -errno;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200209 free(m);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200210 return err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200211 }
212
213 m->ctx = kmod_ref(ctx);
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200214 memcpy(m->name, name, namelen);
Gustavo Sverzut Barbieri87ca03b2011-12-04 12:34:02 -0200215 m->refcount = 1;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200216
Lucas De Marchifd186ae2011-12-06 03:38:37 -0200217 kmod_pool_add_module(ctx, m);
218
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200219 *mod = m;
220
221 return 0;
222}
223
224KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
225{
226 if (mod == NULL)
227 return NULL;
228
229 if (--mod->refcount > 0)
230 return mod;
231
232 DBG(mod->ctx, "kmod_module %p released\n", mod);
233
Lucas De Marchi7636e722011-12-01 17:56:03 -0200234 kmod_module_unref_list(mod->dep);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200235 kmod_unref(mod->ctx);
236 free((char *) mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200237 free(mod);
238 return NULL;
239}
240
241KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
242{
243 if (mod == NULL)
244 return NULL;
245
246 mod->refcount++;
247
248 return mod;
249}
250
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200251#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \
252 do { \
253 if ((_err) < 0) \
254 goto _label_err; \
255 if (*(_list) != NULL) \
256 goto finish; \
257 } while (0)
258
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200259KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
260 const char *alias,
261 struct kmod_list **list)
262{
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200263 int err;
264
265 if (ctx == NULL || alias == NULL)
266 return -ENOENT;
267
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200268 if (list == NULL || *list != NULL) {
269 ERR(ctx, "An empty list is needed to create lookup\n");
270 return -ENOSYS;
271 }
272
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200273 /* Aliases from config file override all the others */
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200274 err = kmod_lookup_alias_from_config(ctx, alias, list);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200275 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200276
Lucas De Marchi64700e42011-12-01 15:57:53 -0200277 err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
278 CHECK_ERR_AND_FINISH(err, fail, list, finish);
279
Lucas De Marchi9ba6f572011-11-30 20:31:45 -0200280 err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
281 CHECK_ERR_AND_FINISH(err, fail, list, finish);
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200282
Lucas De Marchi49e61ca2011-12-01 16:27:04 -0200283 err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
284 CHECK_ERR_AND_FINISH(err, fail, list, finish);
285
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200286finish:
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200287
288 return err;
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200289fail:
290 kmod_module_unref_list(*list);
291 *list = NULL;
Lucas De Marchi84f42202011-12-02 10:03:34 -0200292 return err;
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200293}
Lucas De Marchib14dcfd2011-11-30 20:29:51 -0200294#undef CHECK_ERR_AND_FINISH
295
Lucas De Marchi7f3eb0c2011-11-30 19:03:41 -0200296
297KMOD_EXPORT int kmod_module_unref_list(struct kmod_list *list)
298{
299 for (; list != NULL; list = kmod_list_remove(list))
300 kmod_module_unref(list->data);
301
302 return 0;
303}
304
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200305KMOD_EXPORT struct kmod_list *kmod_module_get_dependencies(const struct kmod_module *mod)
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200306{
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200307 struct kmod_list *l, *l_new, *list_new = NULL;
308
309 if (mod == NULL)
310 return NULL;
311
Lucas De Marchi671d4892011-12-05 20:23:05 -0200312 if (!mod->init.dep) {
313 /* lazy init */
314 char *line = kmod_search_moddep(mod->ctx, mod->name);
315
316 if (line == NULL)
317 return NULL;
318
319 kmod_module_parse_depline((struct kmod_module *)mod, line);
320 free(line);
321
322 if (!mod->init.dep)
323 return NULL;
324 }
Lucas De Marchif1cd7992011-12-05 19:40:45 -0200325
326 kmod_list_foreach(l, mod->dep) {
327 l_new = kmod_list_append(list_new, kmod_module_ref(l->data));
328 if (l_new == NULL) {
329 kmod_module_unref(l->data);
330 goto fail;
331 }
332
333 list_new = l_new;
334 }
335
336 return list_new;
337
338fail:
339 ERR(mod->ctx, "out of memory\n");
340 kmod_module_unref_list(list_new);
341 return NULL;
Lucas De Marchi0835fc32011-12-01 20:06:08 -0200342}
343
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200344KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *entry)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200345{
Gustavo Sverzut Barbieriad4d1ae2011-12-04 13:14:11 -0200346 if (entry == NULL)
347 return NULL;
348 return kmod_module_ref(entry->data);
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200349}
350
Gustavo Sverzut Barbieri69f9dd42011-12-04 14:02:30 -0200351KMOD_EXPORT long kmod_module_get_size(const struct kmod_module *mod)
352{
353 // FIXME TODO: this should be available from /sys/module/foo
354 FILE *fp;
355 char line[4096];
356 int lineno = 0;
357 long size = -ENOENT;
358
359 if (mod == NULL)
360 return -ENOENT;
361
362 fp = fopen("/proc/modules", "r");
363 if (fp == NULL) {
364 int err = -errno;
365 ERR(mod->ctx,
366 "could not open /proc/modules: %s\n", strerror(errno));
367 return err;
368 }
369
370 while (fgets(line, sizeof(line), fp)) {
371 char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
372 long value;
373
374 lineno++;
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200375 if (tok == NULL || !streq(tok, mod->name))
Gustavo Sverzut Barbieri69f9dd42011-12-04 14:02:30 -0200376 continue;
377
378 tok = strtok_r(NULL, " \t", &saveptr);
379 if (tok == NULL) {
380 ERR(mod->ctx,
381 "invalid line format at /proc/modules:%d\n", lineno);
382 break;
383 }
384
385 value = strtol(tok, &endptr, 10);
386 if (endptr == tok || *endptr != '\0') {
387 ERR(mod->ctx,
388 "invalid line format at /proc/modules:%d\n", lineno);
389 break;
390 }
391
392 size = value;
393 break;
394 }
395 fclose(fp);
396 return size;
397}
398
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200399KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200400{
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200401 return mod->name;
402}
403
Lucas De Marchic5e7b1f2011-12-05 20:28:13 -0200404/*
405 * Relative paths are relative to dirname. Absolute paths are only used when
406 * user created kmod_module by giving a path
407 */
Gustavo Sverzut Barbieri1ce08a52011-12-02 20:24:07 -0200408KMOD_EXPORT const char *kmod_module_get_path(const struct kmod_module *mod)
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200409{
Lucas De Marchic5e7b1f2011-12-05 20:28:13 -0200410 if (!mod->init.dep) {
411 /* lazy init */
412 char *line = kmod_search_moddep(mod->ctx, mod->name);
413
414 if (line == NULL)
415 return NULL;
416
417 kmod_module_parse_depline((struct kmod_module *) mod, line);
418 free(line);
419
420 if (!mod->init.dep)
421 return NULL;
422 }
423
Lucas De Marchi6e869df2011-11-30 19:01:01 -0200424 return mod->path;
425}
426
427
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200428extern long delete_module(const char *name, unsigned int flags);
429
430KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod,
431 unsigned int flags)
432{
433 int err;
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200434
435 if (mod == NULL)
436 return -ENOENT;
437
438 /* Filter out other flags */
439 flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
440
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200441 err = delete_module(mod->name, flags);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200442 if (err != 0) {
Lucas De Marchid753b8c2011-12-05 18:14:51 -0200443 ERR(mod->ctx, "Removing '%s': %s\n", mod->name,
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200444 strerror(-err));
445 return err;
446 }
447
448 return 0;
449}
450
451extern long init_module(void *mem, unsigned long len, const char *args);
452
453KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
454 unsigned int flags)
455{
456 int err;
457 void *mmaped_file;
458 struct stat st;
459 int fd;
460 const char *args = "";
461
462 if (mod == NULL)
463 return -ENOENT;
464
465 if (mod->path == NULL) {
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200466 ERR(mod->ctx, "Not supported to load a module by name yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200467 return -ENOSYS;
468 }
469
470 if (flags != 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200471 INFO(mod->ctx, "Flags are not implemented yet\n");
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200472
473 if ((fd = open(mod->path, O_RDONLY)) < 0) {
474 err = -errno;
475 return err;
476 }
477
Lucas De Marchib418a822011-12-01 23:13:27 -0200478 fstat(fd, &st);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200479
480 if ((mmaped_file = mmap(0, st.st_size, PROT_READ,
481 MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
482 close(fd);
483 return -errno;
484 }
485
486 err = init_module(mmaped_file, st.st_size, args);
487 if (err < 0)
Lucas De Marchi1b2e26a2011-11-25 01:28:39 -0200488 ERR(mod->ctx, "Failed to insert module '%s'\n", mod->path);
Lucas De Marchi8f788d52011-11-25 01:22:56 -0200489
490 munmap(mmaped_file, st.st_size);
491 close(fd);
492
493 return err;
494}
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200495
496KMOD_EXPORT const char *kmod_module_initstate_str(enum kmod_module_initstate state)
497{
498 switch (state) {
499 case KMOD_MODULE_BUILTIN:
500 return "builtin";
501 case KMOD_MODULE_LIVE:
502 return "live";
503 case KMOD_MODULE_COMING:
504 return "coming";
505 case KMOD_MODULE_GOING:
506 return "going";
507 default:
508 return NULL;
509 }
510}
511
512KMOD_EXPORT int kmod_module_get_initstate(const struct kmod_module *mod)
513{
514 char path[PATH_MAX], buf[32];
515 int fd, err, pathlen;
516
517 pathlen = snprintf(path, sizeof(path),
518 "/sys/module/%s/initstate", mod->name);
519 fd = open(path, O_RDONLY);
520 if (fd < 0) {
521 err = -errno;
522
523 if (pathlen > (int)sizeof("/initstate") - 1) {
524 struct stat st;
525 path[pathlen - (sizeof("/initstate") - 1)] = '\0';
526 if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
527 return KMOD_MODULE_BUILTIN;
528 }
529
530 ERR(mod->ctx, "could not open '%s': %s\n",
531 path, strerror(-err));
532 return err;
533 }
534
535 err = read_str_safe(fd, buf, sizeof(buf));
536 close(fd);
537 if (err < 0) {
538 ERR(mod->ctx, "could not read from '%s': %s\n",
539 path, strerror(-err));
540 return err;
541 }
542
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200543 if (streq(buf, "live\n"))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200544 return KMOD_MODULE_LIVE;
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200545 else if (streq(buf, "coming\n"))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200546 return KMOD_MODULE_COMING;
Lucas De Marchi877e80c2011-12-07 02:26:31 -0200547 else if (streq(buf, "going\n"))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200548 return KMOD_MODULE_GOING;
549
550 ERR(mod->ctx, "unknown %s: '%s'\n", path, buf);
551 return -EINVAL;
552}
553
554KMOD_EXPORT int kmod_module_get_refcnt(const struct kmod_module *mod)
555{
556 char path[PATH_MAX];
557 long refcnt;
558 int fd, err;
559
560 snprintf(path, sizeof(path), "/sys/module/%s/refcnt", mod->name);
561 fd = open(path, O_RDONLY);
562 if (fd < 0) {
563 err = -errno;
564 ERR(mod->ctx, "could not open '%s': %s\n",
565 path, strerror(errno));
566 return err;
567 }
568
569 err = read_str_long(fd, &refcnt, 10);
570 close(fd);
571 if (err < 0) {
572 ERR(mod->ctx, "could not read integer from '%s': '%s'\n",
573 path, strerror(-err));
574 return err;
575 }
576
577 return (int)refcnt;
578}
579
580KMOD_EXPORT struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod)
581{
582 char dname[PATH_MAX];
583 struct kmod_list *list = NULL;
584 DIR *d;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200585
586 if (mod == NULL)
587 return NULL;
588 snprintf(dname, sizeof(dname), "/sys/module/%s/holders", mod->name);
589
590 d = opendir(dname);
591 if (d == NULL) {
592 ERR(mod->ctx, "could not open '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200593 dname, strerror(errno));
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200594 return NULL;
595 }
596
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200597 for (;;) {
598 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200599 struct kmod_module *holder;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200600 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200601 int err;
602
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200603 err = readdir_r(d, &de, &entp);
604 if (err != 0) {
605 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
606 mod->name, strerror(-err));
607 goto fail;
608 }
609
610 if (entp == NULL)
611 break;
612
613 if (de.d_name[0] == '.') {
614 if (de.d_name[1] == '\0' ||
615 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200616 continue;
617 }
618
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200619 err = kmod_module_new_from_name(mod->ctx, de.d_name, &holder);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200620 if (err < 0) {
621 ERR(mod->ctx, "could not create module for '%s': %s\n",
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200622 de.d_name, strerror(-err));
623 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200624 }
625
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200626 l = kmod_list_append(list, holder);
627 if (l != NULL) {
628 list = l;
629 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200630 ERR(mod->ctx, "out of memory\n");
631 kmod_module_unref(holder);
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200632 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200633 }
634 }
635
636 closedir(d);
637 return list;
Lucas De Marchi53886dd2011-12-05 13:24:23 -0200638
639fail:
640 closedir(d);
641 kmod_module_unref_list(list);
642 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200643}
644
645struct kmod_module_section {
646 unsigned long address;
647 char name[];
648};
649
650static void kmod_module_section_free(struct kmod_module_section *section)
651{
652 free(section);
653}
654
655KMOD_EXPORT struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod)
656{
657 char dname[PATH_MAX];
658 struct kmod_list *list = NULL;
659 DIR *d;
660 int dfd;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200661
662 if (mod == NULL)
663 return NULL;
664 snprintf(dname, sizeof(dname), "/sys/module/%s/sections", mod->name);
665
666 d = opendir(dname);
667 if (d == NULL) {
668 ERR(mod->ctx, "could not open '%s': %s\n",
669 dname, strerror(errno));
670 return NULL;
671 }
672
673 dfd = dirfd(d);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200674
675 for (;;) {
676 struct dirent de, *entp;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200677 struct kmod_module_section *section;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200678 struct kmod_list *l;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200679 unsigned long address;
680 size_t namesz;
681 int fd, err;
682
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200683 err = readdir_r(d, &de, &entp);
684 if (err != 0) {
685 ERR(mod->ctx, "could not iterate for module '%s': %s\n",
686 mod->name, strerror(-err));
687 goto fail;
688 }
689
690 if (de.d_name[0] == '.') {
691 if (de.d_name[1] == '\0' ||
692 (de.d_name[1] == '.' && de.d_name[2] == '\0'))
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200693 continue;
694 }
695
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200696 fd = openat(dfd, de.d_name, O_RDONLY);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200697 if (fd < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200698 ERR(mod->ctx, "could not open '%s/%s': %m\n",
699 dname, de.d_name);
700 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200701 }
702
703 err = read_str_ulong(fd, &address, 16);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200704 close(fd);
705
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200706 if (err < 0) {
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200707 ERR(mod->ctx, "could not read long from '%s/%s': %m\n",
708 dname, de.d_name);
709 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200710 }
711
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200712 namesz = strlen(de.d_name) + 1;
713 section = malloc(sizeof(*section) + namesz);
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200714
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200715 if (section == NULL) {
716 ERR(mod->ctx, "out of memory\n");
717 goto fail;
718 }
719
720 section->address = address;
721 memcpy(section->name, de.d_name, namesz);
722
723 l = kmod_list_append(list, section);
724 if (l != NULL) {
725 list = l;
726 } else {
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200727 ERR(mod->ctx, "out of memory\n");
728 free(section);
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200729 goto fail;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200730 }
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200731 }
732
733 closedir(d);
734 return list;
Lucas De Marchi40923bd2011-12-05 13:40:16 -0200735
736fail:
737 closedir(d);
738 kmod_module_unref_list(list);
739 return NULL;
Gustavo Sverzut Barbierif12ae3c2011-12-04 12:40:00 -0200740}
741
742KMOD_EXPORT const char *kmod_module_section_get_name(const struct kmod_list *entry)
743{
744 struct kmod_module_section *section;
745 if (entry == NULL)
746 return NULL;
747 section = entry->data;
748 return section->name;
749}
750
751KMOD_EXPORT unsigned long kmod_module_section_get_address(const struct kmod_list *entry)
752{
753 struct kmod_module_section *section;
754 if (entry == NULL)
755 return (unsigned long)-1;
756 section = entry->data;
757 return section->address;
758}
759
760KMOD_EXPORT void kmod_module_section_free_list(struct kmod_list *list)
761{
762 while (list) {
763 kmod_module_section_free(list->data);
764 list = kmod_list_remove(list);
765 }
766}