diff --git a/namedev.c b/namedev.c index 23d46518ea..1e424998f6 100644 --- a/namedev.c +++ b/namedev.c @@ -46,6 +46,7 @@ static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *c LIST_HEAD(config_device_list); LIST_HEAD(perm_device_list); + /* compare string with pattern (supports * ? [0-9] [!A-Z]) */ static int strcmp_pattern(const char *p, const char *s) { @@ -99,39 +100,6 @@ static int strcmp_pattern(const char *p, const char *s) return 1; } -#define copy_var(a, b, var) \ - if (b->var) \ - a->var = b->var; - -#define copy_string(a, b, var) \ - if (strlen(b->var)) \ - strcpy(a->var, b->var); - -int add_perm_dev(struct perm_device *new_dev) -{ - struct perm_device *dev; - struct perm_device *tmp_dev; - - /* update the values if we already have the device */ - list_for_each_entry(dev, &perm_device_list, node) { - if (strcmp(new_dev->name, dev->name)) - continue; - copy_var(dev, new_dev, mode); - copy_string(dev, new_dev, owner); - copy_string(dev, new_dev, group); - return 0; - } - - /* not found, add new structure to the perm list */ - tmp_dev = malloc(sizeof(*tmp_dev)); - if (!tmp_dev) - return -ENOMEM; - memcpy(tmp_dev, new_dev, sizeof(*tmp_dev)); - list_add_tail(&tmp_dev->node, &perm_device_list); - //dump_perm_dev(tmp_dev); - return 0; -} - static struct perm_device *find_perm(char *name) { struct perm_device *perm; @@ -865,22 +833,28 @@ int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *ud goto done; found: - /* substitute placeholder */ apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device); udev->partitions = dev->partitions; + done: + /* get permissions given in rule */ + set_empty_perms(udev, dev->mode, + dev->owner, + dev->group); + + /* get permissions given in config file or set defaults */ perm = find_perm(udev->name); - if (perm) { - udev->mode = perm->mode; - strfieldcpy(udev->owner, perm->owner); - strfieldcpy(udev->group, perm->group); + if (perm != NULL) { + set_empty_perms(udev, perm->mode, + perm->owner, + perm->group); } else { - /* no matching perms found :( */ - udev->mode = get_default_mode(); - strfieldcpy(udev->owner, get_default_owner()); - strfieldcpy(udev->group, get_default_group()); + set_empty_perms(udev, get_default_mode(), + get_default_owner(), + get_default_group()); } + dbg("name, '%s' is going to have owner='%s', group='%s', mode = %#o", udev->name, udev->owner, udev->group, udev->mode); diff --git a/namedev.h b/namedev.h index 7f875ed603..16a8bffe97 100644 --- a/namedev.h +++ b/namedev.h @@ -44,6 +44,9 @@ struct sysfs_class_device; #define FIELD_KERNEL "KERNEL" #define FIELD_NAME "NAME" #define FIELD_SYMLINK "SYMLINK" +#define FIELD_OWNER "OWNER" +#define FIELD_GROUP "GROUP" +#define FIELD_MODE "MODE" #define ATTR_PARTITIONS "all_partitions" #define PARTITIONS_COUNT 15 @@ -54,6 +57,14 @@ struct sysfs_class_device; #define RULEFILE_EXT ".rules" #define PERMFILE_EXT ".permissions" +#define set_empty_perms(dev, m, o, g) \ + if (dev->mode == 0) \ + dev->mode = m; \ + if (dev->owner[0] == '\0') \ + strfieldcpy(dev->owner, o); \ + if (dev->group[0] == '\0') \ + strfieldcpy(dev->group, g); + struct sysfs_pair { char file[FILE_SIZE]; char value[VALUE_SIZE]; @@ -71,6 +82,9 @@ struct config_device { char name[NAME_SIZE]; char symlink[NAME_SIZE]; struct sysfs_pair sysfs_pair[MAX_SYSFS_PAIRS]; + char owner[OWNER_SIZE]; + char group[GROUP_SIZE]; + unsigned int mode; int partitions; char config_file[NAME_SIZE]; int config_line; @@ -93,7 +107,6 @@ extern int namedev_name_device(struct sysfs_class_device *class_dev, struct udev extern int namedev_init_permissions(void); extern int namedev_init_rules(void); -extern int add_perm_dev(struct perm_device *new_dev); extern void dump_config_dev(struct config_device *dev); extern void dump_config_dev_list(void); extern void dump_perm_dev(struct perm_device *dev); diff --git a/namedev_parse.c b/namedev_parse.c index defb698b26..fba32a4983 100644 --- a/namedev_parse.c +++ b/namedev_parse.c @@ -43,6 +43,7 @@ LIST_HEAD(file_list); + static int add_config_dev(struct config_device *new_dev) { struct config_device *tmp_dev; @@ -61,9 +62,11 @@ void dump_config_dev(struct config_device *dev) dbg_parse("name='%s', symlink='%s', bus='%s', place='%s', id='%s', " "sysfs_file[0]='%s', sysfs_value[0]='%s', " "kernel='%s', program='%s', result='%s'", + "owner='%s', group='%s', mode=%#o", dev->name, dev->symlink, dev->bus, dev->place, dev->id, dev->sysfs_pair[0].file, dev->sysfs_pair[0].value, - dev->kernel, dev->program, dev->result); + dev->kernel, dev->program, dev->result,; + dev->owner, dev->group, dev->mode); } void dump_config_dev_list(void) @@ -74,6 +77,31 @@ void dump_config_dev_list(void) dump_config_dev(dev); } +static int add_perm_dev(struct perm_device *new_dev) +{ + struct perm_device *dev; + struct perm_device *tmp_dev; + + /* update the values if we already have the device */ + list_for_each_entry(dev, &perm_device_list, node) { + if (strcmp(new_dev->name, dev->name) != 0) + continue; + + set_empty_perms(dev, new_dev->mode, new_dev->owner, new_dev->group); + return 0; + } + + /* not found, add new structure to the perm list */ + tmp_dev = malloc(sizeof(*tmp_dev)); + if (!tmp_dev) + return -ENOMEM; + + memcpy(tmp_dev, new_dev, sizeof(*tmp_dev)); + list_add_tail(&tmp_dev->node, &perm_device_list); + //dump_perm_dev(tmp_dev); + return 0; +} + void dump_perm_dev(struct perm_device *dev) { dbg_parse("name='%s', owner='%s', group='%s', mode=%#o", @@ -240,12 +268,26 @@ static int namedev_parse_rules(char *filename) continue; } + if (strcasecmp(temp2, FIELD_OWNER) == 0) { + strfieldcpy(dev.owner, temp3); + continue; + } + + if (strcasecmp(temp2, FIELD_GROUP) == 0) { + strfieldcpy(dev.group, temp3); + continue; + } + + if (strcasecmp(temp2, FIELD_MODE) == 0) { + dev.mode = strtol(temp3, NULL, 8); + continue; + } + dbg("unknown type of field '%s'", temp2); - dbg("You might be using a rules file in the old format, please fix."); goto error; } - /* simple plausibility check for given keys */ + /* simple plausibility checks for given keys */ if ((dev.sysfs_pair[0].file[0] == '\0') ^ (dev.sysfs_pair[0].value[0] == '\0')) { dbg("inconsistency in " FIELD_SYSFS " key"); @@ -336,14 +378,14 @@ static int namedev_parse_permissions(char *filename) strfieldcpy(dev.group, temp2); if (!temp) { - dbg("cannot parse line: %s", line); + dbg("cannot parse line '%s'", line); continue; } dev.mode = strtol(temp, NULL, 8); dbg_parse("name='%s', owner='%s', group='%s', mode=%#o", - dev.name, dev.owner, dev.group, - dev.mode); + dev.name, dev.owner, dev.group, dev.mode); + retval = add_perm_dev(&dev); if (retval) { dbg("add_perm_dev returned with error %d", retval); diff --git a/udev.8 b/udev.8 index 8ebcf7bd99..d5d9549113 100644 --- a/udev.8 +++ b/udev.8 @@ -220,6 +220,10 @@ to the symlink list of the rule which will create the node. This makes it possible to specify additional symlinks in a possibly separate rules file, while the device nodes are maintained by the distribution provided rules file. +.TP +.B OWNER, GROUP, MODE +The permissions for this device. Every specified value overwrites the value +given in the permissions file. .P .RB "The " NAME " ," SYMLINK " and " PROGRAM fields support simple printf-like string substitution: