]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
Add support for parsing config files
authorLucas De Marchi <lucas.demarchi@profusion.mobi>
Tue, 29 Nov 2011 20:07:43 +0000 (18:07 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Tue, 29 Nov 2011 20:07:43 +0000 (18:07 -0200)
Right now only alias keyword is treated.

Makefile.am
libkmod/libkmod-config.c [new file with mode: 0644]
libkmod/libkmod-private.h
libkmod/libkmod.c

index 9da04547916c2de43cd842ace6382096c4a80ad9..f17270fb0c2cf50e44b82669ed9e43ad0c211b06 100644 (file)
@@ -33,6 +33,7 @@ libkmod_libkmod_la_SOURCES =\
        libkmod/libkmod.c \
        libkmod/libkmod-list.c \
        libkmod/libkmod-loaded.c \
+       libkmod/libkmod-config.c \
        libkmod/libkmod-util.c \
        libkmod/libkmod-module.c
 
diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c
new file mode 100644 (file)
index 0000000..9cc024c
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * libkmod - interface to kernel module operations
+ *
+ * Copyright (C) 2011  ProFUSION embedded systems
+ *
+ * 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 version 2.1.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#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 <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "libkmod.h"
+#include "libkmod-private.h"
+
+static const char *config_files[] = {
+       "/run/modprobe.d",
+       "/etc/modprobe.d",
+       "/usr/local/lib/modprobe",
+       "/lib/modprobe.d",
+};
+
+struct kmod_alias {
+       char *name;
+       char *modname;
+};
+
+static struct kmod_list *add_alias(struct kmod_ctx *ctx,
+                                       struct kmod_list *aliases,
+                                       const char *name, const char *modname)
+{
+       struct kmod_alias *alias;
+
+       DBG(ctx, "name=%s modname=%s\n", name, modname);
+
+       alias = malloc(sizeof(*alias));
+       alias->name = strdup(name);
+       alias->modname = strdup(modname);
+
+       return kmod_list_append(aliases, alias);
+}
+
+static struct kmod_list *free_alias(struct kmod_ctx *ctx, struct kmod_list *l)
+{
+       struct kmod_alias *alias = l->data;
+
+       free(alias->modname);
+       free(alias->name);
+       free(alias);
+
+       return kmod_list_remove(l);
+}
+
+int kmod_parse_config_file(struct kmod_ctx *ctx, const char *filename,
+                                               struct kmod_config *config)
+{
+       char *line;
+       FILE *fp;
+       unsigned int linenum;
+
+       DBG(ctx, "%s\n", filename);
+
+       fp = fopen(filename, "r");
+       if (fp == NULL)
+               return errno;
+
+       while ((line = getline_wrapped(fp, &linenum)) != NULL) {
+               char *cmd;
+
+               if (line[0] == '\0' || line[0] == '#')
+                       goto done_next;
+
+               cmd = strtok(line, "\t ");
+               if (cmd == NULL)
+                       goto done_next;
+
+               if (!strcmp(cmd, "alias")) {
+                       char *alias = strtok(NULL, "\t ");
+                       char *modname = strtok(NULL, "\t ");
+
+                       if (alias == NULL || modname == NULL)
+                               goto syntax_error;
+
+                       config->aliases = add_alias(ctx, config->aliases,
+                                                       alias, modname);
+               } else if (!strcmp(cmd, "include") || !strcmp(cmd, "options")
+                               || !strcmp(cmd, "install")
+                               || !strcmp(cmd, "blacklist")
+                               || !strcmp(cmd, "remove")
+                               || !strcmp(cmd, "softdep")
+                               || !strcmp(cmd, "config")) {
+                       DBG(ctx, "Command %s not implemented yet\n", cmd);
+               } else {
+syntax_error:
+                       ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n",
+                                               filename, linenum, cmd);
+               }
+
+done_next:
+               free(line);
+       }
+
+       fclose(fp);
+
+       return 0;
+}
+
+void kmod_free_config(struct kmod_ctx *ctx, struct kmod_config *config)
+{
+       while (config->aliases)
+               config->aliases =  free_alias(ctx, config->aliases);
+}
+
+static bool conf_files_filter(struct kmod_ctx *ctx, const char *path,
+                                                       const char *fn)
+{
+       size_t len = strlen(fn);
+
+       if (fn[0] == '.')
+               return 1;
+
+       if (len < 6 || (strcmp(&fn[len - 5], ".conf") != 0
+                               && strcmp(&fn[len - 6], ".alias"))) {
+               INFO(ctx, "All config files need .conf: %s/%s, "
+                               "it will be ignored in a future release\n",
+                               path, fn);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list,
+                                               const char *path, size_t *n)
+{
+       struct stat st;
+       DIR *d;
+       int err;
+
+       if (stat(path, &st) < 0)
+               return -ENOENT;
+
+       if (!S_ISDIR(st.st_mode)) {
+               *list = kmod_list_append(*list, (void *)path);
+               *n += 1;
+               return 0;
+       }
+
+       d = opendir(path);
+       if (d == NULL) {
+               err = errno;
+               ERR(ctx, "%m\n");
+               return -errno;
+       }
+
+       for (;;) {
+               struct dirent ent, *entp;
+               char *p;
+
+               err = readdir_r(d, &ent, &entp);
+               if (err != 0) {
+                       err = -err;
+                       goto finish;
+               }
+
+               if (entp == NULL)
+                       break;
+
+               if (conf_files_filter(ctx, path, entp->d_name) == 1)
+                       continue;
+
+               if (asprintf(&p, "%s/%s", path, entp->d_name) < 0) {
+                       err = -ENOMEM;
+                       goto finish;
+               }
+
+               DBG(ctx, "%s\n", p);
+
+               *list = kmod_list_append(*list, p);
+               *n += 1;
+       }
+
+finish:
+       closedir(d);
+       return err;
+}
+
+static int base_cmp(const void *a, const void *b)
+{
+        const char *s1, *s2;
+
+        s1 = *(char * const *)a;
+        s2 = *(char * const *)b;
+
+       return strcmp(basename(s1), basename(s2));
+}
+
+int kmod_parse_config(struct kmod_ctx *ctx, struct kmod_config *config)
+{
+
+       size_t i, n = 0;
+       char **files = NULL;
+       int err = 0;
+       struct kmod_list *list = NULL, *l;
+
+       for (i = 0; i < ARRAY_SIZE(config_files); i++)
+               conf_files_list(ctx, &list, config_files[i], &n);
+
+       files = malloc(sizeof(char *) * n);
+       if (files == NULL) {
+               err = -ENOMEM;
+               goto finish;
+       }
+
+       i = 0;
+       kmod_list_foreach(l, list) {
+               files[i] = l->data;
+               i++;
+       }
+
+       qsort(files, n, sizeof(char *), base_cmp);
+
+       for (i = 0; i < n; i++)
+               kmod_parse_config_file(ctx, files[i], config);
+
+finish:
+       free(files);
+
+       while (list) {
+               free(list->data);
+               list = kmod_list_remove(list);
+       }
+
+       return err;
+}
index b22896dc845b2b07bfbf240c9fd25dcd213ca67e..a32d73a4d86dc4cd56e62bf7c2ba7df76fe200c3 100644 (file)
@@ -54,6 +54,13 @@ struct kmod_list *kmod_list_remove_data(struct kmod_list *list,
 
 const char *kmod_get_dirname(struct kmod_ctx *ctx) __attribute__((nonnull(1)));
 
+struct kmod_config {
+       struct kmod_list *aliases;
+};
+int kmod_parse_config_file(struct kmod_ctx *ctx, const char *filename, struct kmod_config *config);
+int kmod_parse_config(struct kmod_ctx *ctx, struct kmod_config *config);
+void kmod_free_config(struct kmod_ctx *ctx, struct kmod_config *config);
+
 char *getline_wrapped(FILE *fp, unsigned int *linenum);
 
 #endif
index cfc6cb86f341f09d5c623ae1476d699553001098..56b4d3c9db48cfdc63c45473b52027663511143c 100644 (file)
@@ -51,6 +51,7 @@ struct kmod_ctx {
        void *userdata;
        const char *dirname;
        int log_priority;
+       struct kmod_config config;
 };
 
 void kmod_log(struct kmod_ctx *ctx,
@@ -168,6 +169,8 @@ KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname)
        if (env != NULL)
                kmod_set_log_priority(ctx, log_priority(env));
 
+       kmod_parse_config(ctx, &ctx->config);
+
        INFO(ctx, "ctx %p created\n", ctx);
        DBG(ctx, "log_priority=%d\n", ctx->log_priority);
 
@@ -207,6 +210,7 @@ KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
                return ctx;
        INFO(ctx, "context %p released\n", ctx);
        free((char *)ctx->dirname);
+       kmod_free_config(ctx, &ctx->config);
        free(ctx);
        return NULL;
 }