summaryrefslogtreecommitdiff
path: root/namedev.c
diff options
context:
space:
mode:
Diffstat (limited to 'namedev.c')
-rw-r--r--namedev.c345
1 files changed, 345 insertions, 0 deletions
diff --git a/namedev.c b/namedev.c
new file mode 100644
index 0000000000..ee122cf075
--- /dev/null
+++ b/namedev.c
@@ -0,0 +1,345 @@
+/*
+ * namedev.c
+ *
+ * Userspace devfs
+ *
+ * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation version 2 of the License.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "list.h"
+#include "udev.h"
+#include "udev_version.h"
+#include "namedev.h"
+
+#define TYPE_LABEL "LABEL"
+#define TYPE_NUMBER "NUMBER"
+#define TYPE_TOPOLOGY "TOPOLOGY"
+#define TYPE_REPLACE "REPLACE"
+
+enum config_type {
+ KERNEL_NAME = 0, /* must be 0 to let memset() default to this value */
+ LABEL = 1,
+ NUMBER = 2,
+ TOPOLOGY = 3,
+ REPLACE = 4,
+};
+
+#define BUS_SIZE 30
+#define FILE_SIZE 50
+#define VALUE_SIZE 100
+#define ID_SIZE 50
+#define PLACE_SIZE 50
+#define NAME_SIZE 100
+#define OWNER_SIZE 30
+#define GROUP_SIZE 30
+
+
+struct config_device {
+ struct list_head node;
+
+ enum config_type type;
+
+ char bus[BUS_SIZE];
+ char sysfs_file[FILE_SIZE];
+ char sysfs_value[VALUE_SIZE];
+ char id[ID_SIZE];
+ char place[PLACE_SIZE];
+ char kernel_name[NAME_SIZE];
+
+ /* what to set the device to */
+ int mode;
+ char name[NAME_SIZE];
+ char owner[OWNER_SIZE];
+ char group[GROUP_SIZE];
+};
+
+
+static LIST_HEAD(config_device_list);
+
+#define copy_var(a, b, var) \
+ if (b->var) \
+ b->var = a->var;
+
+#define copy_string(a, b, var) \
+ if (strlen(b->var)) \
+ strcpy(b->var, a->var);
+
+static int add_dev(struct config_device *new_dev)
+{
+ struct list_head *tmp;
+ struct config_device *tmp_dev;
+
+ /* loop through the whole list of devices to see if we already have
+ * this one... */
+ list_for_each(tmp, &config_device_list) {
+ struct config_device *dev = list_entry(tmp, struct config_device, node);
+ if (strcmp(dev->name, new_dev->name) == 0) {
+ /* the same, copy the new info into this structure */
+ copy_var(new_dev, dev, type);
+ copy_var(new_dev, dev, mode);
+ copy_string(new_dev, dev, bus);
+ copy_string(new_dev, dev, sysfs_file);
+ copy_string(new_dev, dev, sysfs_value);
+ copy_string(new_dev, dev, id);
+ copy_string(new_dev, dev, place);
+ copy_string(new_dev, dev, kernel_name);
+ copy_string(new_dev, dev, owner);
+ copy_string(new_dev, dev, group);
+ return 0;
+ }
+ }
+
+ /* not found, lets create a new structure, and add it to the list */
+ tmp_dev = malloc(sizeof(*tmp_dev));
+ if (!tmp_dev)
+ return -ENOMEM;
+ memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
+ list_add(&tmp_dev->node, &config_device_list);
+ return 0;
+}
+
+static int get_value(const char *left, char **orig_string, char **ret_string)
+{
+ char *temp;
+ char *string = *orig_string;
+
+ /* eat any whitespace */
+ while (isspace(*string))
+ ++string;
+
+ /* split based on '=' */
+ temp = strsep(&string, "=");
+ if (strcasecmp(temp, left) == 0) {
+ /* got it, now strip off the '"' */
+ while (isspace(*string))
+ ++string;
+ if (*string == '"')
+ ++string;
+ temp = strsep(&string, "\"");
+ *ret_string = temp;
+ *orig_string = string;
+ return 0;
+ }
+ return -ENODEV;
+}
+
+
+static int namedev_init_config(void)
+{
+ char filename[255];
+ char line[255];
+ char *temp;
+ char *temp2;
+ char *temp3;
+ FILE *fd;
+ int retval = 0;
+ struct config_device dev;
+
+ strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_FILE);
+ dbg("opening %s to read as permissions config", filename);
+ fd = fopen(filename, "r");
+ if (fd == NULL) {
+ dbg("Can't open %s", filename);
+ return -ENODEV;
+ }
+
+ /* loop through the whole file */
+ while (1) {
+ /* get a line */
+ temp = fgets(line, sizeof(line), fd);
+ if (temp == NULL)
+ break;
+
+ dbg("read %s", temp);
+
+ /* eat the whitespace at the beginning of the line */
+ while (isspace(*temp))
+ ++temp;
+
+ /* no more line? */
+ if (*temp == 0x00)
+ continue;
+
+ /* see if this is a comment */
+ if (*temp == COMMENT_CHARACTER)
+ continue;
+
+ memset(&dev, 0x00, sizeof(dev));
+
+ /* parse the line */
+ temp2 = strsep(&temp, ",");
+ if (strcasecmp(temp2, TYPE_LABEL) == 0) {
+ /* label type */
+ dev.type = LABEL;
+
+ /* BUS="bus" */
+ retval = get_value("BUS", &temp, &temp3);
+ if (retval)
+ continue;
+ strcpy(dev.bus, temp3);
+ dbg("LABEL name = %s, bus = %s", dev.name, dev.bus);
+ }
+
+ if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
+ /* number type */
+ dev.type = NUMBER;
+
+ /* BUS="bus" */
+ retval = get_value("BUS", &temp, &temp3);
+ if (retval)
+ continue;
+ strcpy(dev.bus, temp3);
+ dbg("NUMBER name = %s, bus = %s", dev.name, dev.bus);
+ }
+
+ if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
+ /* number type */
+ dev.type = TOPOLOGY;
+
+ /* BUS="bus" */
+ retval = get_value("BUS", &temp, &temp3);
+ if (retval)
+ continue;
+ strcpy(dev.bus, temp3);
+ dbg("TOPOLOGY name = %s, bus = %s", dev.name, dev.bus);
+ }
+
+ if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
+ /* number type */
+ dev.type = REPLACE;
+
+ /* KERNEL="kernel_name" */
+ retval = get_value("KERNEL", &temp, &temp3);
+ if (retval)
+ continue;
+ strcpy(dev.kernel_name, temp3);
+
+ /* NAME="new_name" */
+ temp2 = strsep(&temp, ",");
+ retval = get_value("NAME", &temp, &temp3);
+ if (retval)
+ continue;
+ strcpy(dev.name, temp3);
+ dbg("REPLACE name = %s, kernel_name = %s", dev.name, dev.kernel_name);
+ }
+
+ retval = add_dev(&dev);
+ if (retval) {
+ dbg("add_dev returned with error %d", retval);
+ goto exit;
+ }
+ }
+
+exit:
+ fclose(fd);
+ return retval;
+}
+
+
+static int namedev_init_permissions(void)
+{
+ char filename[255];
+ char line[255];
+ char *temp;
+ char *temp2;
+ FILE *fd;
+ int retval = 0;
+ struct config_device dev;
+
+ strcpy(filename, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_PERMISSION_FILE);
+ dbg("opening %s to read as permissions config", filename);
+ fd = fopen(filename, "r");
+ if (fd == NULL) {
+ dbg("Can't open %s", filename);
+ return -ENODEV;
+ }
+
+ /* loop through the whole file */
+ while (1) {
+ /* get a line */
+ temp = fgets(line, sizeof(line), fd);
+ if (temp == NULL)
+ break;
+
+ dbg("read %s", temp);
+
+ /* eat the whitespace at the beginning of the line */
+ while (isspace(*temp))
+ ++temp;
+
+ /* no more line? */
+ if (*temp == 0x00)
+ continue;
+
+ /* see if this is a comment */
+ if (*temp == COMMENT_CHARACTER)
+ continue;
+
+ memset(&dev, 0x00, sizeof(dev));
+
+ /* parse the line */
+ temp2 = strsep(&temp, ":");
+ strncpy(dev.name, temp2, sizeof(dev.name));
+
+ temp2 = strsep(&temp, ":");
+ strncpy(dev.owner, temp2, sizeof(dev.owner));
+
+ temp2 = strsep(&temp, ":");
+ strncpy(dev.group, temp2, sizeof(dev.owner));
+
+ dev.mode = strtol(temp, NULL, 8);
+
+ dbg("name = %s, owner = %s, group = %s, mode = %x", dev.name, dev.owner, dev.group, dev.mode);
+ retval = add_dev(&dev);
+ if (retval) {
+ dbg("add_dev returned with error %d", retval);
+ goto exit;
+ }
+ }
+
+exit:
+ fclose(fd);
+ return retval;
+}
+
+
+
+int namedev_init(void)
+{
+ int retval;
+
+ retval = namedev_init_config();
+ if (retval)
+ return retval;
+
+ retval = namedev_init_permissions();
+ if (retval)
+ return retval;
+
+ return retval;
+}
+