]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
libkmod: Add parser for modules.builtin.modinfo
authorAlexey Gladkov <gladkov.alexey@gmail.com>
Fri, 8 Nov 2019 17:25:20 +0000 (18:25 +0100)
committerLucas De Marchi <lucas.demarchi@intel.com>
Thu, 19 Dec 2019 00:56:10 +0000 (16:56 -0800)
The kernel since version v5.2-rc1 exports information about built-in
modules in the modules.builtin.modinfo. Information is stored in
the same format as in the separate modules (null-terminated string
array). The module name is a prefix for each line.

$ tr '\0' '\n' < modules.builtin.modinfo
ext4.softdep=pre: crc32c
ext4.license=GPL
ext4.description=Fourth Extended Filesystem
ext4.author=Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others
ext4.alias=fs-ext4
ext4.alias=ext3
ext4.alias=fs-ext3
ext4.alias=ext2
ext4.alias=fs-ext2
md_mod.alias=block-major-9-*
md_mod.alias=md
md_mod.description=MD RAID framework
md_mod.license=GPL
md_mod.parmtype=create_on_open:bool
md_mod.parmtype=start_dirty_degraded:int
...

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
Makefile.am
libkmod/libkmod-builtin.c [new file with mode: 0644]
libkmod/libkmod-internal.h

index 47505c1d43ca8727e2158958e427e76d9c280b9f..56c9ba60020b39e99a20560011ecaaf9f896388a 100644 (file)
@@ -68,6 +68,7 @@ libkmod_libkmod_la_SOURCES = \
        libkmod/libkmod.h \
        libkmod/libkmod-internal.h \
        libkmod/libkmod.c \
+       libkmod/libkmod-builtin.c \
        libkmod/libkmod-list.c \
        libkmod/libkmod-config.c \
        libkmod/libkmod-index.c \
diff --git a/libkmod/libkmod-builtin.c b/libkmod/libkmod-builtin.c
new file mode 100644 (file)
index 0000000..98d7365
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * libkmod - interface to kernel built-in modules
+ *
+ * Copyright (C) 2019  Alexey Gladkov <gladkov.alexey@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "libkmod.h"
+#include "libkmod-internal.h"
+
+#define MODULES_BUILTIN_MODINFO "modules.builtin.modinfo"
+
+struct kmod_builtin_iter {
+       struct kmod_ctx *ctx;
+
+       // The file descriptor.
+       int file;
+
+       // The total size in bytes.
+       ssize_t size;
+
+       // The offset of current module.
+       off_t pos;
+
+       // The offset at which the next module is located.
+       off_t next;
+
+       // Number of strings in the current block.
+       ssize_t nstrings;
+
+       // Internal buffer and its size.
+       size_t bufsz;
+       char *buf;
+};
+
+struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
+{
+       char path[PATH_MAX];
+       int file, sv_errno;
+       struct stat sb;
+       struct kmod_builtin_iter *iter = NULL;
+       const char *dirname = kmod_get_dirname(ctx);
+       size_t len = strlen(dirname);
+
+       file = -1;
+
+       if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) {
+               sv_errno = ENAMETOOLONG;
+               goto fail;
+       }
+
+       snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO);
+
+       file = open(path, O_RDONLY|O_CLOEXEC);
+       if (file < 0) {
+               sv_errno = errno;
+               goto fail;
+       }
+
+       if (fstat(file, &sb) < 0) {
+               sv_errno = errno;
+               goto fail;
+       }
+
+       iter = malloc(sizeof(*iter));
+       if (!iter) {
+               sv_errno = ENOMEM;
+               goto fail;
+       }
+
+       iter->ctx = ctx;
+       iter->file = file;
+       iter->size = sb.st_size;
+       iter->nstrings = 0;
+       iter->pos = 0;
+       iter->next = 0;
+       iter->bufsz = 0;
+       iter->buf = NULL;
+
+       return iter;
+fail:
+       if (file >= 0)
+               close(file);
+
+       errno = sv_errno;
+
+       return iter;
+}
+
+void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
+{
+       close(iter->file);
+       free(iter->buf);
+       free(iter);
+}
+
+static off_t get_string(struct kmod_builtin_iter *iter, off_t offset,
+                       char **line, size_t *size)
+{
+       int sv_errno;
+       char *nullp = NULL;
+       size_t linesz = 0;
+
+       while (!nullp) {
+               char buf[BUFSIZ];
+               ssize_t sz;
+               size_t partsz;
+
+               sz = pread(iter->file, buf, BUFSIZ, offset);
+               if (sz < 0) {
+                       sv_errno = errno;
+                       goto fail;
+               } else if (sz == 0) {
+                       offset = 0;
+                       break;
+               }
+
+               nullp = memchr(buf, '\0', (size_t) sz);
+               partsz = (size_t)((nullp) ? (nullp - buf) + 1 : sz);
+               offset += (off_t) partsz;
+
+               if (iter->bufsz < linesz + partsz) {
+                       iter->bufsz = linesz + partsz;
+                       iter->buf = realloc(iter->buf, iter->bufsz);
+
+                       if (!iter->buf) {
+                               sv_errno = errno;
+                               goto fail;
+                       }
+               }
+
+               strncpy(iter->buf + linesz, buf, partsz);
+               linesz += partsz;
+       }
+
+       if (linesz) {
+               *line = iter->buf;
+               *size = linesz;
+       }
+
+       return offset;
+fail:
+       errno = sv_errno;
+       return -1;
+}
+
+bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
+{
+       char *line,  *modname;
+       size_t linesz;
+       off_t pos, offset, modlen;
+
+       modname = NULL;
+
+       iter->nstrings = 0;
+       offset = pos = iter->next;
+
+       while (offset < iter->size) {
+               char *dot;
+               off_t len;
+
+               offset = get_string(iter, pos, &line, &linesz);
+               if (offset <= 0) {
+                       if (offset)
+                               ERR(iter->ctx, "get_string: %s\n", strerror(errno));
+                       pos = iter->size;
+                       break;
+               }
+
+               dot = strchr(line, '.');
+               if (!dot) {
+                       ERR(iter->ctx, "kmod_builtin_iter_next: unexpected string without modname prefix\n");
+                       pos = iter->size;
+                       break;
+               }
+
+               len = dot - line;
+
+               if (!modname) {
+                       modname = strdup(line);
+                       modlen = len;
+               } else if (modlen != len || strncmp(modname, line, len)) {
+                       break;
+               }
+
+               iter->nstrings++;
+               pos = offset;
+       }
+
+       iter->pos = iter->next;
+       iter->next = pos;
+
+       free(modname);
+
+       return (iter->pos < iter->size);
+}
+
+bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter,
+                               char modname[static PATH_MAX])
+{
+       int sv_errno;
+       char *line, *dot;
+       size_t linesz, len;
+       off_t offset;
+
+       if (iter->pos == iter->size)
+               return false;
+
+       line = NULL;
+
+       offset = get_string(iter, iter->pos, &line, &linesz);
+       if (offset <= 0) {
+               sv_errno = errno;
+               if (offset)
+                       ERR(iter->ctx, "get_string: %s\n", strerror(errno));
+               goto fail;
+       }
+
+       dot = strchr(line, '.');
+       if (!dot) {
+               sv_errno = errno;
+               ERR(iter->ctx, "kmod_builtin_iter_get_modname: unexpected string without modname prefix\n");
+               goto fail;
+       }
+
+       len = dot - line;
+
+       if (len > PATH_MAX) {
+               sv_errno = ENAMETOOLONG;
+               goto fail;
+       }
+
+       strncpy(modname, line, len);
+       modname[len] = '\0';
+
+       return true;
+fail:
+       errno = sv_errno;
+       return false;
+}
+
+/* array will be allocated with strings in a single malloc, just free *array */
+ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
+                               char ***modinfo)
+{
+       ssize_t count = 0;
+       char *s, *line = NULL;
+       size_t i, n, linesz, modlen, size;
+       off_t pos, offset;
+
+       char *name = NULL;
+       char buf[PATH_MAX];
+
+       struct kmod_builtin_iter *iter = kmod_builtin_iter_new(ctx);
+
+       if (!iter)
+               return -1;
+
+       while (!name && kmod_builtin_iter_next(iter)) {
+               if (!kmod_builtin_iter_get_modname(iter, buf)) {
+                       count = -errno;
+                       goto fail;
+               }
+
+               if (strcmp(modname, buf))
+                       continue;
+
+               name = buf;
+       }
+
+       if (!name) {
+               count = -ENOSYS;
+               goto fail;
+       }
+
+       modlen = strlen(modname) + 1;
+       count = iter->nstrings;
+       size = iter->next - iter->pos - (modlen * count);
+
+       *modinfo = malloc(size + sizeof(char *) * (count + 1));
+       if (!*modinfo) {
+               count = -errno;
+               goto fail;
+       }
+
+       s = (char *)(*modinfo + count + 1);
+       i = 0;
+
+       n = 0;
+       offset = pos = iter->pos;
+
+       while (offset < iter->next) {
+               offset = get_string(iter, pos, &line, &linesz);
+               if (offset <= 0) {
+                       count = (offset) ? -errno : -EOF;
+                       goto fail;
+               }
+
+               strcpy(s + i, line + modlen);
+               (*modinfo)[n++] = s + i;
+               i += linesz - modlen;
+
+               pos = offset;
+       }
+fail:
+       kmod_builtin_iter_free(iter);
+       return count;
+}
index a65ddd156f18bd69228c8d1f112f6b552216a742..df01df142026dffac92cc4c704a5c3983dc08294 100644 (file)
@@ -193,3 +193,11 @@ struct kmod_signature_info {
 };
 bool kmod_module_signature_info(const struct kmod_file *file, struct kmod_signature_info *sig_info) _must_check_ __attribute__((nonnull(1, 2)));
 void kmod_module_signature_info_free(struct kmod_signature_info *sig_info) __attribute__((nonnull));
+
+/* libkmod-builtin.c */
+struct kmod_builtin_iter;
+struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx) __attribute__((nonnull(1)));
+void kmod_builtin_iter_free(struct kmod_builtin_iter *iter) __attribute__((nonnull(1)));
+bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter) __attribute__((nonnull(1)));
+bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter, char modname[static PATH_MAX]) __attribute__((nonnull(1, 2)));
+ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo) __attribute__((nonnull(1, 2, 3)));