All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 0/4] Add modules.builtin.modinfo support
@ 2019-10-11  8:19 Alexey Gladkov
  2019-10-11  8:19 ` [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo Alexey Gladkov
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-10-11  8:19 UTC (permalink / raw)
  To: linux-modules; +Cc: Lucas De Marchi

The kernel since version v5.2-rc1 exports information about built-in
modules in the modules.builtin.modinfo. Now, kmod can show complete information
about the built-in modules as well as about external modules. Also kmod can
understand aliases of built-in modules.

Before:

$ modinfo block-major-9-1
modinfo: ERROR: Module block-major-9-1 not found.

After:

$ modinfo block-major-9-1
name:           md_mod
filename:       (builtin)
alias:          block-major-9-*
alias:          md
description:    MD RAID framework
license:        GPL
parm:           start_dirty_degraded:int
parm:           create_on_open:bool

Alexey Gladkov (4):
  libkmod: Add parser for modules.builtin.modinfo
  libkmod: Add function to get list of built-in modules
  Lookup aliases in the modules.builtin.modinfo
  modinfo: Show information about built-in modules

 Makefile.am                |   1 +
 libkmod/libkmod-builtin.c  | 231 +++++++++++++++++++++++++++++++++++++
 libkmod/libkmod-internal.h |  10 ++
 libkmod/libkmod-module.c   |  76 ++++++++++--
 libkmod/libkmod.c          |  25 ++++
 libkmod/libkmod.h          |   1 +
 tools/depmod.c             |  63 ++++++++++
 tools/modinfo.c            |  39 ++++---
 8 files changed, 419 insertions(+), 27 deletions(-)
 create mode 100644 libkmod/libkmod-builtin.c

-- 
2.21.0


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo
  2019-10-11  8:19 [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
@ 2019-10-11  8:19 ` Alexey Gladkov
  2019-11-07  8:23   ` Lucas De Marchi
  2019-10-11  8:19 ` [PATCH v1 2/4] libkmod: Add function to get list of built-in modules Alexey Gladkov
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 9+ messages in thread
From: Alexey Gladkov @ 2019-10-11  8:19 UTC (permalink / raw)
  To: linux-modules; +Cc: Lucas De Marchi

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                |   1 +
 libkmod/libkmod-builtin.c  | 231 +++++++++++++++++++++++++++++++++++++
 libkmod/libkmod-internal.h |   8 ++
 3 files changed, 240 insertions(+)
 create mode 100644 libkmod/libkmod-builtin.c

diff --git a/Makefile.am b/Makefile.am
index c5c2f06..176dcfc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
index 0000000..9da0010
--- /dev/null
+++ b/libkmod/libkmod-builtin.c
@@ -0,0 +1,231 @@
+/*
+ * 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 <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;
+	struct kmod_file *file;
+	off_t pos;
+	off_t next;
+};
+
+struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
+{
+	char path[PATH_MAX];
+	struct kmod_file *file;
+	struct kmod_builtin_iter *iter;
+	const char *dirname = kmod_get_dirname(ctx);
+	size_t len = strlen(dirname);
+
+	if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) {
+		errno = ENAMETOOLONG;
+		return NULL;
+	}
+
+	snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO);
+
+	file = kmod_file_open(ctx, path);
+	if (!file)
+		return NULL;
+
+	iter = malloc(sizeof(*iter));
+	if (!iter) {
+		kmod_file_unref(file);
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	iter->ctx = ctx;
+	iter->file = file;
+	iter->pos = 0;
+	iter->next = 0;
+
+	return iter;
+}
+
+bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
+{
+	char *mm, *s, *dot;
+	off_t offset, mmsize;
+	size_t len, modlen;
+	char *modname = NULL;
+
+	mm = kmod_file_get_contents(iter->file);
+	mmsize = kmod_file_get_size(iter->file);
+
+	offset = iter->next;
+
+	while (offset < mmsize) {
+		s = mm + offset;
+
+		dot = strchr(s, '.');
+		if (!dot)
+			return false;
+
+		len = dot - s;
+
+		if (!modname) {
+			modname = s;
+			modlen = len;
+		} else if (modlen != len || strncmp(modname, s, len)) {
+			break;
+		}
+
+		offset += strlen(s) + 1;
+	}
+
+	if (!modname)
+		return false;
+
+	iter->next = offset;
+
+	return true;
+}
+
+void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
+{
+	kmod_file_unref(iter->file);
+	free(iter);
+}
+
+int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter,
+					const char **strings)
+{
+	char *mm = kmod_file_get_contents(iter->file);
+	off_t pos = iter->pos;
+
+	char *start = NULL;
+	size_t count = 0;
+	size_t modlen = 0;
+
+	while (pos < iter->next) {
+		char *dot = strchr(mm + pos, '.');
+		size_t len;
+
+		if (!dot)
+			return -1;
+
+		len = dot - (mm + pos);
+
+		if (!start) {
+			start = mm + pos;
+			modlen = len;
+		} else if (modlen != len || strncmp(start, mm + pos, len)) {
+			break;
+		}
+
+		pos += strlen(mm + pos) + 1;
+		count++;
+	}
+
+	*strings = start;
+	iter->pos = iter->next;
+
+	return count;
+}
+
+/* array will be allocated with strings in a single malloc, just free *array */
+int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
+				char ***modinfo)
+{
+	char *mm, *s, *section, *dot;
+	off_t n, size, offset, mmoffset, mmsize;
+	size_t modlen, len;
+	struct kmod_builtin_iter *iter;
+	int count = 0;
+
+	iter = kmod_builtin_iter_new(ctx);
+
+	if (!iter)
+		return -1;
+
+	modlen = strlen(modname);
+
+	mmsize = kmod_file_get_size(iter->file);
+	mm = kmod_file_get_contents(iter->file);
+
+	section = NULL;
+	size = 0;
+
+	for (mmoffset = 0; mmoffset < mmsize;) {
+		s = mm + mmoffset;
+		dot = strchr(s, '.');
+
+		if (!dot) {
+			count = -ENODATA;
+			goto fail;
+		}
+
+		len = dot - s;
+
+		if (modlen != len || strncmp(modname, s, len)) {
+			if (count)
+				break;
+			mmoffset += strlen(s) + 1;
+			continue;
+		} else if (!count) {
+			section = s;
+		}
+
+		len = strlen(dot + 1) + 1;
+		mmoffset += modlen + 1 + len;
+		size += len;
+
+		count++;
+	}
+
+	if (!count) {
+		count = -ENOSYS;
+		goto fail;
+	}
+
+	*modinfo = malloc(size + sizeof(char *) * (count + 1));
+	if (!*modinfo) {
+		count = -errno;
+		goto fail;
+	}
+
+	s = (char *)(*modinfo + count + 1);
+
+	n = 0;
+	mmoffset = 0;
+
+	for (offset = 0; offset < size;) {
+		len = strlen(section + mmoffset + modlen + 1) + 1;
+
+		strncpy(s + offset, section + mmoffset + modlen + 1, len);
+		(*modinfo)[n++] = s + offset;
+
+		mmoffset += modlen + 1 + len;
+		offset += len;
+	}
+
+fail:
+	kmod_builtin_iter_free(iter);
+	return count;
+}
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index a65ddd1..17ae541 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -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)));
+int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter, const char **modinfo) __attribute__((nonnull(1, 2)));
+int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo) __attribute__((nonnull(1, 2, 3)));
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 2/4] libkmod: Add function to get list of built-in modules
  2019-10-11  8:19 [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
  2019-10-11  8:19 ` [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo Alexey Gladkov
@ 2019-10-11  8:19 ` Alexey Gladkov
  2019-10-11  8:19 ` [PATCH v1 3/4] Lookup aliases in the modules.builtin.modinfo Alexey Gladkov
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-10-11  8:19 UTC (permalink / raw)
  To: linux-modules; +Cc: Lucas De Marchi

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 libkmod/libkmod-internal.h |  1 +
 libkmod/libkmod-module.c   | 43 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index 17ae541..d2000fe 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -145,6 +145,7 @@ void kmod_module_set_visited(struct kmod_module *mod, bool visited) __attribute_
 void kmod_module_set_builtin(struct kmod_module *mod, bool builtin) __attribute__((nonnull((1))));
 void kmod_module_set_required(struct kmod_module *mod, bool required) __attribute__((nonnull(1)));
 bool kmod_module_is_builtin(struct kmod_module *mod) __attribute__((nonnull(1)));
+int kmod_module_get_builtin(struct kmod_ctx *ctx, struct kmod_list **list) __attribute__((nonnull(1, 2)));
 
 /* libkmod-file.c */
 struct kmod_file *kmod_file_open(const struct kmod_ctx *ctx, const char *filename) _must_check_ __attribute__((nonnull(1,2)));
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index bffe715..82b9fbe 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -2866,3 +2866,46 @@ KMOD_EXPORT void kmod_module_dependency_symbols_free_list(struct kmod_list *list
 		list = kmod_list_remove(list);
 	}
 }
+
+/**
+ * kmod_module_get_builtin:
+ * @ctx: kmod library context
+ * @list: where to save the builtin module list
+ *
+ * Returns: 0 on success or < 0 otherwise.
+ */
+int kmod_module_get_builtin(struct kmod_ctx *ctx, struct kmod_list **list)
+{
+	struct kmod_builtin_iter *iter;
+	int err = 0;
+
+	iter = kmod_builtin_iter_new(ctx);
+	if (!iter)
+		return -errno;
+
+	while (kmod_builtin_iter_next(iter)) {
+		struct kmod_module *mod = NULL;
+		const char *strings;
+		int count;
+
+		count = kmod_builtin_iter_get_strings(iter, &strings);
+
+		if (count < 1) {
+			err = -errno;
+			goto fail;
+		}
+
+		kmod_module_new_from_name(ctx, strings, &mod);
+		kmod_module_set_builtin(mod, true);
+
+		*list = kmod_list_append(*list, mod);
+	}
+
+	kmod_builtin_iter_free(iter);
+	return err;
+fail:
+	kmod_builtin_iter_free(iter);
+	kmod_module_unref_list(*list);
+	*list = NULL;
+	return err;
+}
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 3/4] Lookup aliases in the modules.builtin.modinfo
  2019-10-11  8:19 [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
  2019-10-11  8:19 ` [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo Alexey Gladkov
  2019-10-11  8:19 ` [PATCH v1 2/4] libkmod: Add function to get list of built-in modules Alexey Gladkov
@ 2019-10-11  8:19 ` Alexey Gladkov
  2019-10-11  8:19 ` [PATCH v1 4/4] modinfo: Show information about built-in modules Alexey Gladkov
  2019-11-07 10:30 ` [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
  4 siblings, 0 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-10-11  8:19 UTC (permalink / raw)
  To: linux-modules; +Cc: Lucas De Marchi

New modules.builtin.modinfo duplicates modules.builtin in the built-in
module name search. If it exists, then we can use this file, but if not,
then we need to fallback to the old file.

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 libkmod/libkmod-internal.h |  1 +
 libkmod/libkmod-module.c   | 10 ++++--
 libkmod/libkmod.c          | 25 +++++++++++++++
 libkmod/libkmod.h          |  1 +
 tools/depmod.c             | 63 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 98 insertions(+), 2 deletions(-)

diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index d2000fe..ebed886 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -89,6 +89,7 @@ int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name, struct
 int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
 int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
 int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
+int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
 int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
 bool kmod_lookup_alias_is_builtin(struct kmod_ctx *ctx, const char *name) __attribute__((nonnull(1, 2)));
 int kmod_lookup_alias_from_commands(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index 82b9fbe..0754ad5 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -575,10 +575,16 @@ KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
 	err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
 	CHECK_ERR_AND_FINISH(err, fail, list, finish);
 
-	DBG(ctx, "lookup modules.builtin %s\n", alias);
-	err = kmod_lookup_alias_from_builtin_file(ctx, alias, list);
+	DBG(ctx, "lookup modules.builtin.modinfo %s\n", alias);
+	err = kmod_lookup_alias_from_kernel_builtin_file(ctx, alias, list);
 	CHECK_ERR_AND_FINISH(err, fail, list, finish);
 
+	if (err == 0) {
+		DBG(ctx, "lookup modules.builtin %s\n", alias);
+		err = kmod_lookup_alias_from_builtin_file(ctx, alias, list);
+		CHECK_ERR_AND_FINISH(err, fail, list, finish);
+	}
+
 finish:
 	DBG(ctx, "lookup %s=%d, list=%p\n", alias, err, *list);
 	return err;
diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c
index 69fe431..c9d9e2a 100644
--- a/libkmod/libkmod.c
+++ b/libkmod/libkmod.c
@@ -57,6 +57,7 @@ static struct _index_files {
 	[KMOD_INDEX_MODULES_DEP] = { .fn = "modules.dep", .prefix = "" },
 	[KMOD_INDEX_MODULES_ALIAS] = { .fn = "modules.alias", .prefix = "alias " },
 	[KMOD_INDEX_MODULES_SYMBOL] = { .fn = "modules.symbols", .prefix = "alias "},
+	[KMOD_INDEX_MODULES_BUILTIN_ALIAS] = { .fn = "modules.builtin.alias", .prefix = "" },
 	[KMOD_INDEX_MODULES_BUILTIN] = { .fn = "modules.builtin", .prefix = ""},
 };
 
@@ -522,6 +523,30 @@ static char *lookup_builtin_file(struct kmod_ctx *ctx, const char *name)
 	return line;
 }
 
+int kmod_lookup_alias_from_kernel_builtin_file(struct kmod_ctx *ctx,
+						const char *name,
+						struct kmod_list **list)
+{
+	struct kmod_list *l;
+	int ret = kmod_lookup_alias_from_alias_bin(ctx,
+						KMOD_INDEX_MODULES_BUILTIN_ALIAS,
+						name, list);
+	if (ret > 0) {
+		kmod_list_foreach(l, *list) {
+			struct kmod_module *mod = l->data;
+			kmod_module_set_builtin(mod, true);
+		}
+	} else if (ret == -ENOSYS) {
+		/*
+		 * If the system does not support this yet, then
+		 * there is no need to return an error.
+		 */
+		ret = 0;
+	}
+
+	return ret;
+}
+
 int kmod_lookup_alias_from_builtin_file(struct kmod_ctx *ctx, const char *name,
 						struct kmod_list **list)
 {
diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h
index 352627e..3cab2e5 100644
--- a/libkmod/libkmod.h
+++ b/libkmod/libkmod.h
@@ -70,6 +70,7 @@ enum kmod_index {
 	KMOD_INDEX_MODULES_DEP = 0,
 	KMOD_INDEX_MODULES_ALIAS,
 	KMOD_INDEX_MODULES_SYMBOL,
+	KMOD_INDEX_MODULES_BUILTIN_ALIAS,
 	KMOD_INDEX_MODULES_BUILTIN,
 	/* Padding to make sure enum is not mapped to char */
 	_KMOD_INDEX_PAD = 1U << 31,
diff --git a/tools/depmod.c b/tools/depmod.c
index 391afe9..fbbce10 100644
--- a/tools/depmod.c
+++ b/tools/depmod.c
@@ -2402,6 +2402,68 @@ static int output_devname(struct depmod *depmod, FILE *out)
 	return 0;
 }
 
+static int output_builtin_alias_bin(struct depmod *depmod, FILE *out)
+{
+	int ret = 0, count = 0;
+	struct index_node *idx;
+	struct kmod_list *l, *builtin = NULL;
+
+	idx = index_create();
+
+	if (idx == NULL) {
+		ret = -ENOMEM;
+		goto fail;
+	}
+
+	ret = kmod_module_get_builtin(depmod->ctx, &builtin);
+	if (ret < 0) {
+		if (ret == -ENOENT)
+			ret = 0;
+		goto fail;
+	}
+
+	kmod_list_foreach(l, builtin) {
+		struct kmod_list *ll, *info_list = NULL;
+		struct kmod_module *mod = l->data;
+		const char *modname = kmod_module_get_name(mod);
+
+		ret = kmod_module_get_info(mod, &info_list);
+		if (ret < 0)
+			goto fail;
+
+		kmod_list_foreach(ll, info_list) {
+			char alias[PATH_MAX];
+			const char *key = kmod_module_info_get_key(ll);
+			const char *value = kmod_module_info_get_value(ll);
+
+			if (!streq(key, "alias"))
+				continue;
+
+			alias[0] = '\0';
+			if (alias_normalize(value, alias, NULL) < 0) {
+				WRN("Unmatched bracket in %s\n", value);
+				continue;
+			}
+
+			index_insert(idx, alias, modname, 0);
+		}
+
+		kmod_module_info_free_list(info_list);
+
+		index_insert(idx, modname, modname, 0);
+		count++;
+	}
+
+	if (count)
+		index_write(idx, out);
+	index_destroy(idx);
+fail:
+	if (builtin)
+		kmod_module_unref_list(builtin);
+
+	return ret;
+}
+
 static int depmod_output(struct depmod *depmod, FILE *out)
 {
 	static const struct depfile {
@@ -2416,6 +2478,7 @@ static int depmod_output(struct depmod *depmod, FILE *out)
 		{ "modules.symbols", output_symbols },
 		{ "modules.symbols.bin", output_symbols_bin },
 		{ "modules.builtin.bin", output_builtin_bin },
+		{ "modules.builtin.alias.bin", output_builtin_alias_bin },
 		{ "modules.devname", output_devname },
 		{ }
 	};
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH v1 4/4] modinfo: Show information about built-in modules
  2019-10-11  8:19 [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
                   ` (2 preceding siblings ...)
  2019-10-11  8:19 ` [PATCH v1 3/4] Lookup aliases in the modules.builtin.modinfo Alexey Gladkov
@ 2019-10-11  8:19 ` Alexey Gladkov
  2019-11-07 10:30 ` [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
  4 siblings, 0 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-10-11  8:19 UTC (permalink / raw)
  To: linux-modules; +Cc: Lucas De Marchi

Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
---
 libkmod/libkmod-builtin.c |  2 +-
 libkmod/libkmod-module.c  | 23 ++++++++++++++++-------
 tools/modinfo.c           | 39 +++++++++++++++++++++------------------
 3 files changed, 38 insertions(+), 26 deletions(-)

diff --git a/libkmod/libkmod-builtin.c b/libkmod/libkmod-builtin.c
index 9da0010..1c16275 100644
--- a/libkmod/libkmod-builtin.c
+++ b/libkmod/libkmod-builtin.c
@@ -162,7 +162,7 @@ int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
 	iter = kmod_builtin_iter_new(ctx);
 
 	if (!iter)
-		return -1;
+		return -errno;
 
 	modlen = strlen(modname);
 
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index 0754ad5..ed82dcb 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -2286,13 +2286,22 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
 
 	assert(*list == NULL);
 
-	elf = kmod_module_get_elf(mod);
-	if (elf == NULL)
-		return -errno;
+	/* remove const: this can only change internal state */
+	if (kmod_module_is_builtin((struct kmod_module *)mod)) {
+		count = kmod_builtin_get_modinfo(mod->ctx,
+						kmod_module_get_name(mod),
+						&strings);
+		if (count < 0)
+			return count;
+	} else {
+		elf = kmod_module_get_elf(mod);
+		if (elf == NULL)
+			return -errno;
 
-	count = kmod_elf_get_strings(elf, ".modinfo", &strings);
-	if (count < 0)
-		return count;
+		count = kmod_elf_get_strings(elf, ".modinfo", &strings);
+		if (count < 0)
+			return count;
+	}
 
 	for (i = 0; i < count; i++) {
 		struct kmod_list *n;
@@ -2316,7 +2325,7 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
 			goto list_error;
 	}
 
-	if (kmod_module_signature_info(mod->file, &sig_info)) {
+	if (mod->file && kmod_module_signature_info(mod->file, &sig_info)) {
 		struct kmod_list *n;
 
 		n = kmod_module_info_append(list, "sig_id", strlen("sig_id"),
diff --git a/tools/modinfo.c b/tools/modinfo.c
index 86ac04b..0231bb0 100644
--- a/tools/modinfo.c
+++ b/tools/modinfo.c
@@ -172,18 +172,33 @@ static int modinfo_do(struct kmod_module *mod)
 {
 	struct kmod_list *l, *list = NULL;
 	struct param *params = NULL;
-	int err;
+	int err, is_builtin;
+	const char *filename = kmod_module_get_path(mod);
+
+	is_builtin = (filename == NULL);
+
+	if (is_builtin) {
+		printf("%-16s%s%c", "name:", kmod_module_get_name(mod), separator);
+		filename = "(builtin)";
+	}
 
 	if (field != NULL && streq(field, "filename")) {
-		printf("%s%c", kmod_module_get_path(mod), separator);
+		printf("%s%c", filename, separator);
 		return 0;
 	} else if (field == NULL) {
 		printf("%-16s%s%c", "filename:",
-		       kmod_module_get_path(mod), separator);
+		       filename, separator);
 	}
 
 	err = kmod_module_get_info(mod, &list);
 	if (err < 0) {
+		if (is_builtin && err == -ENOENT) {
+			/*
+			 * This is an old kernel that does not have a file
+			 * with information about built-in modules.
+			 */
+			return 0;
+		}
 		ERR("could not get modinfo from '%s': %s\n",
 			kmod_module_get_name(mod), strerror(-err));
 		return err;
@@ -276,7 +291,7 @@ static int modinfo_path_do(struct kmod_ctx *ctx, const char *path)
 
 static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias)
 {
-	struct kmod_list *l, *filtered, *list = NULL;
+	struct kmod_list *l, *list = NULL;
 	int err = kmod_module_new_from_lookup(ctx, alias, &list);
 	if (err < 0) {
 		ERR("Module alias %s not found.\n", alias);
@@ -288,26 +303,14 @@ static int modinfo_alias_do(struct kmod_ctx *ctx, const char *alias)
 		return -ENOENT;
 	}
 
-	err = kmod_module_apply_filter(ctx, KMOD_FILTER_BUILTIN, list, &filtered);
-	kmod_module_unref_list(list);
-	if (err < 0) {
-		ERR("Failed to filter list: %m\n");
-		return err;
-	}
-
-	if (filtered == NULL) {
-		ERR("Module %s not found.\n", alias);
-		return -ENOENT;
-	}
-
-	kmod_list_foreach(l, filtered) {
+	kmod_list_foreach(l, list) {
 		struct kmod_module *mod = kmod_module_get_module(l);
 		int r = modinfo_do(mod);
 		kmod_module_unref(mod);
 		if (r < 0)
 			err = r;
 	}
-	kmod_module_unref_list(filtered);
+	kmod_module_unref_list(list);
 	return err;
 }
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo
  2019-10-11  8:19 ` [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo Alexey Gladkov
@ 2019-11-07  8:23   ` Lucas De Marchi
  2019-11-08 17:31     ` Alexey Gladkov
  0 siblings, 1 reply; 9+ messages in thread
From: Lucas De Marchi @ 2019-11-07  8:23 UTC (permalink / raw)
  To: Alexey Gladkov; +Cc: linux-modules, Lucas De Marchi

On Fri, Oct 11, 2019 at 10:19:53AM +0200, Alexey Gladkov wrote:
>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


Apologies, I thought I had replied to this already. Having this
functionality is very welcome, thanks. I have some comments about the
implementation. See below.


>...
>
>Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
>---
> Makefile.am                |   1 +
> libkmod/libkmod-builtin.c  | 231 +++++++++++++++++++++++++++++++++++++
> libkmod/libkmod-internal.h |   8 ++
> 3 files changed, 240 insertions(+)
> create mode 100644 libkmod/libkmod-builtin.c
>
>diff --git a/Makefile.am b/Makefile.am
>index c5c2f06..176dcfc 100644
>--- a/Makefile.am
>+++ b/Makefile.am
>@@ -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
>index 0000000..9da0010
>--- /dev/null
>+++ b/libkmod/libkmod-builtin.c
>@@ -0,0 +1,231 @@
>+/*
>+ * 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/>.
>+ */

this remembers me we should convert these headers to spdx

>+
>+#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;
>+	struct kmod_file *file;
>+	off_t pos;
>+	off_t next;
>+};
>+
>+struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
>+{
>+	char path[PATH_MAX];
>+	struct kmod_file *file;
>+	struct kmod_builtin_iter *iter;
>+	const char *dirname = kmod_get_dirname(ctx);
>+	size_t len = strlen(dirname);
>+
>+	if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) {
>+		errno = ENAMETOOLONG;
>+		return NULL;
>+	}
>+
>+	snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO);
>+
>+	file = kmod_file_open(ctx, path);
>+	if (!file)
>+		return NULL;
>+
>+	iter = malloc(sizeof(*iter));
>+	if (!iter) {
>+		kmod_file_unref(file);
>+		errno = ENOMEM;
>+		return NULL;
>+	}
>+
>+	iter->ctx = ctx;
>+	iter->file = file;
>+	iter->pos = 0;
>+	iter->next = 0;
>+
>+	return iter;
>+}
>+
>+bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
>+{
>+	char *mm, *s, *dot;
>+	off_t offset, mmsize;
>+	size_t len, modlen;
>+	char *modname = NULL;
>+
>+	mm = kmod_file_get_contents(iter->file);
>+	mmsize = kmod_file_get_size(iter->file);

humn... kmod_file is more target for handling modules. This is only
< 100k  and we would access it sequentially. I think we are fine just
using stdio.

>+
>+	offset = iter->next;
>+
>+	while (offset < mmsize) {
>+		s = mm + offset;
>+
>+		dot = strchr(s, '.');
>+		if (!dot)
>+			return false;

wouldn't this fail if in the description of a module/param we have a dot?
I think a more correct approach is to search for \0 and then try to
match the prefix.

Actually, maybe even better to memmem() "\0<module-name>.", first being
an exception.


>+
>+		len = dot - s;
>+
>+		if (!modname) {
>+			modname = s;
>+			modlen = len;
>+		} else if (modlen != len || strncmp(modname, s, len)) {
>+			break;
>+		}
>+
>+		offset += strlen(s) + 1;
>+	}
>+
>+	if (!modname)
>+		return false;
>+
>+	iter->next = offset;
>+
>+	return true;
>+}
>+
>+void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
>+{
>+	kmod_file_unref(iter->file);
>+	free(iter);
>+}
>+
>+int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter,
>+					const char **strings)
>+{
>+	char *mm = kmod_file_get_contents(iter->file);
>+	off_t pos = iter->pos;
>+
>+	char *start = NULL;
>+	size_t count = 0;
>+	size_t modlen = 0;
>+
>+	while (pos < iter->next) {
>+		char *dot = strchr(mm + pos, '.');
>+		size_t len;
>+
>+		if (!dot)
>+			return -1;
>+
>+		len = dot - (mm + pos);
>+
>+		if (!start) {
>+			start = mm + pos;
>+			modlen = len;
>+		} else if (modlen != len || strncmp(start, mm + pos, len)) {
>+			break;
>+		}
>+
>+		pos += strlen(mm + pos) + 1;
>+		count++;
>+	}
>+
>+	*strings = start;
>+	iter->pos = iter->next;
>+
>+	return count;
>+}
>+
>+/* array will be allocated with strings in a single malloc, just free *array */
>+int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
>+				char ***modinfo)
>+{
>+	char *mm, *s, *section, *dot;
>+	off_t n, size, offset, mmoffset, mmsize;
>+	size_t modlen, len;
>+	struct kmod_builtin_iter *iter;
>+	int count = 0;
>+
>+	iter = kmod_builtin_iter_new(ctx);
>+
>+	if (!iter)
>+		return -1;
>+
>+	modlen = strlen(modname);
>+
>+	mmsize = kmod_file_get_size(iter->file);
>+	mm = kmod_file_get_contents(iter->file);
>+
>+	section = NULL;
>+	size = 0;
>+
>+	for (mmoffset = 0; mmoffset < mmsize;) {
>+		s = mm + mmoffset;
>+		dot = strchr(s, '.');
>+
>+		if (!dot) {
>+			count = -ENODATA;
>+			goto fail;
>+		}
>+
>+		len = dot - s;
>+
>+		if (modlen != len || strncmp(modname, s, len)) {
>+			if (count)
>+				break;
>+			mmoffset += strlen(s) + 1;
>+			continue;
>+		} else if (!count) {
>+			section = s;
>+		}
>+
>+		len = strlen(dot + 1) + 1;
>+		mmoffset += modlen + 1 + len;
>+		size += len;
>+
>+		count++;
>+	}
>+
>+	if (!count) {
>+		count = -ENOSYS;
>+		goto fail;
>+	}
>+
>+	*modinfo = malloc(size + sizeof(char *) * (count + 1));
>+	if (!*modinfo) {
>+		count = -errno;
>+		goto fail;
>+	}
>+
>+	s = (char *)(*modinfo + count + 1);
>+
>+	n = 0;
>+	mmoffset = 0;
>+
>+	for (offset = 0; offset < size;) {
>+		len = strlen(section + mmoffset + modlen + 1) + 1;
>+
>+		strncpy(s + offset, section + mmoffset + modlen + 1, len);
>+		(*modinfo)[n++] = s + offset;
>+
>+		mmoffset += modlen + 1 + len;
>+		offset += len;
>+	}
>+
>+fail:
>+	kmod_builtin_iter_free(iter);
>+	return count;
>+}
>diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
>index a65ddd1..17ae541 100644
>--- a/libkmod/libkmod-internal.h
>+++ b/libkmod/libkmod-internal.h
>@@ -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)));
>+int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter, const char **modinfo) __attribute__((nonnull(1, 2)));
>+int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo) __attribute__((nonnull(1, 2, 3)));
>-- 
>2.21.0
>

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 0/4] Add modules.builtin.modinfo support
  2019-10-11  8:19 [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
                   ` (3 preceding siblings ...)
  2019-10-11  8:19 ` [PATCH v1 4/4] modinfo: Show information about built-in modules Alexey Gladkov
@ 2019-11-07 10:30 ` Alexey Gladkov
  4 siblings, 0 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-11-07 10:30 UTC (permalink / raw)
  To: linux-modules; +Cc: Lucas De Marchi

On Fri, Oct 11, 2019 at 10:19:52AM +0200, Alexey Gladkov wrote:
> The kernel since version v5.2-rc1 exports information about built-in
> modules in the modules.builtin.modinfo. Now, kmod can show complete information
> about the built-in modules as well as about external modules. Also kmod can
> understand aliases of built-in modules.
> 
> Before:
> 
> $ modinfo block-major-9-1
> modinfo: ERROR: Module block-major-9-1 not found.
> 
> After:
> 
> $ modinfo block-major-9-1
> name:           md_mod
> filename:       (builtin)
> alias:          block-major-9-*
> alias:          md
> description:    MD RAID framework
> license:        GPL
> parm:           start_dirty_degraded:int
> parm:           create_on_open:bool

Please review.

> Alexey Gladkov (4):
>   libkmod: Add parser for modules.builtin.modinfo
>   libkmod: Add function to get list of built-in modules
>   Lookup aliases in the modules.builtin.modinfo
>   modinfo: Show information about built-in modules
> 
>  Makefile.am                |   1 +
>  libkmod/libkmod-builtin.c  | 231 +++++++++++++++++++++++++++++++++++++
>  libkmod/libkmod-internal.h |  10 ++
>  libkmod/libkmod-module.c   |  76 ++++++++++--
>  libkmod/libkmod.c          |  25 ++++
>  libkmod/libkmod.h          |   1 +
>  tools/depmod.c             |  63 ++++++++++
>  tools/modinfo.c            |  39 ++++---
>  8 files changed, 419 insertions(+), 27 deletions(-)
>  create mode 100644 libkmod/libkmod-builtin.c
> 
> -- 
> 2.21.0
> 

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo
  2019-11-07  8:23   ` Lucas De Marchi
@ 2019-11-08 17:31     ` Alexey Gladkov
  0 siblings, 0 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-11-08 17:31 UTC (permalink / raw)
  To: Lucas De Marchi; +Cc: linux-modules

On Thu, Nov 07, 2019 at 12:23:10AM -0800, Lucas De Marchi wrote:
> On Fri, Oct 11, 2019 at 10:19:53AM +0200, Alexey Gladkov wrote:
> > 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
> 
> 
> Apologies, I thought I had replied to this already. Having this
> functionality is very welcome, thanks. I have some comments about the
> implementation. See below.
> 
> 
> > ...
> > 
> > Signed-off-by: Alexey Gladkov <gladkov.alexey@gmail.com>
> > ---
> > Makefile.am                |   1 +
> > libkmod/libkmod-builtin.c  | 231 +++++++++++++++++++++++++++++++++++++
> > libkmod/libkmod-internal.h |   8 ++
> > 3 files changed, 240 insertions(+)
> > create mode 100644 libkmod/libkmod-builtin.c
> > 
> > diff --git a/Makefile.am b/Makefile.am
> > index c5c2f06..176dcfc 100644
> > --- a/Makefile.am
> > +++ b/Makefile.am
> > @@ -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
> > index 0000000..9da0010
> > --- /dev/null
> > +++ b/libkmod/libkmod-builtin.c
> > @@ -0,0 +1,231 @@
> > +/*
> > + * 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/>.
> > + */
> 
> this remembers me we should convert these headers to spdx
> 
> > +
> > +#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;
> > +	struct kmod_file *file;
> > +	off_t pos;
> > +	off_t next;
> > +};
> > +
> > +struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
> > +{
> > +	char path[PATH_MAX];
> > +	struct kmod_file *file;
> > +	struct kmod_builtin_iter *iter;
> > +	const char *dirname = kmod_get_dirname(ctx);
> > +	size_t len = strlen(dirname);
> > +
> > +	if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) {
> > +		errno = ENAMETOOLONG;
> > +		return NULL;
> > +	}
> > +
> > +	snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO);
> > +
> > +	file = kmod_file_open(ctx, path);
> > +	if (!file)
> > +		return NULL;
> > +
> > +	iter = malloc(sizeof(*iter));
> > +	if (!iter) {
> > +		kmod_file_unref(file);
> > +		errno = ENOMEM;
> > +		return NULL;
> > +	}
> > +
> > +	iter->ctx = ctx;
> > +	iter->file = file;
> > +	iter->pos = 0;
> > +	iter->next = 0;
> > +
> > +	return iter;
> > +}
> > +
> > +bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
> > +{
> > +	char *mm, *s, *dot;
> > +	off_t offset, mmsize;
> > +	size_t len, modlen;
> > +	char *modname = NULL;
> > +
> > +	mm = kmod_file_get_contents(iter->file);
> > +	mmsize = kmod_file_get_size(iter->file);
> 
> humn... kmod_file is more target for handling modules. This is only
> < 100k  and we would access it sequentially. I think we are fine just
> using stdio.

Make sense.

> > +
> > +	offset = iter->next;
> > +
> > +	while (offset < mmsize) {
> > +		s = mm + offset;
> > +
> > +		dot = strchr(s, '.');
> > +		if (!dot)
> > +			return false;
> 
> wouldn't this fail if in the description of a module/param we have a dot?

No. All fields have a module name as a prefix.

> I think a more correct approach is to search for \0 and then try to
> match the prefix.
> 
> Actually, maybe even better to memmem() "\0<module-name>.", first being
> an exception.
> 
> 
> > +
> > +		len = dot - s;
> > +
> > +		if (!modname) {
> > +			modname = s;
> > +			modlen = len;
> > +		} else if (modlen != len || strncmp(modname, s, len)) {
> > +			break;
> > +		}
> > +
> > +		offset += strlen(s) + 1;
> > +	}
> > +
> > +	if (!modname)
> > +		return false;
> > +
> > +	iter->next = offset;
> > +
> > +	return true;
> > +}
> > +
> > +void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
> > +{
> > +	kmod_file_unref(iter->file);
> > +	free(iter);
> > +}
> > +
> > +int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter,
> > +					const char **strings)
> > +{
> > +	char *mm = kmod_file_get_contents(iter->file);
> > +	off_t pos = iter->pos;
> > +
> > +	char *start = NULL;
> > +	size_t count = 0;
> > +	size_t modlen = 0;
> > +
> > +	while (pos < iter->next) {
> > +		char *dot = strchr(mm + pos, '.');
> > +		size_t len;
> > +
> > +		if (!dot)
> > +			return -1;
> > +
> > +		len = dot - (mm + pos);
> > +
> > +		if (!start) {
> > +			start = mm + pos;
> > +			modlen = len;
> > +		} else if (modlen != len || strncmp(start, mm + pos, len)) {
> > +			break;
> > +		}
> > +
> > +		pos += strlen(mm + pos) + 1;
> > +		count++;
> > +	}
> > +
> > +	*strings = start;
> > +	iter->pos = iter->next;
> > +
> > +	return count;
> > +}
> > +
> > +/* array will be allocated with strings in a single malloc, just free *array */
> > +int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
> > +				char ***modinfo)
> > +{
> > +	char *mm, *s, *section, *dot;
> > +	off_t n, size, offset, mmoffset, mmsize;
> > +	size_t modlen, len;
> > +	struct kmod_builtin_iter *iter;
> > +	int count = 0;
> > +
> > +	iter = kmod_builtin_iter_new(ctx);
> > +
> > +	if (!iter)
> > +		return -1;
> > +
> > +	modlen = strlen(modname);
> > +
> > +	mmsize = kmod_file_get_size(iter->file);
> > +	mm = kmod_file_get_contents(iter->file);
> > +
> > +	section = NULL;
> > +	size = 0;
> > +
> > +	for (mmoffset = 0; mmoffset < mmsize;) {
> > +		s = mm + mmoffset;
> > +		dot = strchr(s, '.');
> > +
> > +		if (!dot) {
> > +			count = -ENODATA;
> > +			goto fail;
> > +		}
> > +
> > +		len = dot - s;
> > +
> > +		if (modlen != len || strncmp(modname, s, len)) {
> > +			if (count)
> > +				break;
> > +			mmoffset += strlen(s) + 1;
> > +			continue;
> > +		} else if (!count) {
> > +			section = s;
> > +		}
> > +
> > +		len = strlen(dot + 1) + 1;
> > +		mmoffset += modlen + 1 + len;
> > +		size += len;
> > +
> > +		count++;
> > +	}
> > +
> > +	if (!count) {
> > +		count = -ENOSYS;
> > +		goto fail;
> > +	}
> > +
> > +	*modinfo = malloc(size + sizeof(char *) * (count + 1));
> > +	if (!*modinfo) {
> > +		count = -errno;
> > +		goto fail;
> > +	}
> > +
> > +	s = (char *)(*modinfo + count + 1);
> > +
> > +	n = 0;
> > +	mmoffset = 0;
> > +
> > +	for (offset = 0; offset < size;) {
> > +		len = strlen(section + mmoffset + modlen + 1) + 1;
> > +
> > +		strncpy(s + offset, section + mmoffset + modlen + 1, len);
> > +		(*modinfo)[n++] = s + offset;
> > +
> > +		mmoffset += modlen + 1 + len;
> > +		offset += len;
> > +	}
> > +
> > +fail:
> > +	kmod_builtin_iter_free(iter);
> > +	return count;
> > +}
> > diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
> > index a65ddd1..17ae541 100644
> > --- a/libkmod/libkmod-internal.h
> > +++ b/libkmod/libkmod-internal.h
> > @@ -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)));
> > +int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter, const char **modinfo) __attribute__((nonnull(1, 2)));
> > +int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo) __attribute__((nonnull(1, 2, 3)));
> > -- 
> > 2.21.0
> > 
> 

-- 
Rgrds, legion


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo
  2019-10-10 12:09 Alexey Gladkov
@ 2019-10-10 12:09 ` Alexey Gladkov
  0 siblings, 0 replies; 9+ messages in thread
From: Alexey Gladkov @ 2019-10-10 12:09 UTC (permalink / raw)
  To: util-linux

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                |   1 +
 libkmod/libkmod-builtin.c  | 231 +++++++++++++++++++++++++++++++++++++
 libkmod/libkmod-internal.h |   8 ++
 3 files changed, 240 insertions(+)
 create mode 100644 libkmod/libkmod-builtin.c

diff --git a/Makefile.am b/Makefile.am
index c5c2f06..176dcfc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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
index 0000000..9da0010
--- /dev/null
+++ b/libkmod/libkmod-builtin.c
@@ -0,0 +1,231 @@
+/*
+ * 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 <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;
+	struct kmod_file *file;
+	off_t pos;
+	off_t next;
+};
+
+struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
+{
+	char path[PATH_MAX];
+	struct kmod_file *file;
+	struct kmod_builtin_iter *iter;
+	const char *dirname = kmod_get_dirname(ctx);
+	size_t len = strlen(dirname);
+
+	if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) {
+		errno = ENAMETOOLONG;
+		return NULL;
+	}
+
+	snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO);
+
+	file = kmod_file_open(ctx, path);
+	if (!file)
+		return NULL;
+
+	iter = malloc(sizeof(*iter));
+	if (!iter) {
+		kmod_file_unref(file);
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	iter->ctx = ctx;
+	iter->file = file;
+	iter->pos = 0;
+	iter->next = 0;
+
+	return iter;
+}
+
+bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
+{
+	char *mm, *s, *dot;
+	off_t offset, mmsize;
+	size_t len, modlen;
+	char *modname = NULL;
+
+	mm = kmod_file_get_contents(iter->file);
+	mmsize = kmod_file_get_size(iter->file);
+
+	offset = iter->next;
+
+	while (offset < mmsize) {
+		s = mm + offset;
+
+		dot = strchr(s, '.');
+		if (!dot)
+			return false;
+
+		len = dot - s;
+
+		if (!modname) {
+			modname = s;
+			modlen = len;
+		} else if (modlen != len || strncmp(modname, s, len)) {
+			break;
+		}
+
+		offset += strlen(s) + 1;
+	}
+
+	if (!modname)
+		return false;
+
+	iter->next = offset;
+
+	return true;
+}
+
+void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
+{
+	kmod_file_unref(iter->file);
+	free(iter);
+}
+
+int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter,
+					const char **strings)
+{
+	char *mm = kmod_file_get_contents(iter->file);
+	off_t pos = iter->pos;
+
+	char *start = NULL;
+	size_t count = 0;
+	size_t modlen = 0;
+
+	while (pos < iter->next) {
+		char *dot = strchr(mm + pos, '.');
+		size_t len;
+
+		if (!dot)
+			return -1;
+
+		len = dot - (mm + pos);
+
+		if (!start) {
+			start = mm + pos;
+			modlen = len;
+		} else if (modlen != len || strncmp(start, mm + pos, len)) {
+			break;
+		}
+
+		pos += strlen(mm + pos) + 1;
+		count++;
+	}
+
+	*strings = start;
+	iter->pos = iter->next;
+
+	return count;
+}
+
+/* array will be allocated with strings in a single malloc, just free *array */
+int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
+				char ***modinfo)
+{
+	char *mm, *s, *section, *dot;
+	off_t n, size, offset, mmoffset, mmsize;
+	size_t modlen, len;
+	struct kmod_builtin_iter *iter;
+	int count = 0;
+
+	iter = kmod_builtin_iter_new(ctx);
+
+	if (!iter)
+		return -1;
+
+	modlen = strlen(modname);
+
+	mmsize = kmod_file_get_size(iter->file);
+	mm = kmod_file_get_contents(iter->file);
+
+	section = NULL;
+	size = 0;
+
+	for (mmoffset = 0; mmoffset < mmsize;) {
+		s = mm + mmoffset;
+		dot = strchr(s, '.');
+
+		if (!dot) {
+			count = -ENODATA;
+			goto fail;
+		}
+
+		len = dot - s;
+
+		if (modlen != len || strncmp(modname, s, len)) {
+			if (count)
+				break;
+			mmoffset += strlen(s) + 1;
+			continue;
+		} else if (!count) {
+			section = s;
+		}
+
+		len = strlen(dot + 1) + 1;
+		mmoffset += modlen + 1 + len;
+		size += len;
+
+		count++;
+	}
+
+	if (!count) {
+		count = -ENOSYS;
+		goto fail;
+	}
+
+	*modinfo = malloc(size + sizeof(char *) * (count + 1));
+	if (!*modinfo) {
+		count = -errno;
+		goto fail;
+	}
+
+	s = (char *)(*modinfo + count + 1);
+
+	n = 0;
+	mmoffset = 0;
+
+	for (offset = 0; offset < size;) {
+		len = strlen(section + mmoffset + modlen + 1) + 1;
+
+		strncpy(s + offset, section + mmoffset + modlen + 1, len);
+		(*modinfo)[n++] = s + offset;
+
+		mmoffset += modlen + 1 + len;
+		offset += len;
+	}
+
+fail:
+	kmod_builtin_iter_free(iter);
+	return count;
+}
diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h
index a65ddd1..17ae541 100644
--- a/libkmod/libkmod-internal.h
+++ b/libkmod/libkmod-internal.h
@@ -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)));
+int kmod_builtin_iter_get_strings(struct kmod_builtin_iter *iter, const char **modinfo) __attribute__((nonnull(1, 2)));
+int kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, char ***modinfo) __attribute__((nonnull(1, 2, 3)));
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-11-08 17:31 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-11  8:19 [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
2019-10-11  8:19 ` [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo Alexey Gladkov
2019-11-07  8:23   ` Lucas De Marchi
2019-11-08 17:31     ` Alexey Gladkov
2019-10-11  8:19 ` [PATCH v1 2/4] libkmod: Add function to get list of built-in modules Alexey Gladkov
2019-10-11  8:19 ` [PATCH v1 3/4] Lookup aliases in the modules.builtin.modinfo Alexey Gladkov
2019-10-11  8:19 ` [PATCH v1 4/4] modinfo: Show information about built-in modules Alexey Gladkov
2019-11-07 10:30 ` [PATCH v1 0/4] Add modules.builtin.modinfo support Alexey Gladkov
  -- strict thread matches above, loose matches on Subject: below --
2019-10-10 12:09 Alexey Gladkov
2019-10-10 12:09 ` [PATCH v1 1/4] libkmod: Add parser for modules.builtin.modinfo Alexey Gladkov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.