You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
921 lines
28 KiB
921 lines
28 KiB
7 years ago
|
From e91ce48303e37b92f123a91acfa9cbda17035d7c Mon Sep 17 00:00:00 2001
|
||
|
From: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Thu, 17 Aug 2017 15:09:06 +0300
|
||
|
Subject: [PATCH] depmod: backport external directories support
|
||
|
|
||
|
Requires to backport scratchbuf implementation
|
||
|
|
||
|
Squashed commit of the following:
|
||
|
|
||
|
commit 92ab2321a4b761eb2822d77dc235dd543b021c69
|
||
|
Author: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Thu Jul 20 17:09:52 2017 +0300
|
||
|
|
||
|
man/depmod.d: add external keyword description
|
||
|
|
||
|
The commit 'depmod: implement external directories support' added
|
||
|
external directories support (see
|
||
|
7da6884e7357ac05772e90f6d7e63b1948103fc4).
|
||
|
|
||
|
This patch documents the extention in the manpage.
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
|
||
|
commit 01673c9b8dbe580634604808f831b735aa7fe298
|
||
|
Author: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Tue May 9 22:09:23 2017 +0300
|
||
|
|
||
|
depmod: implement external directories support
|
||
|
|
||
|
The idea is to add a configuration keyword, external, which
|
||
|
will list directories for scanning for particular kernel version
|
||
|
mask:
|
||
|
|
||
|
external 4.10 /the/modules/dir /second/modules/dir
|
||
|
|
||
|
And extend "search" keyword to set it's priority with pseudo dir
|
||
|
"external" (as it's done for built-in):
|
||
|
|
||
|
search subdir external subdir2 built-in subdir3
|
||
|
|
||
|
(actually, the version is the same as for override keyword: * or
|
||
|
posix regexp, so example above is a bit incorrect).
|
||
|
|
||
|
All other logic left the same: if there are duplicates, only one
|
||
|
is under consideration and it is unloadable if it is bad.
|
||
|
|
||
|
The resulting modules.dep will contain entries a-la:
|
||
|
|
||
|
/the/modules/dir/module1.ko:
|
||
|
kernel/module2.ko: /the/modules/dir/module1.ko
|
||
|
|
||
|
(here /lib/modules/$(uname -r)/kernel/module2.ko depends of
|
||
|
symbols, provided by /the/modules/dir/module1.ko and external has
|
||
|
higher priority).
|
||
|
|
||
|
modprobe and modinfo understand it out of box.
|
||
|
|
||
|
This is a pretty simple extention of existing logic, since now
|
||
|
depmod already is able to:
|
||
|
|
||
|
a) scan modules with full path from command line without -a
|
||
|
switch;
|
||
|
b) detects broken symbol dependencies and broken modversions,
|
||
|
what assumes, that modules are already are not built for the
|
||
|
existing kernel.
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
|
||
|
commit 5274ad44377ad5998b9f4b3c5c180d407ed68fb9
|
||
|
Author: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Tue May 9 22:09:22 2017 +0300
|
||
|
|
||
|
depmod: rewrite depmod modules search with scratchbuf
|
||
|
|
||
|
The recursive search code used used pretty big, PATH_MAX,
|
||
|
automatic storage buffer for the module directory scanning. Some
|
||
|
time ago there was scratchbuf implemented, which dynamically
|
||
|
reallocates its buffer on demand. The patch takes it in use for
|
||
|
the scanning code also. The initial size is hardcoded to 256
|
||
|
bytes which sounds good enough for most usecases so there should
|
||
|
be not many reallocations.
|
||
|
|
||
|
(add #include <shared/scratchbuf.h> which in upstream
|
||
|
comes from 3b4c684c125d depmod: fix string overflow)
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
|
||
|
commit 88f47f04df80dd80065d2811f3a7bae25dd98a79
|
||
|
Author: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Tue May 9 22:09:21 2017 +0300
|
||
|
|
||
|
depmod: create depmod dir independent search function
|
||
|
|
||
|
Prepare to implement external directories support.
|
||
|
|
||
|
The patch splits depmod_modules_search() function to two
|
||
|
functions: depmod_modules_search(), called by the high level with
|
||
|
intention to search all possible modules, and
|
||
|
depmod_module_search_path(), which takes path as a parameter and
|
||
|
scans modules under the path only. Initially it is used to scan
|
||
|
the same depmod->cfg->dirname path only.
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
|
||
|
commit 6488110e07ad49a0dc4da7bbf79dd00a50bd9cc5
|
||
|
Author: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Wed Nov 23 17:23:38 2016 +0200
|
||
|
|
||
|
depmod: search key: move builtin detection under the add function
|
||
|
|
||
|
Prepare to implement external directories support.
|
||
|
|
||
|
It's better to isolate behaviour difference under the
|
||
|
cfg_search_add() call, then make the client code aware of it.
|
||
|
|
||
|
In case of external modules/directories support, there will be
|
||
|
one more keyword added, so making the clients aware of it makes
|
||
|
even less sense.
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
|
||
|
commit 183465f82e0157b7facba9e100d0e822163ca951
|
||
|
Author: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
Date: Wed Nov 9 08:52:26 2016 +0200
|
||
|
|
||
|
shared: make scratchbuf_str static
|
||
|
|
||
|
It fixes linking problem
|
||
|
|
||
|
tools/depmod.o: In function `output_symbols_bin':
|
||
|
depmod.c:(.text.output_symbols_bin+0x135): undefined reference to `scratchbuf_str'
|
||
|
|
||
|
for -O0 build, where gcc doesn't actually inline it.
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
|
||
|
commit 4d202380a16b273a641b3c9e85a6d80d9f367c68
|
||
|
Author: Lucas De Marchi <lucas.demarchi@intel.com>
|
||
|
Date: Wed Aug 10 14:51:57 2016 -0300
|
||
|
|
||
|
testsuite: include stdio.h
|
||
|
|
||
|
It's used in the log macros so include it.
|
||
|
|
||
|
commit c226d66c43c7550247c76e7285aeb338dce2ea34
|
||
|
Author: Lucas De Marchi <lucas.demarchi@intel.com>
|
||
|
Date: Wed Aug 10 14:20:32 2016 -0300
|
||
|
|
||
|
Add scratchbuf implementation
|
||
|
|
||
|
This should fill the requirements for "we need to loop over a lot of
|
||
|
strings that usually are small enough to remain on stack, but we want to
|
||
|
protect ourselves against huge strings not fitting in the static
|
||
|
buffer we estimated as sufficient"
|
||
|
|
||
|
Signed-off-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
|
||
|
---
|
||
|
Makefile.am | 5 +
|
||
|
man/depmod.d.xml | 20 ++++
|
||
|
shared/scratchbuf.c | 60 +++++++++++
|
||
|
shared/scratchbuf.h | 31 ++++++
|
||
|
testsuite/.gitignore | 3 +
|
||
|
testsuite/test-scratchbuf.c | 89 +++++++++++++++++
|
||
|
testsuite/testsuite.h | 1 +
|
||
|
tools/depmod.c | 239 ++++++++++++++++++++++++++++++++++++--------
|
||
|
8 files changed, 404 insertions(+), 44 deletions(-)
|
||
|
create mode 100644 shared/scratchbuf.c
|
||
|
create mode 100644 shared/scratchbuf.h
|
||
|
create mode 100644 testsuite/test-scratchbuf.c
|
||
|
|
||
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 896ae6366f45..407efe3f93c2 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -51,6 +51,7 @@ shared_libshared_la_SOURCES = \
|
||
|
shared/array.h \
|
||
|
shared/hash.c \
|
||
|
shared/hash.h \
|
||
|
+ shared/scratchbuf.c \
|
||
|
shared/strbuf.c \
|
||
|
shared/strbuf.h \
|
||
|
shared/util.c \
|
||
|
@@ -307,6 +308,7 @@ testsuite_libtestsuite_la_LIBADD = -lrt
|
||
|
TESTSUITE = \
|
||
|
testsuite/test-hash \
|
||
|
testsuite/test-array \
|
||
|
+ testsuite/test-scratchbuf \
|
||
|
testsuite/test-strbuf \
|
||
|
testsuite/test-init \
|
||
|
testsuite/test-initstate \
|
||
|
@@ -329,6 +331,9 @@ testsuite_test_hash_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
|
||
|
testsuite_test_array_LDADD = $(TESTSUITE_LDADD)
|
||
|
testsuite_test_array_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
|
||
|
|
||
|
+testsuite_test_scratchbuf_LDADD = $(TESTSUITE_LDADD)
|
||
|
+testsuite_test_scratchbuf_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
|
||
|
+
|
||
|
testsuite_test_strbuf_LDADD = $(TESTSUITE_LDADD)
|
||
|
testsuite_test_strbuf_CPPFLAGS = $(TESTSUITE_CPPFLAGS)
|
||
|
|
||
|
diff --git a/man/depmod.d.xml b/man/depmod.d.xml
|
||
|
index c30c06c5b605..4341a568e8a0 100644
|
||
|
--- a/man/depmod.d.xml
|
||
|
+++ b/man/depmod.d.xml
|
||
|
@@ -75,6 +75,9 @@
|
||
|
first listed directory and the lowest priority given to the last
|
||
|
directory listed. The special keyword <command>built-in</command>
|
||
|
refers to the standard module directories installed by the kernel.
|
||
|
+ Another special keyword <command>external</command> refers to the
|
||
|
+ list of external directories, defined by the
|
||
|
+ <command>external</command> command.
|
||
|
</para>
|
||
|
<para>
|
||
|
By default, depmod will give a higher priority to
|
||
|
@@ -110,6 +113,23 @@
|
||
|
</para>
|
||
|
</listitem>
|
||
|
</varlistentry>
|
||
|
+ <varlistentry>
|
||
|
+ <term>external <replaceable>kernelversion</replaceable>
|
||
|
+ <replaceable>absolutemodulesdirectory...</replaceable>
|
||
|
+ </term>
|
||
|
+ <listitem>
|
||
|
+ <para>
|
||
|
+ This specifies a list of directories, which will be checked
|
||
|
+ according to the priorities in the <command>search</command>
|
||
|
+ command. The order matters also, the first directory has the higher
|
||
|
+ priority.
|
||
|
+ </para>
|
||
|
+ <para>
|
||
|
+ The <replaceable>kernelversion</replaceable> is a POSIX regular
|
||
|
+ expression or * wildcard, like in the <command>override</command>.
|
||
|
+ </para>
|
||
|
+ </listitem>
|
||
|
+ </varlistentry>
|
||
|
</variablelist>
|
||
|
</refsect1>
|
||
|
|
||
|
diff --git a/shared/scratchbuf.c b/shared/scratchbuf.c
|
||
|
new file mode 100644
|
||
|
index 000000000000..8d9eb83f30c1
|
||
|
--- /dev/null
|
||
|
+++ b/shared/scratchbuf.c
|
||
|
@@ -0,0 +1,60 @@
|
||
|
+/*
|
||
|
+ * kmod - interface to kernel module operations
|
||
|
+ *
|
||
|
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
|
||
|
+ *
|
||
|
+ * 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 "scratchbuf.h"
|
||
|
+
|
||
|
+#include <errno.h>
|
||
|
+#include <string.h>
|
||
|
+
|
||
|
+void scratchbuf_init(struct scratchbuf *buf, char *stackbuf, size_t size)
|
||
|
+{
|
||
|
+ buf->bytes = stackbuf;
|
||
|
+ buf->size = size;
|
||
|
+ buf->need_free = false;
|
||
|
+}
|
||
|
+
|
||
|
+int scratchbuf_alloc(struct scratchbuf *buf, size_t size)
|
||
|
+{
|
||
|
+ char *tmp;
|
||
|
+
|
||
|
+ if (size <= buf->size)
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (buf->need_free) {
|
||
|
+ tmp = realloc(buf->bytes, size);
|
||
|
+ if (tmp == NULL)
|
||
|
+ return -ENOMEM;
|
||
|
+ } else {
|
||
|
+ tmp = malloc(size);
|
||
|
+ if (tmp == NULL)
|
||
|
+ return -ENOMEM;
|
||
|
+ memcpy(tmp, buf->bytes, buf->size);
|
||
|
+ }
|
||
|
+
|
||
|
+ buf->size = size;
|
||
|
+ buf->bytes = tmp;
|
||
|
+ buf->need_free = true;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+void scratchbuf_release(struct scratchbuf *buf)
|
||
|
+{
|
||
|
+ if (buf->need_free)
|
||
|
+ free(buf->bytes);
|
||
|
+}
|
||
|
diff --git a/shared/scratchbuf.h b/shared/scratchbuf.h
|
||
|
new file mode 100644
|
||
|
index 000000000000..27ea9d9f6008
|
||
|
--- /dev/null
|
||
|
+++ b/shared/scratchbuf.h
|
||
|
@@ -0,0 +1,31 @@
|
||
|
+#pragma once
|
||
|
+
|
||
|
+#include <stdbool.h>
|
||
|
+#include <stdlib.h>
|
||
|
+
|
||
|
+#include <shared/macro.h>
|
||
|
+
|
||
|
+/*
|
||
|
+ * Buffer abstract data type
|
||
|
+ */
|
||
|
+struct scratchbuf {
|
||
|
+ char *bytes;
|
||
|
+ size_t size;
|
||
|
+ bool need_free;
|
||
|
+};
|
||
|
+
|
||
|
+void scratchbuf_init(struct scratchbuf *buf, char *stackbuf, size_t size);
|
||
|
+int scratchbuf_alloc(struct scratchbuf *buf, size_t sz);
|
||
|
+void scratchbuf_release(struct scratchbuf *buf);
|
||
|
+
|
||
|
+/* Return a C string */
|
||
|
+static inline char *scratchbuf_str(struct scratchbuf *buf)
|
||
|
+{
|
||
|
+ return buf->bytes;
|
||
|
+}
|
||
|
+
|
||
|
+#define SCRATCHBUF_INITIALIZER(buf_) { \
|
||
|
+ .bytes = buf_, \
|
||
|
+ .size = sizeof(buf_) + _array_size_chk(buf_), \
|
||
|
+ .need_free = false, \
|
||
|
+}
|
||
|
diff --git a/testsuite/test-scratchbuf.c b/testsuite/test-scratchbuf.c
|
||
|
new file mode 100644
|
||
|
index 000000000000..6d86957cefb8
|
||
|
--- /dev/null
|
||
|
+++ b/testsuite/test-scratchbuf.c
|
||
|
@@ -0,0 +1,89 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2016 Intel Corporation. All rights reserved.
|
||
|
+ *
|
||
|
+ * This program 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 program 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 <errno.h>
|
||
|
+#include <string.h>
|
||
|
+#include <unistd.h>
|
||
|
+
|
||
|
+#include <shared/scratchbuf.h>
|
||
|
+
|
||
|
+#include "testsuite.h"
|
||
|
+
|
||
|
+static int test_scratchbuf_onlystack(const struct test *t)
|
||
|
+{
|
||
|
+ struct scratchbuf sbuf;
|
||
|
+ const char *smallstr = "xyz";
|
||
|
+ char buf[3 + 2];
|
||
|
+ char buf2[3 + 1];
|
||
|
+
|
||
|
+ scratchbuf_init(&sbuf, buf, sizeof(buf));
|
||
|
+ assert_return(scratchbuf_alloc(&sbuf, strlen(smallstr) + 1) == 0, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.need_free == false, EXIT_FAILURE);
|
||
|
+ scratchbuf_release(&sbuf);
|
||
|
+
|
||
|
+ scratchbuf_init(&sbuf, buf2, sizeof(buf2));
|
||
|
+ assert_return(scratchbuf_alloc(&sbuf, strlen(smallstr) + 1) == 0, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.need_free == false, EXIT_FAILURE);
|
||
|
+ scratchbuf_release(&sbuf);
|
||
|
+
|
||
|
+ memcpy(scratchbuf_str(&sbuf), smallstr, strlen(smallstr) + 1);
|
||
|
+ assert_return(strcmp(scratchbuf_str(&sbuf), smallstr) == 0, EXIT_FAILURE);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+DEFINE_TEST(test_scratchbuf_onlystack,
|
||
|
+ .description = "test scratchbuf for buffer on stack only");
|
||
|
+
|
||
|
+
|
||
|
+static int test_scratchbuf_heap(const struct test *t)
|
||
|
+{
|
||
|
+ struct scratchbuf sbuf;
|
||
|
+ const char *smallstr = "xyz";
|
||
|
+ const char *largestr = "xyzxyzxyz";
|
||
|
+ const char *largestr2 = "xyzxyzxyzxyzxyz";
|
||
|
+ char buf[3 + 1];
|
||
|
+
|
||
|
+ scratchbuf_init(&sbuf, buf, sizeof(buf));
|
||
|
+
|
||
|
+ /* Initially only on stack */
|
||
|
+ assert_return(scratchbuf_alloc(&sbuf, strlen(smallstr) + 1) == 0, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.need_free == false, EXIT_FAILURE);
|
||
|
+ memcpy(scratchbuf_str(&sbuf), smallstr, strlen(smallstr) + 1);
|
||
|
+
|
||
|
+ /* Grow once to heap */
|
||
|
+ assert_return(scratchbuf_alloc(&sbuf, strlen(largestr) + 1) == 0, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.need_free == true, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.size == strlen(largestr) + 1, EXIT_FAILURE);
|
||
|
+ assert_return(strcmp(scratchbuf_str(&sbuf), smallstr) == 0, EXIT_FAILURE);
|
||
|
+ memcpy(scratchbuf_str(&sbuf), largestr, strlen(largestr) + 1);
|
||
|
+ assert_return(strcmp(scratchbuf_str(&sbuf), largestr) == 0, EXIT_FAILURE);
|
||
|
+
|
||
|
+ /* Grow again - realloc should take place */
|
||
|
+ assert_return(scratchbuf_alloc(&sbuf, strlen(largestr2) + 1) == 0, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.need_free == true, EXIT_FAILURE);
|
||
|
+ assert_return(sbuf.size == strlen(largestr2) + 1, EXIT_FAILURE);
|
||
|
+ memcpy(scratchbuf_str(&sbuf), largestr2, strlen(largestr2) + 1);
|
||
|
+ assert_return(strcmp(scratchbuf_str(&sbuf), largestr2) == 0, EXIT_FAILURE);
|
||
|
+
|
||
|
+ scratchbuf_release(&sbuf);
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+DEFINE_TEST(test_scratchbuf_heap,
|
||
|
+ .description = "test scratchbuf for buffer on that grows to heap");
|
||
|
+
|
||
|
+TESTSUITE_MAIN();
|
||
|
diff --git a/testsuite/testsuite.h b/testsuite/testsuite.h
|
||
|
index 3bd74f34ca7e..bb0eb507ac2f 100644
|
||
|
--- a/testsuite/testsuite.h
|
||
|
+++ b/testsuite/testsuite.h
|
||
|
@@ -19,6 +19,7 @@
|
||
|
|
||
|
#include <stdbool.h>
|
||
|
#include <stdarg.h>
|
||
|
+#include <stdio.h>
|
||
|
|
||
|
#include <shared/macro.h>
|
||
|
|
||
|
diff --git a/tools/depmod.c b/tools/depmod.c
|
||
|
index 7b9583249018..79fd14354266 100644
|
||
|
--- a/tools/depmod.c
|
||
|
+++ b/tools/depmod.c
|
||
|
@@ -35,6 +35,7 @@
|
||
|
#include <shared/hash.h>
|
||
|
#include <shared/macro.h>
|
||
|
#include <shared/util.h>
|
||
|
+#include <shared/scratchbuf.h>
|
||
|
|
||
|
#include <libkmod/libkmod.h>
|
||
|
|
||
|
@@ -44,6 +45,7 @@
|
||
|
static int verbose = DEFAULT_VERBOSE;
|
||
|
|
||
|
static const char CFG_BUILTIN_KEY[] = "built-in";
|
||
|
+static const char CFG_EXTERNAL_KEY[] = "external";
|
||
|
static const char *default_cfg_paths[] = {
|
||
|
"/run/depmod.d",
|
||
|
SYSCONFDIR "/depmod.d",
|
||
|
@@ -432,9 +434,21 @@ struct cfg_override {
|
||
|
char path[];
|
||
|
};
|
||
|
|
||
|
+enum search_type {
|
||
|
+ SEARCH_PATH,
|
||
|
+ SEARCH_BUILTIN,
|
||
|
+ SEARCH_EXTERNAL
|
||
|
+};
|
||
|
+
|
||
|
struct cfg_search {
|
||
|
struct cfg_search *next;
|
||
|
- uint8_t builtin;
|
||
|
+ enum search_type type;
|
||
|
+ size_t len;
|
||
|
+ char path[];
|
||
|
+};
|
||
|
+
|
||
|
+struct cfg_external {
|
||
|
+ struct cfg_external *next;
|
||
|
size_t len;
|
||
|
char path[];
|
||
|
};
|
||
|
@@ -449,14 +463,27 @@ struct cfg {
|
||
|
uint8_t warn_dups;
|
||
|
struct cfg_override *overrides;
|
||
|
struct cfg_search *searches;
|
||
|
+ struct cfg_external *externals;
|
||
|
};
|
||
|
|
||
|
-static int cfg_search_add(struct cfg *cfg, const char *path, uint8_t builtin)
|
||
|
+static enum search_type cfg_define_search_type(const char *path)
|
||
|
+{
|
||
|
+ if (streq(path, CFG_BUILTIN_KEY))
|
||
|
+ return SEARCH_BUILTIN;
|
||
|
+ if (streq(path, CFG_EXTERNAL_KEY))
|
||
|
+ return SEARCH_EXTERNAL;
|
||
|
+ return SEARCH_PATH;
|
||
|
+}
|
||
|
+
|
||
|
+static int cfg_search_add(struct cfg *cfg, const char *path)
|
||
|
{
|
||
|
struct cfg_search *s;
|
||
|
size_t len;
|
||
|
+ enum search_type type;
|
||
|
|
||
|
- if (builtin)
|
||
|
+ type = cfg_define_search_type(path);
|
||
|
+
|
||
|
+ if (type != SEARCH_PATH)
|
||
|
len = 0;
|
||
|
else
|
||
|
len = strlen(path) + 1;
|
||
|
@@ -466,15 +493,15 @@ static int cfg_search_add(struct cfg *cfg, const char *path, uint8_t builtin)
|
||
|
ERR("search add: out of memory\n");
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
- s->builtin = builtin;
|
||
|
- if (builtin)
|
||
|
+ s->type = type;
|
||
|
+ if (type != SEARCH_PATH)
|
||
|
s->len = 0;
|
||
|
else {
|
||
|
s->len = len - 1;
|
||
|
memcpy(s->path, path, len);
|
||
|
}
|
||
|
|
||
|
- DBG("search add: %s, builtin=%hhu\n", path, builtin);
|
||
|
+ DBG("search add: %s, search type=%hhu\n", path, type);
|
||
|
|
||
|
s->next = cfg->searches;
|
||
|
cfg->searches = s;
|
||
|
@@ -522,6 +549,32 @@ static void cfg_override_free(struct cfg_override *o)
|
||
|
free(o);
|
||
|
}
|
||
|
|
||
|
+static int cfg_external_add(struct cfg *cfg, const char *path)
|
||
|
+{
|
||
|
+ struct cfg_external *ext;
|
||
|
+ size_t len = strlen(path);
|
||
|
+
|
||
|
+ ext = malloc(sizeof(struct cfg_external) + len + 1);
|
||
|
+ if (ext == NULL) {
|
||
|
+ ERR("external add: out of memory\n");
|
||
|
+ return -ENOMEM;
|
||
|
+ }
|
||
|
+
|
||
|
+ strcpy(ext->path, path);
|
||
|
+ ext->len = len;
|
||
|
+
|
||
|
+ DBG("external add: %s\n", ext->path);
|
||
|
+
|
||
|
+ ext->next = cfg->externals;
|
||
|
+ cfg->externals = ext;
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void cfg_external_free(struct cfg_external *ext)
|
||
|
+{
|
||
|
+ free(ext);
|
||
|
+}
|
||
|
+
|
||
|
static int cfg_kernel_matches(const struct cfg *cfg, const char *pattern)
|
||
|
{
|
||
|
regex_t re;
|
||
|
@@ -567,8 +620,7 @@ static int cfg_file_parse(struct cfg *cfg, const char *filename)
|
||
|
if (streq(cmd, "search")) {
|
||
|
const char *sp;
|
||
|
while ((sp = strtok_r(NULL, "\t ", &saveptr)) != NULL) {
|
||
|
- uint8_t builtin = streq(sp, CFG_BUILTIN_KEY);
|
||
|
- cfg_search_add(cfg, sp, builtin);
|
||
|
+ cfg_search_add(cfg, sp);
|
||
|
}
|
||
|
} else if (streq(cmd, "override")) {
|
||
|
const char *modname = strtok_r(NULL, "\t ", &saveptr);
|
||
|
@@ -586,6 +638,20 @@ static int cfg_file_parse(struct cfg *cfg, const char *filename)
|
||
|
}
|
||
|
|
||
|
cfg_override_add(cfg, modname, subdir);
|
||
|
+ } else if (streq(cmd, "external")) {
|
||
|
+ const char *version = strtok_r(NULL, "\t ", &saveptr);
|
||
|
+ const char *dir = strtok_r(NULL, "\t ", &saveptr);
|
||
|
+
|
||
|
+ if (version == NULL || dir == NULL)
|
||
|
+ goto syntax_error;
|
||
|
+
|
||
|
+ if (!cfg_kernel_matches(cfg, version)) {
|
||
|
+ INF("%s:%u: external directory did not match %s\n",
|
||
|
+ filename, linenum, version);
|
||
|
+ goto done_next;
|
||
|
+ }
|
||
|
+
|
||
|
+ cfg_external_add(cfg, dir);
|
||
|
} else if (streq(cmd, "include")
|
||
|
|| streq(cmd, "make_map_files")) {
|
||
|
INF("%s:%u: command %s not implemented yet\n",
|
||
|
@@ -762,7 +828,7 @@ static int cfg_load(struct cfg *cfg, const char * const *cfg_paths)
|
||
|
* list here. But only if there was no "search" option specified.
|
||
|
*/
|
||
|
if (cfg->searches == NULL)
|
||
|
- cfg_search_add(cfg, "updates", 0);
|
||
|
+ cfg_search_add(cfg, "updates");
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
@@ -780,6 +846,12 @@ static void cfg_free(struct cfg *cfg)
|
||
|
cfg->searches = cfg->searches->next;
|
||
|
cfg_search_free(tmp);
|
||
|
}
|
||
|
+
|
||
|
+ while (cfg->externals) {
|
||
|
+ struct cfg_external *tmp = cfg->externals;
|
||
|
+ cfg->externals = cfg->externals->next;
|
||
|
+ cfg_external_free(tmp);
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
|
||
|
@@ -987,6 +1059,33 @@ static int depmod_module_del(struct depmod *depmod, struct mod *mod)
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
+static const char *search_to_string(const struct cfg_search *s)
|
||
|
+{
|
||
|
+ switch(s->type) {
|
||
|
+ case SEARCH_EXTERNAL:
|
||
|
+ return "external";
|
||
|
+ case SEARCH_BUILTIN:
|
||
|
+ return "built-in";
|
||
|
+ default:
|
||
|
+ return s->path;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static bool depmod_is_path_starts_with(const char *path,
|
||
|
+ size_t pathlen,
|
||
|
+ const char *prefix,
|
||
|
+ size_t prefix_len)
|
||
|
+{
|
||
|
+ if (pathlen <= prefix_len)
|
||
|
+ return false;
|
||
|
+ if (path[prefix_len] != '/')
|
||
|
+ return false;
|
||
|
+ if (memcmp(path, prefix, prefix_len) != 0)
|
||
|
+ return false;
|
||
|
+
|
||
|
+ return true;
|
||
|
+}
|
||
|
+
|
||
|
/* returns if existing module @mod is higher priority than newpath.
|
||
|
* note this is the inverse of module-init-tools is_higher_priority()
|
||
|
*/
|
||
|
@@ -995,6 +1094,7 @@ static int depmod_module_is_higher_priority(const struct depmod *depmod, const s
|
||
|
const struct cfg *cfg = depmod->cfg;
|
||
|
const struct cfg_override *ov;
|
||
|
const struct cfg_search *se;
|
||
|
+ const struct cfg_external *ext;
|
||
|
|
||
|
/* baselen includes the last '/' and mod->baselen doesn't. So it's
|
||
|
* actually correct to use modnamelen in the first and modnamesz in
|
||
|
@@ -1003,35 +1103,55 @@ static int depmod_module_is_higher_priority(const struct depmod *depmod, const s
|
||
|
size_t oldlen = mod->baselen + mod->modnamesz;
|
||
|
const char *oldpath = mod->path;
|
||
|
int i, bprio = -1, oldprio = -1, newprio = -1;
|
||
|
-
|
||
|
- assert(strncmp(newpath, cfg->dirname, cfg->dirnamelen) == 0);
|
||
|
- assert(strncmp(oldpath, cfg->dirname, cfg->dirnamelen) == 0);
|
||
|
-
|
||
|
- newpath += cfg->dirnamelen + 1;
|
||
|
- newlen -= cfg->dirnamelen + 1;
|
||
|
- oldpath += cfg->dirnamelen + 1;
|
||
|
- oldlen -= cfg->dirnamelen + 1;
|
||
|
+ size_t relnewlen = 0;
|
||
|
+ size_t reloldlen = 0;
|
||
|
+ const char *relnewpath = NULL;
|
||
|
+ const char *reloldpath = NULL;
|
||
|
|
||
|
DBG("comparing priorities of %s and %s\n",
|
||
|
oldpath, newpath);
|
||
|
|
||
|
+ if (strncmp(newpath, cfg->dirname, cfg->dirnamelen) == 0) {
|
||
|
+ relnewpath = newpath + cfg->dirnamelen + 1;
|
||
|
+ relnewlen = newlen - cfg->dirnamelen + 1;
|
||
|
+ }
|
||
|
+ if (strncmp(oldpath, cfg->dirname, cfg->dirnamelen) == 0) {
|
||
|
+ reloldpath = oldpath + cfg->dirnamelen + 1;
|
||
|
+ reloldlen = oldlen - cfg->dirnamelen + 1;
|
||
|
+ }
|
||
|
+
|
||
|
for (ov = cfg->overrides; ov != NULL; ov = ov->next) {
|
||
|
DBG("override %s\n", ov->path);
|
||
|
- if (newlen == ov->len && memcmp(ov->path, newpath, newlen) == 0)
|
||
|
+ if (relnewlen == ov->len &&
|
||
|
+ memcmp(ov->path, relnewpath, relnewlen) == 0)
|
||
|
return 0;
|
||
|
- if (oldlen == ov->len && memcmp(ov->path, oldpath, oldlen) == 0)
|
||
|
+ if (reloldlen == ov->len &&
|
||
|
+ memcmp(ov->path, reloldpath, reloldlen) == 0)
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
for (i = 0, se = cfg->searches; se != NULL; se = se->next, i++) {
|
||
|
- DBG("search %s\n", se->builtin ? "built-in" : se->path);
|
||
|
- if (se->builtin)
|
||
|
+ DBG("search %s\n", search_to_string(se));
|
||
|
+ if (se->type == SEARCH_BUILTIN)
|
||
|
bprio = i;
|
||
|
- else if (newlen > se->len && newpath[se->len] == '/' &&
|
||
|
- memcmp(se->path, newpath, se->len) == 0)
|
||
|
+ else if (se->type == SEARCH_EXTERNAL) {
|
||
|
+ for (ext = cfg->externals; ext != NULL; ext = ext->next, i++) {
|
||
|
+ if (depmod_is_path_starts_with(newpath,
|
||
|
+ newlen,
|
||
|
+ ext->path,
|
||
|
+ ext->len))
|
||
|
+ newprio = i;
|
||
|
+ if (depmod_is_path_starts_with(oldpath,
|
||
|
+ oldlen,
|
||
|
+ ext->path,
|
||
|
+ ext->len))
|
||
|
+ oldprio = i;
|
||
|
+ }
|
||
|
+ } else if (relnewlen > se->len && relnewpath[se->len] == '/' &&
|
||
|
+ memcmp(se->path, relnewpath, se->len) == 0)
|
||
|
newprio = i;
|
||
|
- else if (oldlen > se->len && oldpath[se->len] == '/' &&
|
||
|
- memcmp(se->path, oldpath, se->len) == 0)
|
||
|
+ else if (reloldlen > se->len && reloldpath[se->len] == '/' &&
|
||
|
+ memcmp(se->path, reloldpath, se->len) == 0)
|
||
|
oldprio = i;
|
||
|
}
|
||
|
|
||
|
@@ -1102,10 +1222,11 @@ add:
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
-static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t baselen, char *path)
|
||
|
+static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t baselen, struct scratchbuf *s_path)
|
||
|
{
|
||
|
struct dirent *de;
|
||
|
int err = 0, dfd = dirfd(d);
|
||
|
+ char *path;
|
||
|
|
||
|
while ((de = readdir(d)) != NULL) {
|
||
|
const char *name = de->d_name;
|
||
|
@@ -1118,11 +1239,13 @@ static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t basel
|
||
|
if (streq(name, "build") || streq(name, "source"))
|
||
|
continue;
|
||
|
namelen = strlen(name);
|
||
|
- if (baselen + namelen + 2 >= PATH_MAX) {
|
||
|
- path[baselen] = '\0';
|
||
|
- ERR("path is too long %s%s\n", path, name);
|
||
|
+ if (scratchbuf_alloc(s_path, baselen + namelen + 2) < 0) {
|
||
|
+ err = -ENOMEM;
|
||
|
+ ERR("No memory\n");
|
||
|
continue;
|
||
|
}
|
||
|
+
|
||
|
+ path = scratchbuf_str(s_path);
|
||
|
memcpy(path + baselen, name, namelen + 1);
|
||
|
|
||
|
if (de->d_type == DT_REG)
|
||
|
@@ -1148,10 +1271,6 @@ static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t basel
|
||
|
if (is_dir) {
|
||
|
int fd;
|
||
|
DIR *subdir;
|
||
|
- if (baselen + namelen + 2 + NAME_MAX >= PATH_MAX) {
|
||
|
- ERR("directory path is too long %s\n", path);
|
||
|
- continue;
|
||
|
- }
|
||
|
fd = openat(dfd, name, O_RDONLY);
|
||
|
if (fd < 0) {
|
||
|
ERR("openat(%d, %s, O_RDONLY): %m\n",
|
||
|
@@ -1168,7 +1287,7 @@ static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t basel
|
||
|
path[baselen + namelen + 1] = '\0';
|
||
|
err = depmod_modules_search_dir(depmod, subdir,
|
||
|
baselen + namelen + 1,
|
||
|
- path);
|
||
|
+ s_path);
|
||
|
closedir(subdir);
|
||
|
} else {
|
||
|
err = depmod_modules_search_file(depmod, baselen,
|
||
|
@@ -1181,33 +1300,65 @@ static int depmod_modules_search_dir(struct depmod *depmod, DIR *d, size_t basel
|
||
|
err = 0; /* ignore errors */
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-static int depmod_modules_search(struct depmod *depmod)
|
||
|
+static int depmod_modules_search_path(struct depmod *depmod,
|
||
|
+ const char *path)
|
||
|
{
|
||
|
- char path[PATH_MAX];
|
||
|
- DIR *d = opendir(depmod->cfg->dirname);
|
||
|
+ char buf[256];
|
||
|
+ _cleanup_(scratchbuf_release) struct scratchbuf s_path_buf =
|
||
|
+ SCRATCHBUF_INITIALIZER(buf);
|
||
|
+ char *path_buf;
|
||
|
+ DIR *d;
|
||
|
size_t baselen;
|
||
|
int err;
|
||
|
+
|
||
|
+ d = opendir(path);
|
||
|
if (d == NULL) {
|
||
|
err = -errno;
|
||
|
- ERR("could not open directory %s: %m\n", depmod->cfg->dirname);
|
||
|
+ ERR("could not open directory %s: %m\n", path);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
- baselen = depmod->cfg->dirnamelen;
|
||
|
- memcpy(path, depmod->cfg->dirname, baselen);
|
||
|
- path[baselen] = '/';
|
||
|
+ baselen = strlen(path);
|
||
|
+
|
||
|
+ if (scratchbuf_alloc(&s_path_buf, baselen + 2) < 0) {
|
||
|
+ err = -ENOMEM;
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ path_buf = scratchbuf_str(&s_path_buf);
|
||
|
+
|
||
|
+ memcpy(path_buf, path, baselen);
|
||
|
+ path_buf[baselen] = '/';
|
||
|
baselen++;
|
||
|
- path[baselen] = '\0';
|
||
|
+ path_buf[baselen] = '\0';
|
||
|
|
||
|
- err = depmod_modules_search_dir(depmod, d, baselen, path);
|
||
|
+ err = depmod_modules_search_dir(depmod, d, baselen, &s_path_buf);
|
||
|
+out:
|
||
|
closedir(d);
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
+static int depmod_modules_search(struct depmod *depmod)
|
||
|
+{
|
||
|
+ int err;
|
||
|
+ struct cfg_external *ext;
|
||
|
+
|
||
|
+ err = depmod_modules_search_path(depmod, depmod->cfg->dirname);
|
||
|
+ if (err < 0)
|
||
|
+ return err;
|
||
|
+
|
||
|
+ for (ext = depmod->cfg->externals; ext != NULL; ext = ext->next) {
|
||
|
+ err = depmod_modules_search_path(depmod, ext->path);
|
||
|
+ if (err < 0 && err == -ENOENT)
|
||
|
+ /* ignore external dir absense */
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
static int mod_cmp(const void *pa, const void *pb) {
|
||
|
const struct mod *a = *(const struct mod **)pa;
|
||
|
const struct mod *b = *(const struct mod **)pb;
|
||
|
--
|
||
|
2.14.1
|
||
|
|
||
|
--- kmod-20/man/depmod.d.5.orig 2017-08-17 16:01:34.330058135 +0300
|
||
|
+++ kmod-20/man/depmod.d.5 2017-08-17 16:01:37.901058086 +0300
|
||
|
@@ -1,13 +1,13 @@
|
||
|
'\" t
|
||
|
.\" Title: depmod.d
|
||
|
.\" Author: Jon Masters <jcm@jonmasters.org>
|
||
|
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||
|
-.\" Date: 03/01/2015
|
||
|
+.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||
|
+.\" Date: 08/17/2017
|
||
|
.\" Manual: depmod.d
|
||
|
.\" Source: kmod
|
||
|
.\" Language: English
|
||
|
.\"
|
||
|
-.TH "DEPMOD\&.D" "5" "03/01/2015" "kmod" "depmod.d"
|
||
|
+.TH "DEPMOD\&.D" "5" "08/17/2017" "kmod" "depmod.d"
|
||
|
.\" -----------------------------------------------------------------
|
||
|
.\" * Define some portability stuff
|
||
|
.\" -----------------------------------------------------------------
|
||
|
@@ -52,7 +52,11 @@
|
||
|
This allows you to specify the order in which /lib/modules (or other configured module location) subdirectories will be processed by
|
||
|
\fBdepmod\fR\&. Directories are listed in order, with the highest priority given to the first listed directory and the lowest priority given to the last directory listed\&. The special keyword
|
||
|
\fBbuilt\-in\fR
|
||
|
-refers to the standard module directories installed by the kernel\&.
|
||
|
+refers to the standard module directories installed by the kernel\&. Another special keyword
|
||
|
+\fBexternal\fR
|
||
|
+refers to the list of external directories, defined by the
|
||
|
+\fBexternal\fR
|
||
|
+command\&.
|
||
|
.sp
|
||
|
By default, depmod will give a higher priority to a directory with the name
|
||
|
\fBupdates\fR
|
||
|
@@ -73,6 +77,18 @@
|
||
|
\fBextra\fR
|
||
|
subdirectory within /lib/modules (or other module location) will take priority over any likenamed module already provided by the kernel\&.
|
||
|
.RE
|
||
|
+.PP
|
||
|
+external \fIkernelversion\fR \fIabsolutemodulesdirectory\&.\&.\&.\fR
|
||
|
+.RS 4
|
||
|
+This specifies a list of directories, which will be checked according to the priorities in the
|
||
|
+\fBsearch\fR
|
||
|
+command\&. The order matters also, the first directory has the higher priority\&.
|
||
|
+.sp
|
||
|
+The
|
||
|
+\fIkernelversion\fR
|
||
|
+is a POSIX regular expression or * wildcard, like in the
|
||
|
+\fBoverride\fR\&.
|
||
|
+.RE
|
||
|
.SH "COPYRIGHT"
|
||
|
.PP
|
||
|
This manual page Copyright 2006\-2010, Jon Masters, Red Hat, Inc\&.
|