chiark / gitweb /
[PATCH] udev-test.pl cleanup
[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 <time.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35
36 #include "libsysfs/sysfs/libsysfs.h"
37 #include "list.h"
38 #include "udev.h"
39 #include "udev_version.h"
40 #include "logging.h"
41 #include "namedev.h"
42 #include "klibc_fixups.h"
43
44 static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, char *attr);
45
46 LIST_HEAD(config_device_list);
47 LIST_HEAD(perm_device_list);
48
49
50 /* compare string with pattern (supports * ? [0-9] [!A-Z]) */
51 static int strcmp_pattern(const char *p, const char *s)
52 {
53         if (s[0] == '\0') {
54                 while (p[0] == '*')
55                         p++;
56                 return (p[0] != '\0');
57         }
58         switch (p[0]) {
59         case '[':
60                 {
61                         int not = 0;
62                         p++;
63                         if (p[0] == '!') {
64                                 not = 1;
65                                 p++;
66                         }
67                         while ((p[0] != '\0') && (p[0] != ']')) {
68                                 int match = 0;
69                                 if (p[1] == '-') {
70                                         if ((s[0] >= p[0]) && (s[0] <= p[2]))
71                                                 match = 1;
72                                         p += 3;
73                                 } else {
74                                         match = (p[0] == s[0]);
75                                         p++;
76                                 }
77                                 if (match ^ not) {
78                                         while ((p[0] != '\0') && (p[0] != ']'))
79                                                 p++;
80                                         if (p[0] == ']')
81                                                 return strcmp_pattern(p+1, s+1);
82                                 }
83                         }
84                 }
85                 break;
86         case '*':
87                 if (strcmp_pattern(p, s+1))
88                         return strcmp_pattern(p+1, s);
89                 return 0;
90         case '\0':
91                 if (s[0] == '\0') {
92                         return 0;
93                 }
94                 break;
95         default:
96                 if ((p[0] == s[0]) || (p[0] == '?'))
97                         return strcmp_pattern(p+1, s+1);
98                 break;
99         }
100         return 1;
101 }
102
103 static struct perm_device *find_perm(char *name)
104 {
105         struct perm_device *perm;
106
107         list_for_each_entry(perm, &perm_device_list, node) {
108                 if (strcmp_pattern(perm->name, name))
109                         continue;
110                 return perm;
111         }
112         return NULL;
113 }
114
115 static mode_t get_default_mode(void)
116 {
117         mode_t mode = 0600;     /* default to owner rw only */
118
119         if (strlen(default_mode_str) != 0)
120                 mode = strtol(default_mode_str, NULL, 8);
121
122         return mode;
123 }
124
125 static char *get_default_owner(void)
126 {
127         if (strlen(default_owner_str) == 0)
128                 strfieldcpy(default_owner_str, "root");
129
130         return default_owner_str;
131 }
132
133 static char *get_default_group(void)
134 {
135         if (strlen(default_group_str) == 0)
136                 strfieldcpy(default_group_str, "root");
137
138         return default_group_str;
139 }
140
141 /* extract possible {attr} and move str behind it */
142 static char *get_format_attribute(char **str)
143 {
144         char *pos;
145         char *attr = NULL;
146
147         if (*str[0] == '{') {
148                 pos = strchr(*str, '}');
149                 if (pos == NULL) {
150                         dbg("missing closing brace for format");
151                         return NULL;
152                 }
153                 pos[0] = '\0';
154                 attr = *str+1;
155                 *str = pos+1;
156                 dbg("attribute='%s', str='%s'", attr, *str);
157         }
158         return attr;
159 }
160
161 /* extract possible format length and move str behind it*/
162 static int get_format_len(char **str)
163 {
164         int num;
165         char *tail;
166
167         if (isdigit(*str[0])) {
168                 num = (int) strtoul(*str, &tail, 10);
169                 if (num > 0) {
170                         *str = tail;
171                         dbg("format length=%i", num);
172                         return num;
173                 } else {
174                         dbg("format parsing error '%s'", *str);
175                 }
176         }
177         return -1;
178 }
179
180 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
181                          struct sysfs_class_device *class_dev,
182                          struct sysfs_device *sysfs_device)
183 {
184         char temp[NAME_SIZE];
185         char temp2[NAME_SIZE];
186         char *tail;
187         char *pos;
188         char *attr;
189         int len;
190         int i;
191         char c;
192         char *spos;
193         char *rest;
194         int slen;
195         struct sysfs_attribute *tmpattr;
196
197         pos = string;
198
199         while (1) {
200                 pos = strchr(string, '%');
201                 if (pos != NULL) {
202                         pos[0] = '\0';
203                         tail = pos+1;
204                         len = get_format_len(&tail);
205                         c = tail[0];
206                         strfieldcpy(temp, tail+1);
207                         tail = temp;
208                 } else {
209                         break;
210                 }
211                 dbg("format=%c, string='%s', tail='%s'",c , string, tail);
212
213                 attr = get_format_attribute(&tail);
214
215                 switch (c) {
216                 case 'b':
217                         if (strlen(udev->bus_id) == 0)
218                                 break;
219                         strfieldcatmax(string, udev->bus_id, maxsize);
220                         dbg("substitute bus_id '%s'", udev->bus_id);
221                         break;
222                 case 'k':
223                         if (strlen(udev->kernel_name) == 0)
224                                 break;
225                         strfieldcatmax(string, udev->kernel_name, maxsize);
226                         dbg("substitute kernel name '%s'", udev->kernel_name);
227                         break;
228                 case 'n':
229                         if (strlen(udev->kernel_number) == 0)
230                                 break;
231                         strfieldcatmax(string, udev->kernel_number, maxsize);
232                         dbg("substitute kernel number '%s'", udev->kernel_number);
233                                 break;
234                 case 'm':
235                         strintcatmax(string, udev->minor, maxsize);
236                         dbg("substitute minor number '%u'", udev->minor);
237                         break;
238                 case 'M':
239                         strintcatmax(string, udev->major, maxsize);
240                         dbg("substitute major number '%u'", udev->major);
241                         break;
242                 case 'c':
243                         if (strlen(udev->program_result) == 0)
244                                 break;
245                         /* get part part of the result string */
246                         i = 0;
247                         if (attr != NULL)
248                                 i = strtoul(attr, &rest, 10);
249                         if (i > 0) {
250                                 foreach_strpart(udev->program_result, " \n\r", spos, slen) {
251                                         i--;
252                                         if (i == 0)
253                                                 break;
254                                 }
255                                 if (i > 0) {
256                                         dbg("requested part of result string not found");
257                                         break;
258                                 }
259                                 if (rest[0] == '+')
260                                         strfieldcpy(temp2, spos);
261                                 else
262                                         strfieldcpymax(temp2, spos, slen+1);
263                                 strfieldcatmax(string, temp2, maxsize);
264                                 dbg("substitute part of result string '%s'", temp2);
265                         } else {
266                                 strfieldcatmax(string, udev->program_result, maxsize);
267                                 dbg("substitute result string '%s'", udev->program_result);
268                         }
269                         break;
270                 case 's':
271                         if (attr != NULL) {
272                                 tmpattr = find_sysfs_attribute(class_dev, sysfs_device, attr);
273                                 if (tmpattr == NULL) {
274                                         dbg("sysfa attribute '%s' not found", attr);
275                                         break;
276                                 }
277                                 strfieldcatmax(string, tmpattr->value, maxsize);
278                                 dbg("substitute sysfs value '%s'", tmpattr->value);
279                         } else {
280                                 dbg("missing attribute");
281                         }
282                         break;
283                 case '%':
284                         strfieldcatmax(string, "%", maxsize);
285                         break;
286                 default:
287                         dbg("unknown substitution type '%%%c'", c);
288                         break;
289                 }
290                 /* truncate to specified length */
291                 if (len > 0)
292                         pos[len] = '\0';
293
294                 strfieldcatmax(string, tail, maxsize);
295         }
296 }
297
298 /* 
299  * Note, we can have multiple files for different busses in here due
300  * to the mess that USB has for its device tree...
301  */
302 static struct bus_file {
303         char *bus;
304         char *file;
305 } bus_files[] = {
306         { .bus = "scsi",        .file = "vendor" },
307         { .bus = "usb",         .file = "idVendor" },
308         { .bus = "usb",         .file = "iInterface" },
309         { .bus = "usb-serial",  .file = "detach_state" },
310         { .bus = "ide",         .file = "detach_state" },
311         { .bus = "pci",         .file = "vendor" },
312         {}
313 };
314
315 #define SECONDS_TO_WAIT_FOR_FILE        10
316 static void wait_for_device_to_initialize(struct sysfs_device *sysfs_device)
317 {
318         /* sleep until we see the file for this specific bus type show up this
319          * is needed because we can easily out-run the kernel in looking for
320          * these files before the paticular subsystem has created them in the
321          * sysfs tree properly.
322          *
323          * And people thought that the /sbin/hotplug event system was going to
324          * be slow, poo on you for arguing that before even testing it...
325          */
326         struct bus_file *b = &bus_files[0];
327         struct sysfs_attribute *tmpattr;
328         int found = 0;
329         int loop = SECONDS_TO_WAIT_FOR_FILE;
330
331         while (1) {
332                 if (b->bus == NULL) {
333                         if (!found)
334                                 break;
335                         /* sleep to give the kernel a chance to create the file */
336                         sleep(1);
337                         --loop;
338                         if (loop == 0)
339                                 break;
340                         b = &bus_files[0];
341                 }
342                 if (strcmp(sysfs_device->bus, b->bus) == 0) {
343                         found = 1;
344                         dbg("looking for file '%s' on bus '%s'", b->file, b->bus);
345                         tmpattr = sysfs_get_device_attr(sysfs_device, b->file);
346                         if (tmpattr) {
347                                 /* found it! */
348                                 goto exit;
349                         }
350                         dbg("can't find '%s' file", b->file);
351                 }
352                 ++b;
353         }
354         if (!found)
355                 dbg("did not find bus type '%s' on list of bus_id_files, "
356                     "contact greg@kroah.com", sysfs_device->bus);
357 exit:
358         return; /* here to prevent compiler warning... */
359 }
360
361 static void fix_kernel_name(struct udevice *udev)
362 {
363         char *temp = udev->kernel_name;
364
365         while (*temp != 0x00) {
366                 /* Some block devices have a ! in their name, 
367                  * we need to change that to / */
368                 if (*temp == '!')
369                         *temp = '/';
370                 ++temp;
371         }
372 }
373
374 static int execute_program(char *path, char *value, int len)
375 {
376         int retval;
377         int count;
378         int status;
379         int fds[2];
380         pid_t pid;
381         char *pos;
382         char arg[PROGRAM_SIZE];
383         char *argv[sizeof(arg) / 2];
384         int i;
385
386         i = 0;
387         if (strchr(path, ' ')) {
388                 strfieldcpy(arg, path);
389                 pos = arg;
390                 while (pos != NULL) {
391                         if (pos[0] == '\'') {
392                                 /* don't separate if in apostrophes */
393                                 pos++;
394                                 argv[i] = strsep(&pos, "\'");
395                                 while (pos[0] == ' ')
396                                         pos++;
397                 } else {
398                                 argv[i] = strsep(&pos, " ");
399                         }
400                         dbg("arg[%i] '%s'", i, argv[i]);
401                         i++;
402                 }
403         }
404         argv[i] =  NULL;
405
406         retval = pipe(fds);
407         if (retval != 0) {
408                 dbg("pipe failed");
409                 return -1;
410         }
411
412         pid = fork();
413         switch(pid) {
414         case 0:
415                 /* child */
416                 close(STDOUT_FILENO);
417
418                 /* dup write side of pipe to STDOUT */
419                 dup(fds[1]);
420                 if (argv[0] !=  NULL) {
421                         dbg("execute '%s' with given arguments", argv[0]);
422                         retval = execv(argv[0], argv);
423                 } else {
424                         dbg("execute '%s' with main argument", path);
425                         retval = execv(path, main_argv);
426                 }
427
428                 info(FIELD_PROGRAM " execution of '%s' failed", path);
429                 exit(1);
430         case -1:
431                 dbg("fork failed");
432                 return -1;
433         default:
434                 /* parent reads from fds[0] */
435                 close(fds[1]);
436                 retval = 0;
437                 i = 0;
438                 while (1) {
439                         count = read(fds[0], value + i, len - i-1);
440                         if (count <= 0)
441                                 break;
442
443                         i += count;
444                         if (i >= len-1) {
445                                 dbg("result len %d too short", len);
446                                 retval = -1;
447                                 break;
448                         }
449                 }
450
451                 if (count < 0) {
452                         dbg("read failed with '%s'", strerror(errno));
453                         retval = -1;
454                 }
455
456                 if (i > 0 && value[i] == '\n')
457                         i--;
458                 value[i] = '\0';
459                 dbg("result is '%s'", value);
460
461                 close(fds[0]);
462                 wait(&status);
463
464                 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
465                         dbg("exec program status 0x%x", status);
466                         retval = -1;
467                 }
468         }
469         return retval;
470 }
471
472 static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, char *attr)
473 {
474         struct sysfs_attribute *tmpattr = NULL;
475         char *c;
476
477         dbg("look for device attribute '%s'", attr);
478         /* try to find the attribute in the class device directory */
479         tmpattr = sysfs_get_classdev_attr(class_dev, attr);
480         if (tmpattr)
481                 goto attr_found;
482
483         /* look in the class device directory if present */
484         if (sysfs_device) {
485                 tmpattr = sysfs_get_device_attr(sysfs_device, attr);
486                 if (tmpattr)
487                         goto attr_found;
488         }
489
490         return NULL;
491
492 attr_found:
493         c = strchr(tmpattr->value, '\n');
494         if (c != NULL)
495                 c[0] = '\0';
496
497         dbg("found attribute '%s'", tmpattr->path);
498         return tmpattr;
499 }
500
501 static int compare_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, struct sysfs_pair *pair)
502 {
503         struct sysfs_attribute *tmpattr;
504         int i;
505         int len;
506
507         if ((pair == NULL) || (pair->file[0] == '\0') || (pair->value == '\0'))
508                 return -ENODEV;
509
510         tmpattr = find_sysfs_attribute(class_dev, sysfs_device, pair->file);
511         if (tmpattr == NULL)
512                 return -ENODEV;
513
514         /* strip trailing whitespace of value, if not asked to match for it */
515         if (! isspace(pair->value[strlen(pair->value)-1])) {
516                 i = len = strlen(tmpattr->value);
517                 while (i > 0 &&  isspace(tmpattr->value[i-1]))
518                         i--;
519                 if (i < len) {
520                         tmpattr->value[i] = '\0';
521                         dbg("remove %i trailing whitespace chars from '%s'",
522                             len - i, tmpattr->value);
523                 }
524         }
525
526         dbg("compare attribute '%s' value '%s' with '%s'",
527                   pair->file, tmpattr->value, pair->value);
528         if (strcmp_pattern(pair->value, tmpattr->value) != 0)
529                 return -ENODEV;
530
531         dbg("found matching attribute '%s' with value '%s'",
532             pair->file, pair->value);
533         return 0;
534 }
535
536 static int match_sysfs_pairs(struct config_device *dev, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
537 {
538         struct sysfs_pair *pair;
539         int i;
540
541         for (i = 0; i < MAX_SYSFS_PAIRS; ++i) {
542                 pair = &dev->sysfs_pair[i];
543                 if ((pair->file[0] == '\0') || (pair->value[0] == '\0'))
544                         break;
545                 if (compare_sysfs_attribute(class_dev, sysfs_device, pair) != 0) {
546                         dbg("sysfs attribute doesn't match");
547                         return -ENODEV;
548                 }
549         }
550
551         return 0;
552 }
553
554 static int match_id(struct config_device *dev, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
555 {
556         char path[SYSFS_PATH_MAX];
557         char *temp = NULL;
558
559         /* we have to have a sysfs device for ID to work */
560         if (!sysfs_device)
561                 return -ENODEV;
562
563         strfieldcpy(path, sysfs_device->path);
564         temp = strrchr(path, '/');
565         temp++;
566         dbg("search '%s' in '%s', path='%s'", dev->id, temp, path);
567         if (strcmp_pattern(dev->id, temp) != 0)
568                 return -ENODEV;
569         else
570                 return 0;
571 }
572
573 static int match_place(struct config_device *dev, struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
574 {
575         char path[SYSFS_PATH_MAX];
576         int found;
577         char *temp = NULL;
578
579         /* we have to have a sysfs device for PLACE to work */
580         if (!sysfs_device)
581                 return -ENODEV;
582
583         found = 0;
584         strfieldcpy(path, sysfs_device->path);
585         temp = strrchr(path, '/');
586         dbg("search '%s' in '%s', path='%s'", dev->place, temp, path);
587         if (strstr(temp, dev->place) != NULL) {
588                 found = 1;
589         } else {
590                 *temp = 0x00;
591                 temp = strrchr(path, '/');
592                 dbg("search '%s' in '%s', path='%s'", dev->place, temp, path);
593                 if (strstr(temp, dev->place) != NULL)
594                         found = 1;
595         }
596         if (!found) {
597                 dbg("place doesn't match");
598                 return -ENODEV;
599         }
600
601         return 0;
602 }
603
604 static struct sysfs_device *get_sysfs_device(struct sysfs_class_device *class_dev)
605 {
606         struct sysfs_device *sysfs_device;
607         struct sysfs_class_device *class_dev_parent;
608         struct timespec tspec;
609         int loop;
610
611         /* Figure out where the device symlink is at.  For char devices this will
612          * always be in the class_dev->path.  But for block devices, it's different.
613          * The main block device will have the device symlink in it's path, but
614          * all partitions have the symlink in its parent directory.
615          * But we need to watch out for block devices that do not have parents, yet
616          * look like a partition (fd0, loop0, etc.)  They all do not have a device
617          * symlink yet.  We do sit and spin on waiting for them right now, we should
618          * possibly have a whitelist for these devices here...
619          */
620         class_dev_parent = sysfs_get_classdev_parent(class_dev);
621         if (class_dev_parent) 
622                 dbg("Really a partition");
623
624         tspec.tv_sec = 0;
625         tspec.tv_nsec = 10000000;  /* sleep 10 millisec */
626         loop = 10;
627         while (loop--) {
628                 if (udev_sleep)
629                         nanosleep(&tspec, NULL);
630                 if (class_dev_parent)
631                         sysfs_device = sysfs_get_classdev_device(class_dev_parent);
632                 else
633                         sysfs_device = sysfs_get_classdev_device(class_dev);
634
635                 if (sysfs_device != NULL)
636                         goto device_found;
637         }
638         dbg("timed out waiting for device symlink, continuing on anyway...");
639         
640 device_found:
641         /* We have another issue with just the wait above - the sysfs part of
642          * the kernel may not be quick enough to have created the link to the
643          * device under the "bus" subsystem. Due to this, the sysfs_device->bus
644          * will not contain the actual bus name :(
645          *
646          * Libsysfs now provides a new API sysfs_get_device_bus(), so use it
647          * if needed
648          */
649         if (sysfs_device) {
650                 if (sysfs_device->bus[0] != '\0')
651                         goto bus_found;
652
653                 loop = 10;
654                 tspec.tv_nsec = 10000000;
655                 while (loop--) {
656                         if (udev_sleep)
657                                 nanosleep(&tspec, NULL);
658                         sysfs_get_device_bus(sysfs_device);
659                         
660                         if (sysfs_device->bus[0] != '\0')
661                                 goto bus_found;
662                 }
663                 dbg("timed out waiting to find the device bus, continuing on anyway");
664                 goto exit;
665 bus_found:
666                 dbg("device %s is registered with bus '%s'",
667                                 sysfs_device->name, sysfs_device->bus);
668         }
669 exit:
670         return sysfs_device;
671 }
672
673 static int match_rule(struct config_device *dev, struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
674 {
675         while (1) {
676                 /* check for matching bus value */
677                 if (dev->bus[0] != '\0') {
678                         if (sysfs_device == NULL) {
679                                 dbg("device has no bus");
680                                 goto try_parent;
681                         }
682                         dbg("check for " FIELD_BUS " dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
683                         if (strcmp_pattern(dev->bus, sysfs_device->bus) != 0) {
684                                 dbg(FIELD_BUS " is not matching");
685                                 goto try_parent;
686                         } else {
687                                 dbg(FIELD_BUS " matches");
688                         }
689                 }
690
691                 /* check for matching kernel name*/
692                 if (dev->kernel[0] != '\0') {
693                         dbg("check for " FIELD_KERNEL " dev->kernel='%s' class_dev->name='%s'", dev->kernel, class_dev->name);
694                         if (strcmp_pattern(dev->kernel, class_dev->name) != 0) {
695                                 dbg(FIELD_KERNEL " is not matching");
696                                 goto try_parent;
697                         } else {
698                                 dbg(FIELD_KERNEL " matches");
699                         }
700                 }
701
702                 /* check for matching bus id */
703                 if (dev->id[0] != '\0') {
704                         dbg("check " FIELD_ID);
705                         if (match_id(dev, class_dev, sysfs_device) != 0) {
706                                 dbg(FIELD_ID " is not matching");
707                                 goto try_parent;
708                         } else {
709                                 dbg(FIELD_ID " matches");
710                         }
711                 }
712
713                 /* check for matching place of device */
714                 if (dev->place[0] != '\0') {
715                         dbg("check " FIELD_PLACE);
716                         if (match_place(dev, class_dev, sysfs_device) != 0) {
717                                 dbg(FIELD_PLACE " is not matching");
718                                 goto try_parent;
719                         } else {
720                                 dbg(FIELD_PLACE " matches");
721                         }
722                 }
723
724                 /* check for matching sysfs pairs */
725                 if (dev->sysfs_pair[0].file[0] != '\0') {
726                         dbg("check " FIELD_SYSFS " pairs");
727                         if (match_sysfs_pairs(dev, class_dev, sysfs_device) != 0) {
728                                 dbg(FIELD_SYSFS " is not matching");
729                                 goto try_parent;
730                         } else {
731                                 dbg(FIELD_SYSFS " matches");
732                         }
733                 }
734
735                 /* execute external program */
736                 if (dev->program[0] != '\0') {
737                         dbg("check " FIELD_PROGRAM);
738                         apply_format(udev, dev->program, sizeof(dev->program),
739                                      class_dev, sysfs_device);
740                         if (execute_program(dev->program, udev->program_result, NAME_SIZE) != 0) {
741                                 dbg(FIELD_PROGRAM " returned nonzero");
742                                 goto try_parent;
743                         } else {
744                                 dbg(FIELD_PROGRAM " returned successful");
745                         }
746                 }
747
748                 /* check for matching result of external program */
749                 if (dev->result[0] != '\0') {
750                         dbg("check for " FIELD_RESULT
751                             " dev->result='%s', udev->program_result='%s'",
752                             dev->result, udev->program_result);
753                         if (strcmp_pattern(dev->result, udev->program_result) != 0) {
754                                 dbg(FIELD_RESULT " is not matching");
755                                 goto try_parent;
756                         } else {
757                                 dbg(FIELD_RESULT " matches");
758                         }
759                 }
760
761                 /* Yeah, we matched! */
762                 return 0;
763
764 try_parent:
765                 dbg("try parent sysfs device");
766                 sysfs_device = sysfs_get_device_parent(sysfs_device);
767                 if (sysfs_device == NULL)
768                         return -ENODEV;
769                 dbg("sysfs_device->path='%s'", sysfs_device->path);
770                 dbg("sysfs_device->bus_id='%s'", sysfs_device->bus_id);
771                 dbg("sysfs_device->bus='%s'", sysfs_device->bus);
772         }
773
774 }
775
776 int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *udev)
777 {
778         struct sysfs_device *sysfs_device = NULL;
779         struct config_device *dev;
780         struct perm_device *perm;
781         char *pos;
782
783         udev->mode = 0;
784
785         /* find the sysfs_device associated with this class device */
786         sysfs_device = get_sysfs_device(class_dev);
787         if (sysfs_device) {
788                 dbg("sysfs_device->path='%s'", sysfs_device->path);
789                 dbg("sysfs_device->bus_id='%s'", sysfs_device->bus_id);
790                 dbg("sysfs_device->bus='%s'", sysfs_device->bus);
791                 strfieldcpy(udev->bus_id, sysfs_device->bus_id);
792                 wait_for_device_to_initialize(sysfs_device);
793         }
794         dbg("class_dev->name = '%s'", class_dev->name);
795
796         strfieldcpy(udev->kernel_name, class_dev->name);
797         fix_kernel_name(udev);
798         dbg("udev->kernel_name = '%s'", udev->kernel_name);
799
800         /* get kernel number */
801         pos = class_dev->name + strlen(class_dev->name);
802         while (isdigit(*(pos-1)))
803                 pos--;
804         strfieldcpy(udev->kernel_number, pos);
805         dbg("kernel_number='%s'", udev->kernel_number);
806
807         /* look for a matching rule to apply */
808         list_for_each_entry(dev, &config_device_list, node) {
809                 dbg("process rule");
810                 if (match_rule(dev, class_dev, udev, sysfs_device) == 0) {
811                         if (dev->name[0] == '\0' && dev->symlink[0] == '\0') {
812                                 info("configured rule in '%s' at line %i applied, '%s' is ignored",
813                                      dev->config_file, dev->config_line, udev->kernel_name);
814                                 return -1;
815                         }
816
817                         if (dev->symlink[0] != '\0') {
818                                 info("configured rule in '%s' at line %i applied, added symlink '%s'",
819                                      dev->config_file, dev->config_line, dev->symlink);
820                                 if (udev->symlink[0] != '\0')
821                                         strfieldcat(udev->symlink, " ");
822                                 strfieldcat(udev->symlink, dev->symlink);
823                         }
824
825                         if (dev->name[0] != '\0') {
826                                 info("configured rule in '%s' at line %i applied, '%s' becomes '%s'",
827                                      dev->config_file, dev->config_line, udev->kernel_name, dev->name);
828                                 strfieldcpy(udev->name, dev->name);
829                                 goto found;
830                         }
831                 }
832         }
833
834         /* no rule was found so we use the kernel name */
835         strfieldcpy(udev->name, udev->kernel_name);
836         goto done;
837
838 found:
839         apply_format(udev, udev->name, sizeof(udev->name), class_dev, sysfs_device);
840         apply_format(udev, udev->symlink, sizeof(udev->symlink), class_dev, sysfs_device);
841         udev->partitions = dev->partitions;
842
843 done:
844         /* get permissions given in rule */
845         set_empty_perms(udev, dev->mode,
846                               dev->owner,
847                               dev->group);
848
849         /* get permissions given in config file or set defaults */
850         perm = find_perm(udev->name);
851         if (perm != NULL) {
852                 set_empty_perms(udev, perm->mode,
853                                       perm->owner,
854                                       perm->group);
855         } else {
856                 set_empty_perms(udev, get_default_mode(),
857                                       get_default_owner(),
858                                       get_default_group());
859         }
860
861         dbg("name, '%s' is going to have owner='%s', group='%s', mode = %#o",
862             udev->name, udev->owner, udev->group, udev->mode);
863
864         return 0;
865 }
866
867 int namedev_init(void)
868 {
869         int retval;
870
871         retval = namedev_init_rules();
872         if (retval)
873                 return retval;
874
875         retval = namedev_init_permissions();
876         if (retval)
877                 return retval;
878
879         dump_config_dev_list();
880         dump_perm_dev_list();
881         return retval;
882 }