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.
36 #include "udev_version.h"
38 #include "libsysfs/libsysfs.h"
39 #include "klibc_fixups.h"
41 LIST_HEAD(config_device_list
);
42 LIST_HEAD(perm_device_list
);
44 /* compare string with pattern (supports * ? [0-9] [!A-Z]) */
45 static int strcmp_pattern(const char *p
, const char *s
)
61 while (*p
&& (*p
!= ']')) {
64 if ((*s
>= *p
) && (*s
<= p
[2]))
72 while (*p
&& (*p
!= ']'))
74 return strcmp_pattern(p
+1, s
+1);
80 if (strcmp_pattern(p
, s
+1))
81 return strcmp_pattern(p
+1, s
);
89 if ((*p
== *s
) || (*p
== '?'))
90 return strcmp_pattern(p
+1, s
+1);
96 #define copy_var(a, b, var) \
100 #define copy_string(a, b, var) \
101 if (strlen(b->var)) \
102 strcpy(a->var, b->var);
104 int add_config_dev(struct config_device
*new_dev
)
106 struct list_head
*tmp
;
107 struct config_device
*tmp_dev
;
109 /* update the values if we already have the device */
110 list_for_each(tmp
, &config_device_list
) {
111 struct config_device
*dev
= list_entry(tmp
, struct config_device
, node
);
112 if (strcmp_pattern(new_dev
->name
, dev
->name
))
114 if (strncmp(dev
->bus
, new_dev
->bus
, sizeof(dev
->name
)))
116 copy_var(dev
, new_dev
, type
);
117 copy_string(dev
, new_dev
, bus
);
118 copy_string(dev
, new_dev
, sysfs_file
);
119 copy_string(dev
, new_dev
, sysfs_value
);
120 copy_string(dev
, new_dev
, id
);
121 copy_string(dev
, new_dev
, place
);
122 copy_string(dev
, new_dev
, kernel_name
);
123 copy_string(dev
, new_dev
, exec_program
);
124 copy_string(dev
, new_dev
, symlink
);
128 /* not found, add new structure to the device list */
129 tmp_dev
= malloc(sizeof(*tmp_dev
));
132 memcpy(tmp_dev
, new_dev
, sizeof(*tmp_dev
));
133 list_add_tail(&tmp_dev
->node
, &config_device_list
);
134 //dump_config_dev(tmp_dev);
138 int add_perm_dev(struct perm_device
*new_dev
)
140 struct list_head
*tmp
;
141 struct perm_device
*tmp_dev
;
143 /* update the values if we already have the device */
144 list_for_each(tmp
, &perm_device_list
) {
145 struct perm_device
*dev
= list_entry(tmp
, struct perm_device
, node
);
146 if (strcmp_pattern(new_dev
->name
, dev
->name
))
148 copy_var(dev
, new_dev
, mode
);
149 copy_string(dev
, new_dev
, owner
);
150 copy_string(dev
, new_dev
, group
);
154 /* not found, add new structure to the perm list */
155 tmp_dev
= malloc(sizeof(*tmp_dev
));
158 memcpy(tmp_dev
, new_dev
, sizeof(*tmp_dev
));
159 list_add_tail(&tmp_dev
->node
, &perm_device_list
);
160 //dump_perm_dev(tmp_dev);
164 static struct perm_device
*find_perm(char *name
)
166 struct list_head
*tmp
;
167 struct perm_device
*perm
= NULL
;
169 list_for_each(tmp
, &perm_device_list
) {
170 perm
= list_entry(tmp
, struct perm_device
, node
);
171 if (strcmp_pattern(perm
->name
, name
))
178 static mode_t
get_default_mode(struct sysfs_class_device
*class_dev
)
180 mode_t mode
= 0600; /* default to owner rw only */
182 if (strlen(default_mode_str
) != 0) {
183 mode
= strtol(default_mode_str
, NULL
, 8);
188 static void build_kernel_number(struct sysfs_class_device
*class_dev
, struct udevice
*udev
)
192 dig
= class_dev
->name
+ strlen(class_dev
->name
);
193 while (isdigit(*(dig
-1)))
195 strfieldcpy(udev
->kernel_number
, dig
);
196 dbg("kernel_number='%s'", udev
->kernel_number
);
199 static void apply_format(struct udevice
*udev
, unsigned char *string
)
201 char name
[NAME_SIZE
];
202 char temp
[NAME_SIZE
];
211 pos
= strchr(string
, '%');
216 if (isdigit(tail
[0])) {
217 num
= (int) strtoul(&pos
[1], &tail
, 10);
219 dbg("format parsing error '%s'", pos
+1);
223 strfieldcpy(name
, tail
+1);
227 if (strlen(udev
->bus_id
) == 0)
229 strcat(pos
, udev
->bus_id
);
230 dbg("substitute bus_id '%s'", udev
->bus_id
);
233 if (strlen(udev
->kernel_number
) == 0)
235 strcat(pos
, udev
->kernel_number
);
236 dbg("substitute kernel number '%s'", udev
->kernel_number
);
239 if (strlen(udev
->kernel_number
) == 0) {
244 strcat(pos
, udev
->kernel_number
);
245 dbg("substitute kernel number '%s'", udev
->kernel_number
);
248 sprintf(pos
, "%u", udev
->minor
);
249 dbg("substitute minor number '%u'", udev
->minor
);
252 sprintf(pos
, "%u", udev
->major
);
253 dbg("substitute major number '%u'", udev
->major
);
256 if (strlen(udev
->callout_value
) == 0)
259 /* get part of return string */
260 strncpy(temp
, udev
->callout_value
, sizeof(temp
));
264 pos3
= strsep(&pos2
, " ");
266 dbg("requested part of callout string not found");
271 dbg("substitute partial callout output '%s'", pos3
);
273 strcat(pos
, udev
->callout_value
);
274 dbg("substitute callout output '%s'", udev
->callout_value
);
278 dbg("unknown substitution type '%%%c'", pos
[1]);
281 strcat(string
, name
);
288 static int exec_callout(struct config_device
*dev
, char *value
, int len
)
298 char *args
[CALLOUT_MAXARG
];
301 dbg("callout to '%s'", dev
->exec_program
);
315 close(STDOUT_FILENO
);
316 dup(fds
[1]); /* dup write side of pipe to STDOUT */
317 if (strchr(dev
->exec_program
, ' ')) {
318 /* callout with arguments */
319 pos
= dev
->exec_program
;
320 for (i
=0; i
< CALLOUT_MAXARG
-1; i
++) {
321 args
[i
] = strsep(&pos
, " ");
326 dbg("too many args - %d", i
);
329 retval
= execve(args
[0], args
, main_envp
);
331 retval
= execve(dev
->exec_program
, main_argv
, main_envp
);
334 dbg("child execve failed");
337 return -1; /* avoid compiler warning */
339 /* parent reads from fds[0] */
343 res
= read(fds
[0], buffer
, sizeof(buffer
) - 1);
348 dbg("callout len %d too short", len
);
352 dbg("callout value already set");
356 strncpy(value
, buffer
, len
);
357 pos
= value
+ strlen(value
)-1;
360 dbg("callout returned '%s'", value
);
366 dbg("wait failed result %d", res
);
371 if (!WIFEXITED(status
) || (WEXITSTATUS(status
) != 0)) {
372 dbg("callout program status 0x%x", status
);
380 static int do_callout(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
382 struct config_device
*dev
;
383 struct list_head
*tmp
;
385 list_for_each(tmp
, &config_device_list
) {
386 dev
= list_entry(tmp
, struct config_device
, node
);
387 if (dev
->type
!= CALLOUT
)
391 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
392 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
396 /* substitute anything that needs to be in the program name */
397 apply_format(udev
, dev
->exec_program
);
398 if (exec_callout(dev
, udev
->callout_value
, NAME_SIZE
))
400 if (strcmp_pattern(dev
->id
, udev
->callout_value
) != 0)
402 strfieldcpy(udev
->name
, dev
->name
);
403 strfieldcpy(udev
->symlink
, dev
->symlink
);
404 dbg("callout returned matching value '%s', '%s' becomes '%s'",
405 dev
->id
, class_dev
->name
, udev
->name
);
411 static int do_label(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
413 struct sysfs_attribute
*tmpattr
= NULL
;
414 struct config_device
*dev
;
415 struct list_head
*tmp
;
418 list_for_each(tmp
, &config_device_list
) {
419 dev
= list_entry(tmp
, struct config_device
, node
);
420 if (dev
->type
!= LABEL
)
424 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
425 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
429 dbg("look for device attribute '%s'", dev
->sysfs_file
);
430 /* try to find the attribute in the class device directory */
431 tmpattr
= sysfs_get_classdev_attr(class_dev
, dev
->sysfs_file
);
435 /* look in the class device directory if present */
437 tmpattr
= sysfs_get_device_attr(sysfs_device
, dev
->sysfs_file
);
445 c
= tmpattr
->value
+ strlen(tmpattr
->value
)-1;
448 dbg("compare attribute '%s' value '%s' with '%s'",
449 dev
->sysfs_file
, tmpattr
->value
, dev
->sysfs_value
);
450 if (strcmp_pattern(dev
->sysfs_value
, tmpattr
->value
) != 0)
453 strfieldcpy(udev
->name
, dev
->name
);
454 strfieldcpy(udev
->symlink
, dev
->symlink
);
455 dbg("found matching attribute '%s', '%s' becomes '%s' ",
456 dev
->sysfs_file
, class_dev
->name
, udev
->name
);
463 static int do_number(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
465 struct config_device
*dev
;
466 struct list_head
*tmp
;
467 char path
[SYSFS_PATH_MAX
];
471 /* we have to have a sysfs device for NUMBER to work */
475 list_for_each(tmp
, &config_device_list
) {
476 dev
= list_entry(tmp
, struct config_device
, node
);
477 if (dev
->type
!= NUMBER
)
480 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
481 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
485 strfieldcpy(path
, sysfs_device
->path
);
486 temp
= strrchr(path
, '/');
487 dbg("search '%s' in '%s', path='%s'", dev
->id
, temp
, path
);
488 if (strstr(temp
, dev
->id
) != NULL
) {
492 temp
= strrchr(path
, '/');
493 dbg("search '%s' in '%s', path='%s'", dev
->id
, temp
, path
);
494 if (strstr(temp
, dev
->id
) != NULL
)
499 strfieldcpy(udev
->name
, dev
->name
);
500 strfieldcpy(udev
->symlink
, dev
->symlink
);
501 dbg("found matching id '%s', '%s' becomes '%s'",
502 dev
->id
, class_dev
->name
, udev
->name
);
508 static int do_topology(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
510 struct config_device
*dev
;
511 struct list_head
*tmp
;
512 char path
[SYSFS_PATH_MAX
];
516 /* we have to have a sysfs device for TOPOLOGY to work */
520 list_for_each(tmp
, &config_device_list
) {
521 dev
= list_entry(tmp
, struct config_device
, node
);
522 if (dev
->type
!= TOPOLOGY
)
525 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
526 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
530 strfieldcpy(path
, sysfs_device
->path
);
531 temp
= strrchr(path
, '/');
532 dbg("search '%s' in '%s', path='%s'", dev
->place
, temp
, path
);
533 if (strstr(temp
, dev
->place
) != NULL
) {
537 temp
= strrchr(path
, '/');
538 dbg("search '%s' in '%s', path='%s'", dev
->place
, temp
, path
);
539 if (strstr(temp
, dev
->place
) != NULL
)
545 strfieldcpy(udev
->name
, dev
->name
);
546 strfieldcpy(udev
->symlink
, dev
->symlink
);
547 dbg("found matching place '%s', '%s' becomes '%s'",
548 dev
->place
, class_dev
->name
, udev
->name
);
554 static int do_replace(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
556 struct config_device
*dev
;
557 struct list_head
*tmp
;
559 list_for_each(tmp
, &config_device_list
) {
560 dev
= list_entry(tmp
, struct config_device
, node
);
561 if (dev
->type
!= REPLACE
)
564 dbg("compare name '%s' with '%s'", dev
->kernel_name
, class_dev
->name
);
565 if (strcmp_pattern(dev
->kernel_name
, class_dev
->name
) != 0)
568 strfieldcpy(udev
->name
, dev
->name
);
569 strfieldcpy(udev
->symlink
, dev
->symlink
);
570 dbg("found name, '%s' becomes '%s'", dev
->kernel_name
, udev
->name
);
577 static void do_kernelname(struct sysfs_class_device
*class_dev
, struct udevice
*udev
)
579 /* heh, this is pretty simple... */
580 strfieldcpy(udev
->name
, class_dev
->name
);
583 int namedev_name_device(struct sysfs_class_device
*class_dev
, struct udevice
*udev
)
585 struct sysfs_device
*sysfs_device
= NULL
;
586 struct sysfs_class_device
*class_dev_parent
= NULL
;
588 struct perm_device
*perm
;
592 /* find the sysfs_device for this class device */
593 /* Wouldn't it really be nice if libsysfs could do this for us? */
594 sysfs_device
= sysfs_get_classdev_device(class_dev
);
595 if (sysfs_device
== NULL
) {
596 /* bah, let's go backwards up a level to see if the device is there,
597 * as block partitions don't point to the physical device. Need to fix that
598 * up in the kernel...
600 if (strcmp(class_dev
->classname
, SYSFS_BLOCK_NAME
) == 0) {
601 dbg("looking at block device");
602 if (isdigit(class_dev
->path
[strlen(class_dev
->path
)-1])) {
603 dbg("really is a partition");
604 class_dev_parent
= sysfs_get_classdev_parent
606 if (class_dev_parent
== NULL
) {
607 dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev
->name
);
609 dbg("class_dev_parent->name='%s'", class_dev_parent
->name
);
610 sysfs_device
= sysfs_get_classdev_device(class_dev_parent
);
617 dbg("sysfs_device->path='%s'", sysfs_device
->path
);
618 dbg("sysfs_device->bus_id='%s'", sysfs_device
->bus_id
);
619 dbg("sysfs_device->bus='%s'", sysfs_device
->bus
);
620 strfieldcpy(udev
->bus_id
, sysfs_device
->bus_id
);
622 dbg("class_dev->name = '%s'", class_dev
->name
);
625 build_kernel_number(class_dev
, udev
);
627 /* rules are looked at in priority order */
628 retval
= do_callout(class_dev
, udev
, sysfs_device
);
632 retval
= do_label(class_dev
, udev
, sysfs_device
);
636 retval
= do_number(class_dev
, udev
, sysfs_device
);
640 retval
= do_topology(class_dev
, udev
, sysfs_device
);
644 retval
= do_replace(class_dev
, udev
, sysfs_device
);
648 do_kernelname(class_dev
, udev
);
652 /* substitute placeholder */
653 apply_format(udev
, udev
->name
);
654 apply_format(udev
, udev
->symlink
);
657 perm
= find_perm(udev
->name
);
659 udev
->mode
= perm
->mode
;
660 strfieldcpy(udev
->owner
, perm
->owner
);
661 strfieldcpy(udev
->group
, perm
->group
);
663 /* no matching perms found :( */
664 udev
->mode
= get_default_mode(class_dev
);
665 udev
->owner
[0] = 0x00;
666 udev
->group
[0] = 0x00;
668 dbg("name, '%s' is going to have owner='%s', group='%s', mode = %#o",
669 udev
->name
, udev
->owner
, udev
->group
, udev
->mode
);
674 int namedev_init(void)
678 retval
= namedev_init_rules();
682 retval
= namedev_init_permissions();
686 dump_config_dev_list();
687 dump_perm_dev_list();