* 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, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
#include <inttypes.h>
#include <limits.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/types.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include <sys/mman.h>
+#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/types.h>
#include <sys/wait.h>
-#include <fnmatch.h>
-
#ifdef HAVE_LINUX_MODULE_H
#include <linux/module.h>
#endif
+#include <shared/util.h>
+
#include "libkmod.h"
#include "libkmod-internal.h"
* @short_description: operate on kernel modules
*/
+enum kmod_module_builtin {
+ KMOD_MODULE_BUILTIN_UNKNOWN,
+ KMOD_MODULE_BUILTIN_NO,
+ KMOD_MODULE_BUILTIN_YES,
+};
+
/**
* kmod_module:
*
bool remove_commands : 1;
} init;
+ /*
+ * mark if module is builtin, i.e. it's present on modules.builtin
+ * file. This is set as soon as it is needed or as soon as we know
+ * about it, i.e. the module was created from builtin lookup.
+ */
+ enum kmod_module_builtin builtin;
+
/*
* private field used by kmod_module_get_probe_list() to detect
* dependency loops
bool ignorecmd : 1;
/*
- * if module was created by searching the modules.builtin file, this
- * is set. There's nothing much useful one can do with such a
- * "module", except knowing it's builtin.
+ * set by kmod_module_get_probe_list: indicates whether this is the
+ * module the user asked for or its dependency, or whether this
+ * is a softdep only
*/
- bool builtin : 1;
+ bool required : 1;
};
static inline const char *path_join(const char *path, size_t prefixlen,
p++;
for (p = strtok_r(p, " \t", &saveptr); p != NULL;
p = strtok_r(NULL, " \t", &saveptr)) {
- struct kmod_module *depmod;
+ struct kmod_module *depmod = NULL;
const char *path;
path = path_join(p, dirnamelen, buf);
void kmod_module_set_builtin(struct kmod_module *mod, bool builtin)
{
- mod->builtin = builtin;
+ mod->builtin =
+ builtin ? KMOD_MODULE_BUILTIN_YES : KMOD_MODULE_BUILTIN_NO;
+}
+
+void kmod_module_set_required(struct kmod_module *mod, bool required)
+{
+ mod->required = required;
}
+bool kmod_module_is_builtin(struct kmod_module *mod)
+{
+ if (mod->builtin == KMOD_MODULE_BUILTIN_UNKNOWN) {
+ kmod_module_set_builtin(mod,
+ kmod_lookup_alias_is_builtin(mod->ctx, mod->name));
+ }
+
+ return mod->builtin == KMOD_MODULE_BUILTIN_YES;
+}
/*
* Memory layout with alias:
*
}
err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m);
- if (err < 0)
+ if (err < 0) {
+ free(abspath);
return err;
+ }
m->path = abspath;
*mod = m;
int err;
const void *mem;
off_t size;
- struct kmod_file *file;
- struct kmod_elf *elf = NULL;
+ struct kmod_elf *elf;
const char *path;
const char *args = options ? options : "";
path = kmod_module_get_path(mod);
if (path == NULL) {
ERR(mod->ctx, "could not find module by name='%s'\n", mod->name);
- return -ENOSYS;
+ return -ENOENT;
}
- file = kmod_file_open(mod->ctx, path);
- if (file == NULL) {
+ mod->file = kmod_file_open(mod->ctx, path);
+ if (mod->file == NULL) {
err = -errno;
return err;
}
- if (kmod_file_get_direct(file)) {
+ if (kmod_file_get_direct(mod->file)) {
unsigned int kernel_flags = 0;
if (flags & KMOD_INSERT_FORCE_VERMAGIC)
if (flags & KMOD_INSERT_FORCE_MODVERSION)
kernel_flags |= MODULE_INIT_IGNORE_MODVERSIONS;
- err = finit_module(kmod_file_get_fd(file), args, kernel_flags);
+ err = finit_module(kmod_file_get_fd(mod->file), args, kernel_flags);
if (err == 0 || errno != ENOSYS)
goto init_finished;
}
- size = kmod_file_get_size(file);
- mem = kmod_file_get_contents(file);
-
if (flags & (KMOD_INSERT_FORCE_VERMAGIC | KMOD_INSERT_FORCE_MODVERSION)) {
- elf = kmod_elf_new(mem, size);
+ elf = kmod_file_get_elf(mod->file);
if (elf == NULL) {
err = -errno;
- goto elf_failed;
+ return err;
}
if (flags & KMOD_INSERT_FORCE_MODVERSION) {
}
mem = kmod_elf_get_memory(elf);
+ } else {
+ mem = kmod_file_get_contents(mod->file);
}
+ size = kmod_file_get_size(mod->file);
err = init_module(mem, size, args);
init_finished:
err = -errno;
INFO(mod->ctx, "Failed to insert module '%s': %m\n", path);
}
-
- if (elf != NULL)
- kmod_elf_unref(elf);
-elf_failed:
- kmod_file_unref(file);
-
return err;
}
module_is_blacklisted(mod))
continue;
- if ((filter_type & KMOD_FILTER_BUILTIN) && mod->builtin)
+ if ((filter_type & KMOD_FILTER_BUILTIN)
+ && kmod_module_is_builtin(mod))
continue;
node = kmod_list_append(*output, mod);
}
static int __kmod_module_get_probe_list(struct kmod_module *mod,
+ bool required,
bool ignorecmd,
struct kmod_list **list);
kmod_list_foreach(l, pre) {
struct kmod_module *m = l->data;
- err = __kmod_module_get_probe_list(m, false, list);
+ err = __kmod_module_get_probe_list(m, false, false, list);
if (err < 0)
goto fail;
}
kmod_list_foreach(l, post) {
struct kmod_module *m = l->data;
- err = __kmod_module_get_probe_list(m, false, list);
+ err = __kmod_module_get_probe_list(m, false, false, list);
if (err < 0)
goto fail;
}
/* re-entrant */
static int __kmod_module_get_probe_list(struct kmod_module *mod,
+ bool required,
bool ignorecmd,
struct kmod_list **list)
{
mod->visited = true;
dep = kmod_module_get_dependencies(mod);
+ if (required) {
+ /*
+ * Called from kmod_module_probe_insert_module(); set the
+ * ->required flag on mod and all its dependencies before
+ * they are possibly visited through some softdeps.
+ */
+ mod->required = true;
+ kmod_list_foreach(l, dep) {
+ struct kmod_module *m = l->data;
+ m->required = true;
+ }
+ }
+
kmod_list_foreach(l, dep) {
struct kmod_module *m = l->data;
err = __kmod_module_fill_softdep(m, list);
* Make sure we don't get screwed by previous calls to this function
*/
kmod_set_modules_visited(mod->ctx, false);
+ kmod_set_modules_required(mod->ctx, false);
- err = __kmod_module_get_probe_list(mod, ignorecmd, list);
+ err = __kmod_module_get_probe_list(mod, true, ignorecmd, list);
if (err < 0) {
kmod_module_unref_list(*list);
*list = NULL;
(flags & KMOD_PROBE_FAIL_ON_LOADED))
break;
- if (err == -EEXIST)
+ /*
+ * Ignore errors from softdeps
+ */
+ if (err == -EEXIST || !m->required)
err = 0;
+
else if (err < 0)
break;
}
struct kmod_module *m;
struct kmod_list *node;
int err;
+ size_t len = strlen(line);
char *saveptr, *name = strtok_r(line, " \t", &saveptr);
err = kmod_module_new_from_name(ctx, name, &m);
if (err < 0) {
ERR(ctx, "could not get module from name '%s': %s\n",
name, strerror(-err));
- continue;
+ goto eat_line;
}
node = kmod_list_append(l, m);
ERR(ctx, "out of memory\n");
kmod_module_unref(m);
}
+eat_line:
+ while (line[len - 1] != '\n' && fgets(line, sizeof(line), fp))
+ len = strlen(line);
}
fclose(fp);
if (mod == NULL)
return -ENOENT;
- if (mod->builtin)
+ /* remove const: this can only change internal state */
+ if (kmod_module_is_builtin((struct kmod_module *)mod))
return KMOD_MODULE_BUILTIN;
pathlen = snprintf(path, sizeof(path),
struct stat st;
path[pathlen - (sizeof("/initstate") - 1)] = '\0';
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
- return KMOD_MODULE_BUILTIN;
+ return KMOD_MODULE_COMING;
}
DBG(mod->ctx, "could not open '%s': %s\n",
* loaded.
*/
snprintf(line, sizeof(line), "/sys/module/%s", mod->name);
- dfd = open(line, O_RDONLY);
+ dfd = open(line, O_RDONLY|O_CLOEXEC);
if (dfd < 0)
return -errno;
int err = -errno;
ERR(mod->ctx,
"could not open /proc/modules: %s\n", strerror(errno));
+ close(dfd);
return err;
}
while (fgets(line, sizeof(line), fp)) {
+ size_t len = strlen(line);
char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
long value;
lineno++;
if (tok == NULL || !streq(tok, mod->name))
- continue;
+ goto eat_line;
tok = strtok_r(NULL, " \t", &saveptr);
if (tok == NULL) {
size = value;
break;
+eat_line:
+ while (line[len - 1] != '\n' && fgets(line, sizeof(line), fp))
+ len = strlen(line);
}
fclose(fp);
* Get the ref count of this @mod, as returned by Linux Kernel, by reading
* /sys filesystem.
*
- * Returns: 0 on success or < 0 on failure.
+ * Returns: the reference count on success or < 0 on failure.
*/
KMOD_EXPORT int kmod_module_get_refcnt(const struct kmod_module *mod)
{
struct kmod_list *n;
char *key_hex;
- n = kmod_module_info_append(list, "signer", strlen("signer"),
- sig_info.signer, sig_info.signer_len);
+ n = kmod_module_info_append(list, "signature", strlen("sig_id"),
+ sig_info.id_type, strlen(sig_info.id_type));
if (n == NULL)
goto list_error;
count++;
- /* Display the key id as 01:12:DE:AD:BE:EF:... */
- key_hex = malloc(sig_info.key_id_len * 3);
- if (key_hex == NULL)
- goto list_error;
- for (i = 0; i < (int)sig_info.key_id_len; i++) {
- sprintf(key_hex + i * 3, "%02X",
- (unsigned char)sig_info.key_id[i]);
- if (i < (int)sig_info.key_id_len - 1)
- key_hex[i * 3 + 2] = ':';
- }
- n = kmod_module_info_append(list, "sig_key", strlen("sig_key"),
- key_hex, sig_info.key_id_len * 3 - 1);
- free(key_hex);
+ n = kmod_module_info_append(list, "signer", strlen("signer"),
+ sig_info.signer, sig_info.signer_len);
if (n == NULL)
goto list_error;
count++;
+ if (sig_info.key_id_len) {
+ /* Display the key id as 01:12:DE:AD:BE:EF:... */
+ key_hex = malloc(sig_info.key_id_len * 3);
+ if (key_hex == NULL)
+ goto list_error;
+ for (i = 0; i < (int)sig_info.key_id_len; i++) {
+ sprintf(key_hex + i * 3, "%02X",
+ (unsigned char)sig_info.key_id[i]);
+ if (i < (int)sig_info.key_id_len - 1)
+ key_hex[i * 3 + 2] = ':';
+ }
+ n = kmod_module_info_append(list, "sig_key", strlen("sig_key"),
+ key_hex, sig_info.key_id_len * 3 - 1);
+ free(key_hex);
+ if (n == NULL)
+ goto list_error;
+ count++;
+ } else {
+ n = kmod_module_info_append(list, "sig_key", strlen("sig_key"),
+ NULL, 0);
+ if (n == NULL)
+ goto list_error;
+ count++;
+ }
+
n = kmod_module_info_append(list,
"sig_hashalgo", strlen("sig_hashalgo"),
sig_info.hash_algo, strlen(sig_info.hash_algo));
count++;
/*
- * Omit sig_info.id_type and sig_info.algo for now, as these
+ * Omit sig_info.algo for now, as these
* are currently constant.
*/
}