6 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation version 2 of the License.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* define this to enable parsing debugging */
25 /* #define DEBUG_PARSER */
39 #include "udev_version.h"
41 #include "libsysfs/libsysfs.h"
43 #define TYPE_LABEL "LABEL"
44 #define TYPE_NUMBER "NUMBER"
45 #define TYPE_TOPOLOGY "TOPOLOGY"
46 #define TYPE_REPLACE "REPLACE"
47 #define TYPE_CALLOUT "CALLOUT"
49 static LIST_HEAD(config_device_list);
51 static void dump_dev(struct config_device *dev)
55 dbg_parse("KERNEL name='%s' ,"
56 "owner='%s', group='%s', mode=%#o",
57 dev->name, dev->owner, dev->group, dev->mode);
60 dbg_parse("LABEL name='%s', bus='%s', sysfs_file='%s', sysfs_value='%s', "
61 "owner='%s', group='%s', mode=%#o",
62 dev->name, dev->bus, dev->sysfs_file, dev->sysfs_value,
63 dev->owner, dev->group, dev->mode);
66 dbg_parse("NUMBER name='%s', bus='%s', id='%s', "
67 "owner='%s', group='%s', mode=%#o",
68 dev->name, dev->bus, dev->id,
69 dev->owner, dev->group, dev->mode);
72 dbg_parse("TOPOLOGY name='%s', bus='%s', place='%s', "
73 "owner='%s', group='%s', mode=%#o",
74 dev->name, dev->bus, dev->place,
75 dev->owner, dev->group, dev->mode);
78 dbg_parse("REPLACE name=%s, kernel_name=%s, "
79 "owner='%s', group='%s', mode=%#o",
80 dev->name, dev->kernel_name,
81 dev->owner, dev->group, dev->mode);
84 dbg_parse("CALLOUT name='%s', program='%s', bus='%s', id='%s', "
85 "owner='%s', group='%s', mode=%#o",
86 dev->name, dev->exec_program, dev->bus, dev->id,
87 dev->owner, dev->group, dev->mode);
90 dbg_parse("unknown type of method");
94 #define copy_var(a, b, var) \
98 #define copy_string(a, b, var) \
100 strcpy(a->var, b->var);
102 static int add_dev(struct config_device *new_dev)
104 struct list_head *tmp;
105 struct config_device *tmp_dev;
107 /* update the values if we already have the device */
108 list_for_each(tmp, &config_device_list) {
109 struct config_device *dev = list_entry(tmp, struct config_device, node);
110 int len = strlen(new_dev->name);
111 if (new_dev->name[len-1] == '*') {
113 if (strncmp(dev->name, new_dev->name, len))
116 if (strcmp(dev->name, new_dev->name))
119 /* the same, copy the new info into this structure */
120 copy_var(dev, new_dev, type);
121 copy_var(dev, new_dev, mode);
122 copy_string(dev, new_dev, bus);
123 copy_string(dev, new_dev, sysfs_file);
124 copy_string(dev, new_dev, sysfs_value);
125 copy_string(dev, new_dev, id);
126 copy_string(dev, new_dev, place);
127 copy_string(dev, new_dev, kernel_name);
128 copy_string(dev, new_dev, owner);
129 copy_string(dev, new_dev, group);
133 /* not found, add new structure to the device list */
134 tmp_dev = malloc(sizeof(*tmp_dev));
137 memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
138 list_add(&tmp_dev->node, &config_device_list);
143 static void dump_dev_list(void)
145 struct list_head *tmp;
147 list_for_each(tmp, &config_device_list) {
148 struct config_device *dev = list_entry(tmp, struct config_device, node);
153 static int get_pair(char **orig_string, char **left, char **right)
156 char *string = *orig_string;
161 /* eat any whitespace */
162 while (isspace(*string))
165 /* split based on '=' */
166 temp = strsep(&string, "=");
171 /* take the right side and strip off the '"' */
172 while (isspace(*string))
179 temp = strsep(&string, "\"");
180 if (!string || *temp == '\0')
183 *orig_string = string;
188 static int get_value(const char *left, char **orig_string, char **ret_string)
193 retval = get_pair(orig_string, &left_string, ret_string);
196 if (strcasecmp(left_string, left) != 0)
201 static int namedev_init_config(void)
210 struct config_device dev;
212 dbg("opening %s to read as config", udev_config_filename);
213 fd = fopen(udev_config_filename, "r");
215 dbg("can't open %s", udev_config_filename);
219 /* loop through the whole file */
223 temp = fgets(line, sizeof(line), fd);
228 dbg_parse("read %s", temp);
230 /* eat the whitespace at the beginning of the line */
231 while (isspace(*temp))
238 /* see if this is a comment */
239 if (*temp == COMMENT_CHARACTER)
242 memset(&dev, 0x00, sizeof(struct config_device));
245 temp2 = strsep(&temp, ",");
246 if (strcasecmp(temp2, TYPE_LABEL) == 0) {
251 retval = get_value("BUS", &temp, &temp3);
254 strfieldcpy(dev.bus, temp3);
257 temp2 = strsep(&temp, ",");
258 retval = get_pair(&temp, &temp2, &temp3);
261 strfieldcpy(dev.sysfs_file, temp2);
262 strfieldcpy(dev.sysfs_value, temp3);
264 /* NAME="new_name" */
265 temp2 = strsep(&temp, ",");
266 retval = get_value("NAME", &temp, &temp3);
269 strfieldcpy(dev.name, temp3);
271 dbg_parse("LABEL name='%s', bus='%s', "
272 "sysfs_file='%s', sysfs_value='%s'",
273 dev.name, dev.bus, dev.sysfs_file,
277 if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
282 retval = get_value("BUS", &temp, &temp3);
285 strfieldcpy(dev.bus, temp3);
288 temp2 = strsep(&temp, ",");
289 retval = get_value("id", &temp, &temp3);
292 strfieldcpy(dev.id, temp3);
294 /* NAME="new_name" */
295 temp2 = strsep(&temp, ",");
296 retval = get_value("NAME", &temp, &temp3);
299 strfieldcpy(dev.name, temp3);
301 dbg_parse("NUMBER name='%s', bus='%s', id='%s'",
302 dev.name, dev.bus, dev.id);
305 if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
310 retval = get_value("BUS", &temp, &temp3);
313 strfieldcpy(dev.bus, temp3);
316 temp2 = strsep(&temp, ",");
317 retval = get_value("place", &temp, &temp3);
320 strfieldcpy(dev.place, temp3);
322 /* NAME="new_name" */
323 temp2 = strsep(&temp, ",");
324 retval = get_value("NAME", &temp, &temp3);
327 strfieldcpy(dev.name, temp3);
329 dbg_parse("TOPOLOGY name='%s', bus='%s', place='%s'",
330 dev.name, dev.bus, dev.place);
333 if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
337 /* KERNEL="kernel_name" */
338 retval = get_value("KERNEL", &temp, &temp3);
341 strfieldcpy(dev.kernel_name, temp3);
343 /* NAME="new_name" */
344 temp2 = strsep(&temp, ",");
345 retval = get_value("NAME", &temp, &temp3);
348 strfieldcpy(dev.name, temp3);
349 dbg_parse("REPLACE name='%s', kernel_name='%s'",
350 dev.name, dev.kernel_name);
352 if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
356 /* PROGRAM="executable" */
357 retval = get_value("PROGRAM", &temp, &temp3);
360 strfieldcpy(dev.exec_program, temp3);
363 temp2 = strsep(&temp, ",");
364 retval = get_value("BUS", &temp, &temp3);
367 strfieldcpy(dev.bus, temp3);
370 temp2 = strsep(&temp, ",");
371 retval = get_value("ID", &temp, &temp3);
374 strfieldcpy(dev.id, temp3);
376 /* NAME="new_name" */
377 temp2 = strsep(&temp, ",");
378 retval = get_value("NAME", &temp, &temp3);
381 strfieldcpy(dev.name, temp3);
382 dbg_parse("CALLOUT name='%s', program='%s'",
383 dev.name, dev.exec_program);
386 retval = add_dev(&dev);
388 dbg("add_dev returned with error %d", retval);
392 dbg_parse("%s:%d:%Zd: error parsing '%s'", udev_config_filename,
393 lineno, temp - line, temp);
400 static int namedev_init_permissions(void)
407 struct config_device dev;
409 dbg("opening %s to read as permissions config", udev_config_permission_filename);
410 fd = fopen(udev_config_permission_filename, "r");
412 dbg("can't open %s", udev_config_permission_filename);
416 /* loop through the whole file */
419 temp = fgets(line, sizeof(line), fd);
423 dbg_parse("read %s", temp);
425 /* eat the whitespace at the beginning of the line */
426 while (isspace(*temp))
433 /* see if this is a comment */
434 if (*temp == COMMENT_CHARACTER)
437 memset(&dev, 0x00, sizeof(dev));
440 temp2 = strsep(&temp, ":");
441 strncpy(dev.name, temp2, sizeof(dev.name));
443 temp2 = strsep(&temp, ":");
444 strncpy(dev.owner, temp2, sizeof(dev.owner));
446 temp2 = strsep(&temp, ":");
447 strncpy(dev.group, temp2, sizeof(dev.owner));
449 dev.mode = strtol(temp, NULL, 8);
451 dbg_parse("name='%s', owner='%s', group='%s', mode=%#o",
452 dev.name, dev.owner, dev.group,
454 retval = add_dev(&dev);
456 dbg("add_dev returned with error %d", retval);
466 static mode_t get_default_mode(struct sysfs_class_device *class_dev)
468 /* just default everyone to rw for the world! */
473 static int exec_callout(struct config_device *dev, char *value, int len)
483 dbg("callout to '%s'", dev->exec_program);
497 close(STDOUT_FILENO);
498 dup(fds[1]); /* dup write side of pipe to STDOUT */
499 retval = execve(dev->exec_program, main_argv, main_envp);
501 dbg("child execve failed");
504 return -1; /* avoid compiler warning */
506 /* parent reads from fds[0] */
510 res = read(fds[0], buffer, sizeof(buffer) - 1);
515 dbg("callout len %d too short\n", len);
519 dbg("callout value already set");
523 strncpy(value, buffer, len);
529 dbg("wait failed result %d", res);
534 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
535 dbg("callout program status 0x%x", status);
543 static int do_callout(struct sysfs_class_device *class_dev, struct udevice *udev)
545 struct config_device *dev;
546 struct list_head *tmp;
549 list_for_each(tmp, &config_device_list) {
550 dev = list_entry(tmp, struct config_device, node);
551 if (dev->type != CALLOUT)
554 if (exec_callout(dev, value, sizeof(value)))
556 if (strncmp(value, dev->id, sizeof(value)) != 0)
558 strfieldcpy(udev->name, dev->name);
559 if (dev->mode != 0) {
560 udev->mode = dev->mode;
561 strfieldcpy(udev->owner, dev->owner);
562 strfieldcpy(udev->group, dev->group);
564 dbg_parse("callout returned matching value '%s', '%s' becomes '%s'"
565 " - owner='%s', group='%s', mode =%#o",
566 dev->id, class_dev->name, udev->name,
567 dev->owner, dev->group, dev->mode);
573 static int do_label(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
575 struct sysfs_attribute *tmpattr = NULL;
576 struct config_device *dev;
577 struct list_head *tmp;
579 list_for_each(tmp, &config_device_list) {
580 dev = list_entry(tmp, struct config_device, node);
581 if (dev->type != LABEL)
584 dbg_parse("look for device attribute '%s'", dev->sysfs_file);
585 /* try to find the attribute in the class device directory */
586 tmpattr = sysfs_get_classdev_attr(class_dev, dev->sysfs_file);
590 /* look in the class device directory if present */
592 tmpattr = sysfs_get_device_attr(sysfs_device, dev->sysfs_file);
600 tmpattr->value[strlen(tmpattr->value)-1] = 0x00;
601 dbg_parse("compare attribute '%s' value '%s' with '%s'",
602 dev->sysfs_file, tmpattr->value, dev->sysfs_value);
603 if (strcmp(dev->sysfs_value, tmpattr->value) != 0)
606 strfieldcpy(udev->name, dev->name);
607 if (dev->mode != 0) {
608 udev->mode = dev->mode;
609 strfieldcpy(udev->owner, dev->owner);
610 strfieldcpy(udev->group, dev->group);
612 dbg_parse("found matching attribute '%s', '%s' becomes '%s' "
613 "- owner='%s', group='%s', mode=%#o",
614 dev->sysfs_file, class_dev->name, udev->name,
615 dev->owner, dev->group, dev->mode);
622 static int do_number(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
624 struct config_device *dev;
625 struct list_head *tmp;
626 char path[SYSFS_PATH_MAX];
630 /* we have to have a sysfs device for NUMBER to work */
634 list_for_each(tmp, &config_device_list) {
635 dev = list_entry(tmp, struct config_device, node);
636 if (dev->type != NUMBER)
640 strfieldcpy(path, sysfs_device->path);
641 temp = strrchr(path, '/');
642 dbg_parse("search '%s' in '%s', path='%s'", dev->id, temp, path);
643 if (strstr(temp, dev->id) != NULL) {
647 temp = strrchr(path, '/');
648 dbg_parse("search '%s' in '%s', path='%s'", dev->id, temp, path);
649 if (strstr(temp, dev->id) != NULL)
654 strfieldcpy(udev->name, dev->name);
655 if (dev->mode != 0) {
656 udev->mode = dev->mode;
657 strfieldcpy(udev->owner, dev->owner);
658 strfieldcpy(udev->group, dev->group);
660 dbg_parse("found matching id '%s', '%s' becomes '%s'"
661 " - owner='%s', group ='%s', mode=%#o",
662 dev->id, class_dev->name, udev->name,
663 dev->owner, dev->group, dev->mode);
670 static int do_topology(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
672 struct config_device *dev;
673 struct list_head *tmp;
674 char path[SYSFS_PATH_MAX];
678 /* we have to have a sysfs device for TOPOLOGY to work */
682 list_for_each(tmp, &config_device_list) {
683 dev = list_entry(tmp, struct config_device, node);
684 if (dev->type != TOPOLOGY)
688 strfieldcpy(path, sysfs_device->path);
689 temp = strrchr(path, '/');
690 dbg_parse("search '%s' in '%s', path='%s'", dev->place, temp, path);
691 if (strstr(temp, dev->place) != NULL) {
695 temp = strrchr(path, '/');
696 dbg_parse("search '%s' in '%s', path='%s'", dev->place, temp, path);
697 if (strstr(temp, dev->place) != NULL)
703 strfieldcpy(udev->name, dev->name);
704 if (dev->mode != 0) {
705 udev->mode = dev->mode;
706 strfieldcpy(udev->owner, dev->owner);
707 strfieldcpy(udev->group, dev->group);
709 dbg_parse("found matching place '%s', '%s' becomes '%s'"
710 " - owner='%s', group ='%s', mode=%#o",
711 dev->place, class_dev->name, udev->name,
712 dev->owner, dev->group, dev->mode);
718 static int do_replace(struct sysfs_class_device *class_dev, struct udevice *udev)
720 struct config_device *dev;
721 struct list_head *tmp;
723 list_for_each(tmp, &config_device_list) {
724 dev = list_entry(tmp, struct config_device, node);
725 if (dev->type != REPLACE)
728 dbg_parse("compare name '%s' with '%s'",
729 dev->kernel_name, dev->name);
730 if (strcmp(dev->kernel_name, class_dev->name) != 0)
733 strfieldcpy(udev->name, dev->name);
734 if (dev->mode != 0) {
735 udev->mode = dev->mode;
736 strfieldcpy(udev->owner, dev->owner);
737 strfieldcpy(udev->group, dev->group);
739 dbg_parse("found name, '%s' becomes '%s' - owner='%s', group='%s', mode = %#o",
740 dev->kernel_name, udev->name,
741 dev->owner, dev->group, dev->mode);
748 static void do_kernelname(struct sysfs_class_device *class_dev, struct udevice *udev)
750 struct config_device *dev;
751 struct list_head *tmp;
754 strfieldcpy(udev->name, class_dev->name);
755 list_for_each(tmp, &config_device_list) {
756 dev = list_entry(tmp, struct config_device, node);
757 len = strlen(dev->name);
758 if (dev->name[len-1] == '*') {
760 if (strncmp(dev->name, class_dev->name, len))
763 if (strcmp(dev->name, class_dev->name))
766 if (dev->mode != 0) {
767 dbg_parse("found permissions for '%s'", class_dev->name);
768 udev->mode = dev->mode;
769 strfieldcpy(udev->owner, dev->owner);
770 strfieldcpy(udev->group, dev->group);
775 static int get_attr(struct sysfs_class_device *class_dev, struct udevice *udev)
777 struct sysfs_device *sysfs_device = NULL;
778 struct sysfs_class_device *class_dev_parent = NULL;
784 /* find the sysfs_device for this class device */
785 /* Wouldn't it really be nice if libsysfs could do this for us? */
786 if (class_dev->sysdevice) {
787 sysfs_device = class_dev->sysdevice;
789 /* bah, let's go backwards up a level to see if the device is there,
790 * as block partitions don't point to the physical device. Need to fix that
791 * up in the kernel...
793 if (strstr(class_dev->path, "block")) {
794 dbg_parse("looking at block device...");
795 if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
796 char path[SYSFS_PATH_MAX];
798 dbg_parse("really is a partition...");
799 strfieldcpy(path, class_dev->path);
800 temp = strrchr(path, '/');
802 dbg_parse("looking for a class device at '%s'", path);
803 class_dev_parent = sysfs_open_class_device(path);
804 if (class_dev_parent == NULL) {
805 dbg("sysfs_open_class_device at '%s' failed", path);
807 dbg_parse("class_dev_parent->name=%s", class_dev_parent->name);
808 if (class_dev_parent->sysdevice)
809 sysfs_device = class_dev_parent->sysdevice;
816 dbg_parse("sysfs_device->path='%s'", sysfs_device->path);
817 dbg_parse("sysfs_device->bus_id='%s'", sysfs_device->bus_id);
819 dbg_parse("class_dev->name = '%s'", class_dev->name);
822 /* rules are looked at in priority order */
823 retval = do_callout(class_dev, udev);
827 retval = do_label(class_dev, udev, sysfs_device);
831 retval = do_number(class_dev, udev, sysfs_device);
835 retval = do_topology(class_dev, udev, sysfs_device);
839 retval = do_replace(class_dev, udev);
843 do_kernelname(class_dev, udev);
847 /* substitute placeholder in NAME */
849 char *pos = strchr(udev->name, '%');
851 char name[NAME_SIZE];
853 strfieldcpy(name, pos+2);
859 strcat(udev->name, sysfs_device->bus_id);
860 dbg("bus_id inserted: %s",
861 sysfs_device->bus_id);
864 dig = class_dev->name + strlen(class_dev->name);
865 while (isdigit(*(dig-1)))
867 strcat(udev->name, dig);
868 dbg("substitute kernel number '%s'", dig);
871 sprintf(pos, "%u", udev->minor);
872 dbg("substitute minor number '%u'", udev->minor);
875 sprintf(pos, "%u", udev->major);
876 dbg("substitute major number '%u'", udev->major);
879 dbg("unknown substitution type '%%%c'", pos[1]);
882 strcat(udev->name, name);
888 /* mode was never set above */
890 udev->mode = get_default_mode(class_dev);
891 udev->owner[0] = 0x00;
892 udev->group[0] = 0x00;
895 if (class_dev_parent)
896 sysfs_close_class_device(class_dev_parent);
901 int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *dev)
905 retval = get_attr(class_dev, dev);
907 dbg("get_attr failed");
912 int namedev_init(void)
916 retval = namedev_init_config();
920 retval = namedev_init_permissions();