chiark / gitweb /
[PATCH] Just live with a sleep(1) in namedev for now until libsysfs is fixed up.
[elogind.git] / namedev.c
1 /*
2  * namedev.c
3  *
4  * Userspace devfs
5  *
6  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
7  *
8  *
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.
12  * 
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.
17  * 
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.
21  *
22  */
23
24 #include <stddef.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <ctype.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34
35 #include "list.h"
36 #include "udev.h"
37 #include "udev_version.h"
38 #include "namedev.h"
39 #include "libsysfs/libsysfs.h"
40 #include "klibc_fixups.h"
41
42 LIST_HEAD(config_device_list);
43 LIST_HEAD(perm_device_list);
44
45 /* compare string with pattern (supports * ? [0-9] [!A-Z]) */
46 static int strcmp_pattern(const char *p, const char *s)
47 {
48         if (*s == '\0') {
49                 while (*p == '*')
50                         p++;
51                 return (*p != '\0');
52         }
53         switch (*p) {
54         case '[':
55                 {
56                         int not = 0;
57                         p++;
58                         if (*p == '!') {
59                                 not = 1;
60                                 p++;
61                         }
62                         while (*p && (*p != ']')) {
63                                 int match = 0;
64                                 if (p[1] == '-') {
65                                         if ((*s >= *p) && (*s <= p[2]))
66                                                 match = 1;
67                                         p += 3;
68                                 } else {
69                                         match = (*p == *s);
70                                         p++;
71                                 }
72                                 if (match ^ not) {
73                                         while (*p && (*p != ']'))
74                                                 p++;
75                                         return strcmp_pattern(p+1, s+1);
76                                 }
77                         }
78                 }
79                 break;
80         case '*':
81                 if (strcmp_pattern(p, s+1))
82                         return strcmp_pattern(p+1, s);
83                 return 0;
84         case '\0':
85                 if (*s == '\0') {
86                         return 0;
87                 }
88                 break;
89         default:
90                 if ((*p == *s) || (*p == '?'))
91                         return strcmp_pattern(p+1, s+1);
92                 break;
93         }
94         return 1;
95 }
96
97 #define copy_var(a, b, var)             \
98         if (b->var)                     \
99                 a->var = b->var;
100
101 #define copy_string(a, b, var)          \
102         if (strlen(b->var))             \
103                 strcpy(a->var, b->var);
104
105 int add_config_dev(struct config_device *new_dev)
106 {
107         struct list_head *tmp;
108         struct config_device *tmp_dev;
109
110         /* update the values if we already have the device */
111         list_for_each(tmp, &config_device_list) {
112                 struct config_device *dev = list_entry(tmp, struct config_device, node);
113                 if (strcmp_pattern(new_dev->name, dev->name))
114                         continue;
115                 if (strncmp(dev->bus, new_dev->bus, sizeof(dev->name)))
116                         continue;
117                 copy_var(dev, new_dev, type);
118                 copy_string(dev, new_dev, bus);
119                 copy_string(dev, new_dev, sysfs_file);
120                 copy_string(dev, new_dev, sysfs_value);
121                 copy_string(dev, new_dev, id);
122                 copy_string(dev, new_dev, place);
123                 copy_string(dev, new_dev, kernel_name);
124                 copy_string(dev, new_dev, exec_program);
125                 copy_string(dev, new_dev, symlink);
126                 return 0;
127         }
128
129         /* not found, add new structure to the device list */
130         tmp_dev = malloc(sizeof(*tmp_dev));
131         if (!tmp_dev)
132                 return -ENOMEM;
133         memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
134         list_add_tail(&tmp_dev->node, &config_device_list);
135         //dump_config_dev(tmp_dev);
136         return 0;
137 }
138
139 int add_perm_dev(struct perm_device *new_dev)
140 {
141         struct list_head *tmp;
142         struct perm_device *tmp_dev;
143
144         /* update the values if we already have the device */
145         list_for_each(tmp, &perm_device_list) {
146                 struct perm_device *dev = list_entry(tmp, struct perm_device, node);
147                 if (strcmp_pattern(new_dev->name, dev->name))
148                         continue;
149                 copy_var(dev, new_dev, mode);
150                 copy_string(dev, new_dev, owner);
151                 copy_string(dev, new_dev, group);
152                 return 0;
153         }
154
155         /* not found, add new structure to the perm list */
156         tmp_dev = malloc(sizeof(*tmp_dev));
157         if (!tmp_dev)
158                 return -ENOMEM;
159         memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
160         list_add_tail(&tmp_dev->node, &perm_device_list);
161         //dump_perm_dev(tmp_dev);
162         return 0;
163 }
164
165 static struct perm_device *find_perm(char *name)
166 {
167         struct list_head *tmp;
168         struct perm_device *perm = NULL;
169
170         list_for_each(tmp, &perm_device_list) {
171                 perm = list_entry(tmp, struct perm_device, node);
172                 if (strcmp_pattern(perm->name, name))
173                         continue;
174                 return perm;
175         }
176         return NULL;
177 }
178
179 static mode_t get_default_mode(struct sysfs_class_device *class_dev)
180 {
181         mode_t mode = 0600;     /* default to owner rw only */
182
183         if (strlen(default_mode_str) != 0) {
184                 mode = strtol(default_mode_str, NULL, 8);
185         }
186         return mode;
187 }
188
189 static void build_kernel_number(struct sysfs_class_device *class_dev, struct udevice *udev)
190 {
191         char *dig;
192
193         dig = class_dev->name + strlen(class_dev->name);
194         while (isdigit(*(dig-1)))
195                 dig--;
196         strfieldcpy(udev->kernel_number, dig);
197         dbg("kernel_number='%s'", udev->kernel_number);
198 }
199
200 static void apply_format(struct udevice *udev, unsigned char *string)
201 {
202         char name[NAME_SIZE];
203         char temp[NAME_SIZE];
204         char *tail;
205         char *pos;
206         char *pos2;
207         char *pos3;
208         int num;
209
210         while (1) {
211                 num = 0;
212                 pos = strchr(string, '%');
213
214                 if (pos) {
215                         *pos = '\0';
216                         tail = pos+1;
217                         if (isdigit(tail[0])) {
218                                 num = (int) strtoul(&pos[1], &tail, 10);
219                                 if (tail == NULL) {
220                                         dbg("format parsing error '%s'", pos+1);
221                                         break;
222                                 }
223                         }
224                         strfieldcpy(name, tail+1);
225
226                         switch (tail[0]) {
227                         case 'b':
228                                 if (strlen(udev->bus_id) == 0)
229                                         break;
230                                 strcat(pos, udev->bus_id);
231                                 dbg("substitute bus_id '%s'", udev->bus_id);
232                                 break;
233                         case 'n':
234                                 if (strlen(udev->kernel_number) == 0)
235                                         break;
236                                 strcat(pos, udev->kernel_number);
237                                 dbg("substitute kernel number '%s'", udev->kernel_number);
238                                 break;
239                         case 'D':
240                                 if (strlen(udev->kernel_number) == 0) {
241                                         strcat(pos, "disc");
242                                         break;
243                                 }
244                                 strcat(pos, "part");
245                                 strcat(pos, udev->kernel_number);
246                                 dbg("substitute kernel number '%s'", udev->kernel_number);
247                                 break;
248                         case 'm':
249                                 sprintf(pos, "%u", udev->minor);
250                                 dbg("substitute minor number '%u'", udev->minor);
251                                 break;
252                         case 'M':
253                                 sprintf(pos, "%u", udev->major);
254                                 dbg("substitute major number '%u'", udev->major);
255                                 break;
256                         case 'c':
257                                 if (strlen(udev->callout_value) == 0)
258                                         break;
259                                 if (num) {
260                                         /* get part of return string */
261                                         strncpy(temp, udev->callout_value, sizeof(temp));
262                                         pos2 = temp;
263                                         while (num) {
264                                                 num--;
265                                                 pos3 = strsep(&pos2, " ");
266                                                 if (pos3 == NULL) {
267                                                         dbg("requested part of callout string not found");
268                                                         break;
269                                                 }
270                                         }
271                                         strcat(pos, pos3);
272                                         dbg("substitute partial callout output '%s'", pos3);
273                                 } else {
274                                         strcat(pos, udev->callout_value);
275                                         dbg("substitute callout output '%s'", udev->callout_value);
276                                 }
277                                 break;
278                         default:
279                                 dbg("unknown substitution type '%%%c'", pos[1]);
280                                 break;
281                         }
282                         strcat(string, name);
283                 } else
284                         break;
285         }
286 }
287
288 static struct bus_file {
289         char *bus;
290         char *file;
291 } bus_files[] = {
292         { .bus = "scsi",        .file = "vendor" },
293         { .bus = "usb",         .file = "idVendor" },
294         {}
295 };
296
297 #define SECONDS_TO_WAIT_FOR_FILE        10
298 static void wait_for_device_to_initialize(struct sysfs_device *sysfs_device)
299 {
300         /* sleep until we see the file for this specific bus type show up this
301          * is needed because we can easily out-run the kernel in looking for
302          * these files before the paticular subsystem has created them in the
303          * sysfs tree properly.
304          *
305          * And people thought that the /sbin/hotplug event system was going to
306          * be slow, poo on you for arguing that before even testing it...
307          */
308         struct bus_file *b = &bus_files[0];
309         struct sysfs_attribute *tmpattr;
310         int loop;
311
312         while (1) {
313                 if (b->bus == NULL)
314                         break;
315                 if (strcmp(sysfs_device->bus, b->bus) == 0) {
316                         tmpattr = NULL;
317                         loop = SECONDS_TO_WAIT_FOR_FILE;
318                         while (loop--) {
319                                 dbg("looking for file '%s' on bus '%s'", b->file, b->bus);
320                                 tmpattr = sysfs_get_device_attr(sysfs_device, b->file);
321                                 if (tmpattr) {
322                                         /* found it! */
323                                         goto exit;
324                                 }
325                                 /* sleep to give the kernel a chance to create the file */
326                                 sleep(1);
327                         }
328                         dbg("Timed out waiting for '%s' file, continuing on anyway...", b->file);
329                         goto exit;
330                 }
331                 b++;
332         }
333         dbg("Did not find bus type '%s' on list of bus_id_files, contact greg@kroah.com", sysfs_device->bus);
334 exit:
335         return; /* here to prevent compiler warning... */
336 }
337
338 static int exec_callout(struct config_device *dev, char *value, int len)
339 {
340         int retval;
341         int res;
342         int status;
343         int fds[2];
344         pid_t pid;
345         int value_set = 0;
346         char buffer[256];
347         char *pos;
348         char *args[CALLOUT_MAXARG];
349         int i;
350
351         dbg("callout to '%s'", dev->exec_program);
352         retval = pipe(fds);
353         if (retval != 0) {
354                 dbg("pipe failed");
355                 return -1;
356         }
357         pid = fork();
358         if (pid == -1) {
359                 dbg("fork failed");
360                 return -1;
361         }
362
363         if (pid == 0) {
364                 /* child */
365                 close(STDOUT_FILENO);
366                 dup(fds[1]);    /* dup write side of pipe to STDOUT */
367                 if (strchr(dev->exec_program, ' ')) {
368                         /* callout with arguments */
369                         pos = dev->exec_program;
370                         for (i=0; i < CALLOUT_MAXARG-1; i++) {
371                                 args[i] = strsep(&pos, " ");
372                                 if (args[i] == NULL)
373                                         break;
374                         }
375                         if (args[i]) {
376                                 dbg("too many args - %d", i);
377                                 args[i] = NULL;
378                         }
379                         retval = execve(args[0], args, main_envp);
380                 } else {
381                         retval = execve(dev->exec_program, main_argv, main_envp);
382                 }
383                 if (retval != 0) {
384                         dbg("child execve failed");
385                         exit(1);
386                 }
387                 return -1; /* avoid compiler warning */
388         } else {
389                 /* parent reads from fds[0] */
390                 close(fds[1]);
391                 retval = 0;
392                 while (1) {
393                         res = read(fds[0], buffer, sizeof(buffer) - 1);
394                         if (res <= 0)
395                                 break;
396                         buffer[res] = '\0';
397                         if (res > len) {
398                                 dbg("callout len %d too short", len);
399                                 retval = -1;
400                         }
401                         if (value_set) {
402                                 dbg("callout value already set");
403                                 retval = -1;
404                         } else {
405                                 value_set = 1;
406                                 strncpy(value, buffer, len);
407                                 pos = value + strlen(value)-1;
408                                 if (pos[0] == '\n')
409                                 pos[0] = '\0';
410                                 dbg("callout returned '%s'", value);
411                         }
412                 }
413                 close(fds[0]);
414                 res = wait(&status);
415                 if (res < 0) {
416                         dbg("wait failed result %d", res);
417                         retval = -1;
418                 }
419
420 #ifndef __KLIBC__
421                 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
422                         dbg("callout program status 0x%x", status);
423                         retval = -1;
424                 }
425 #endif
426         }
427         return retval;
428 }
429
430 static int do_callout(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
431 {
432         struct config_device *dev;
433         struct list_head *tmp;
434
435         list_for_each(tmp, &config_device_list) {
436                 dev = list_entry(tmp, struct config_device, node);
437                 if (dev->type != CALLOUT)
438                         continue;
439
440                 if (sysfs_device) {
441                         dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
442                         if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
443                                 continue;
444                 }
445
446                 /* substitute anything that needs to be in the program name */
447                 apply_format(udev, dev->exec_program);
448                 if (exec_callout(dev, udev->callout_value, NAME_SIZE))
449                         continue;
450                 if (strcmp_pattern(dev->id, udev->callout_value) != 0)
451                         continue;
452                 strfieldcpy(udev->name, dev->name);
453                 strfieldcpy(udev->symlink, dev->symlink);
454                 dbg("callout returned matching value '%s', '%s' becomes '%s'",
455                     dev->id, class_dev->name, udev->name);
456                 return 0;
457         }
458         return -ENODEV;
459 }
460
461 static int do_label(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
462 {
463         struct sysfs_attribute *tmpattr = NULL;
464         struct config_device *dev;
465         struct list_head *tmp;
466         char *c;
467
468         list_for_each(tmp, &config_device_list) {
469                 dev = list_entry(tmp, struct config_device, node);
470                 if (dev->type != LABEL)
471                         continue;
472
473                 if (sysfs_device) {
474                         dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
475                         if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
476                                 continue;
477                 }
478
479                 dbg("look for device attribute '%s'", dev->sysfs_file);
480                 /* try to find the attribute in the class device directory */
481                 tmpattr = sysfs_get_classdev_attr(class_dev, dev->sysfs_file);
482                 if (tmpattr)
483                         goto label_found;
484
485                 /* look in the class device directory if present */
486                 if (sysfs_device) {
487                         tmpattr = sysfs_get_device_attr(sysfs_device, dev->sysfs_file);
488                         if (tmpattr)
489                                 goto label_found;
490                 }
491
492                 continue;
493
494 label_found:
495                 c = tmpattr->value + strlen(tmpattr->value)-1;
496                 if (*c == '\n')
497                         *c = 0x00;
498                 dbg("compare attribute '%s' value '%s' with '%s'",
499                           dev->sysfs_file, tmpattr->value, dev->sysfs_value);
500                 if (strcmp_pattern(dev->sysfs_value, tmpattr->value) != 0)
501                         continue;
502
503                 strfieldcpy(udev->name, dev->name);
504                 strfieldcpy(udev->symlink, dev->symlink);
505                 dbg("found matching attribute '%s', '%s' becomes '%s' ",
506                     dev->sysfs_file, class_dev->name, udev->name);
507
508                 return 0;
509         }
510         return -ENODEV;
511 }
512
513 static int do_number(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
514 {
515         struct config_device *dev;
516         struct list_head *tmp;
517         char path[SYSFS_PATH_MAX];
518         int found;
519         char *temp = NULL;
520
521         /* we have to have a sysfs device for NUMBER to work */
522         if (!sysfs_device)
523                 return -ENODEV;
524
525         list_for_each(tmp, &config_device_list) {
526                 dev = list_entry(tmp, struct config_device, node);
527                 if (dev->type != NUMBER)
528                         continue;
529
530                 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
531                 if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
532                         continue;
533
534                 found = 0;
535                 strfieldcpy(path, sysfs_device->path);
536                 temp = strrchr(path, '/');
537                 dbg("search '%s' in '%s', path='%s'", dev->id, temp, path);
538                 if (strstr(temp, dev->id) != NULL) {
539                         found = 1;
540                 } else {
541                         *temp = 0x00;
542                         temp = strrchr(path, '/');
543                         dbg("search '%s' in '%s', path='%s'", dev->id, temp, path);
544                         if (strstr(temp, dev->id) != NULL)
545                                 found = 1;
546                 }
547                 if (!found)
548                         continue;
549                 strfieldcpy(udev->name, dev->name);
550                 strfieldcpy(udev->symlink, dev->symlink);
551                 dbg("found matching id '%s', '%s' becomes '%s'",
552                     dev->id, class_dev->name, udev->name);
553                 return 0;
554         }
555         return -ENODEV;
556 }
557
558 static int do_topology(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
559 {
560         struct config_device *dev;
561         struct list_head *tmp;
562         char path[SYSFS_PATH_MAX];
563         int found;
564         char *temp = NULL;
565
566         /* we have to have a sysfs device for TOPOLOGY to work */
567         if (!sysfs_device)
568                 return -ENODEV;
569
570         list_for_each(tmp, &config_device_list) {
571                 dev = list_entry(tmp, struct config_device, node);
572                 if (dev->type != TOPOLOGY)
573                         continue;
574
575                 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
576                 if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
577                         continue;
578
579                 found = 0;
580                 strfieldcpy(path, sysfs_device->path);
581                 temp = strrchr(path, '/');
582                 dbg("search '%s' in '%s', path='%s'", dev->place, temp, path);
583                 if (strstr(temp, dev->place) != NULL) {
584                         found = 1;
585                 } else {
586                         *temp = 0x00;
587                         temp = strrchr(path, '/');
588                         dbg("search '%s' in '%s', path='%s'", dev->place, temp, path);
589                         if (strstr(temp, dev->place) != NULL)
590                                 found = 1;
591                 }
592                 if (!found)
593                         continue;
594
595                 strfieldcpy(udev->name, dev->name);
596                 strfieldcpy(udev->symlink, dev->symlink);
597                 dbg("found matching place '%s', '%s' becomes '%s'",
598                     dev->place, class_dev->name, udev->name);
599                 return 0;
600         }
601         return -ENODEV;
602 }
603
604 static int do_replace(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
605 {
606         struct config_device *dev;
607         struct list_head *tmp;
608
609         list_for_each(tmp, &config_device_list) {
610                 dev = list_entry(tmp, struct config_device, node);
611                 if (dev->type != REPLACE)
612                         continue;
613
614                 dbg("compare name '%s' with '%s'", dev->kernel_name, class_dev->name);
615                 if (strcmp_pattern(dev->kernel_name, class_dev->name) != 0)
616                         continue;
617
618                 strfieldcpy(udev->name, dev->name);
619                 strfieldcpy(udev->symlink, dev->symlink);
620                 dbg("found name, '%s' becomes '%s'", dev->kernel_name, udev->name);
621                 
622                 return 0;
623         }
624         return -ENODEV;
625 }
626
627 static void do_kernelname(struct sysfs_class_device *class_dev, struct udevice *udev)
628 {
629         /* heh, this is pretty simple... */
630         strfieldcpy(udev->name, class_dev->name);
631 }
632
633 static struct sysfs_device *get_sysfs_device(struct sysfs_class_device *class_dev)
634 {
635         struct sysfs_device *sysfs_device;
636         struct sysfs_class_device *class_dev_parent;
637         int loop;
638
639         /* FIXME!!! */
640         /* This is needed here as we can easily out-race the placement of the
641          * device symlink by the kernel.  The call to sleep(1); will be removed
642          * once libsysfs can be queried for sysfs_get_classdev_device()
643          * multiple times and have it return the proper information when the
644          * class device really shows up.  For now, we live with the time
645          * delay...
646          */
647         sleep(1);
648
649 #if 0   /* FIXME
650            Something like this could also work, but for some reason doesn't,
651            I also tried just stat() on the device symlink, but that still
652            has nasty races, I'm probably doing something stupid... :( */
653         loop = 10;
654         while (loop--) {
655                 struct stat buf;
656                 int retval;
657                 char filename[SYSFS_PATH_MAX + 6];
658
659                 strcpy(filename, class_dev->path);
660                 strcat(filename, "/device");
661                 dbg("looking for '%s'", filename);
662                 retval = stat(filename, &buf);
663                 if (!retval)
664                         break;
665
666                 /* bah, let's go backwards up a level to see if the device is there,
667                  * as block partitions don't point to the physical device.  Need to fix that
668                  * up in the kernel...
669                  */
670                 if (strcmp(class_dev->classname, SYSFS_BLOCK_NAME) == 0) {
671                         if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
672                                 class_dev_parent = sysfs_get_classdev_parent(class_dev);
673                                 if (class_dev_parent == NULL) {
674                                         dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev->name);
675                                 } else {
676                                         strcpy(filename, class_dev_parent->path);
677                                         strcat(filename, "/device");
678                                         dbg("looking for '%s'", filename);
679                                         retval = stat(filename, &buf);
680                                         if (!retval)
681                                                 break;
682                                 }
683                         }
684                 }
685                 /* sleep to give the kernel a chance to create the device file */
686                 sleep(1);
687         }
688 #endif
689         loop = 1;       /* FIXME put a real value in here for when everything is fixed... */
690         while (loop--) {
691                 /* find the sysfs_device for this class device */
692                 /* Wouldn't it really be nice if libsysfs could do this for us? */
693                 sysfs_device = sysfs_get_classdev_device(class_dev);
694                 if (sysfs_device != NULL)
695                         goto exit;
696
697                 /* bah, let's go backwards up a level to see if the device is there,
698                  * as block partitions don't point to the physical device.  Need to fix that
699                  * up in the kernel...
700                  */
701                 if (strcmp(class_dev->classname, SYSFS_BLOCK_NAME) == 0) {
702                         dbg("looking at block device");
703                         if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
704                                 dbg("really is a partition");
705                                 class_dev_parent = sysfs_get_classdev_parent(class_dev);
706                                 if (class_dev_parent == NULL) {
707                                         dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev->name);
708                                 } else {
709                                         dbg("class_dev_parent->name='%s'", class_dev_parent->name);
710                                         sysfs_device = sysfs_get_classdev_device(class_dev_parent);
711                                         if (sysfs_device != NULL)
712                                                 goto exit;
713                                 }
714                         }
715                 }
716                 /* sleep to give the kernel a chance to create the link */
717                 sleep(1);
718
719         }
720         dbg("Timed out waiting for device symlink, continuing on anyway...");
721 exit:
722         return sysfs_device;
723 }
724
725 int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *udev)
726 {
727         struct sysfs_device *sysfs_device = NULL;
728         struct sysfs_class_device *class_dev_parent = NULL;
729         int retval = 0;
730         struct perm_device *perm;
731
732         udev->mode = 0;
733
734         /* find the sysfs_device associated with this class device */
735         sysfs_device = get_sysfs_device(class_dev);
736         if (sysfs_device) {
737                 dbg("sysfs_device->path='%s'", sysfs_device->path);
738                 dbg("sysfs_device->bus_id='%s'", sysfs_device->bus_id);
739                 dbg("sysfs_device->bus='%s'", sysfs_device->bus);
740                 strfieldcpy(udev->bus_id, sysfs_device->bus_id);
741                 wait_for_device_to_initialize(sysfs_device);
742         } else {
743                 dbg("class_dev->name = '%s'", class_dev->name);
744         }
745
746         build_kernel_number(class_dev, udev);
747
748         /* rules are looked at in priority order */
749         retval = do_callout(class_dev, udev, sysfs_device);
750         if (retval == 0)
751                 goto found;
752
753         retval = do_label(class_dev, udev, sysfs_device);
754         if (retval == 0)
755                 goto found;
756
757         retval = do_number(class_dev, udev, sysfs_device);
758         if (retval == 0)
759                 goto found;
760
761         retval = do_topology(class_dev, udev, sysfs_device);
762         if (retval == 0)
763                 goto found;
764
765         retval = do_replace(class_dev, udev, sysfs_device);
766         if (retval == 0)
767                 goto found;
768
769         do_kernelname(class_dev, udev);
770         goto done;
771
772 found:
773         /* substitute placeholder */
774         apply_format(udev, udev->name);
775         apply_format(udev, udev->symlink);
776
777 done:
778         perm = find_perm(udev->name);
779         if (perm) {
780                 udev->mode = perm->mode;
781                 strfieldcpy(udev->owner, perm->owner);
782                 strfieldcpy(udev->group, perm->group);
783         } else {
784                 /* no matching perms found :( */
785                 udev->mode = get_default_mode(class_dev);
786                 udev->owner[0] = 0x00;
787                 udev->group[0] = 0x00;
788         }
789         dbg("name, '%s' is going to have owner='%s', group='%s', mode = %#o",
790             udev->name, udev->owner, udev->group, udev->mode);
791
792         return 0;
793 }
794
795 int namedev_init(void)
796 {
797         int retval;
798
799         retval = namedev_init_rules();
800         if (retval)
801                 return retval;
802
803         retval = namedev_init_permissions();
804         if (retval)
805                 return retval;
806
807         dump_config_dev_list();
808         dump_perm_dev_list();
809         return retval;
810 }