chiark / gitweb /
[PATCH] clean up the way we find the sysdevice for a block device for namedev.
[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 /* define this to enable parsing debugging */
25 #define DEBUG_PARSER 
26
27 #include <stddef.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <ctype.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <sys/wait.h>
36
37 #include "list.h"
38 #include "udev.h"
39 #include "udev_version.h"
40 #include "namedev.h"
41 #include "libsysfs/libsysfs.h"
42
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"
48
49 static LIST_HEAD(config_device_list);
50
51 static void dump_dev(struct config_device *dev)
52 {
53         switch (dev->type) {
54         case KERNEL_NAME:
55                 dbg_parse("KERNEL name ='%s'"
56                         " owner = '%s', group = '%s', mode = '%#o'",
57                         dev->name, 
58                         dev->owner, dev->group, dev->mode);
59                 break;
60         case LABEL:
61                 dbg_parse("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'"
62                         " owner = '%s', group = '%s', mode = '%#o'",
63                         dev->name, dev->bus, dev->sysfs_file, dev->sysfs_value,
64                         dev->owner, dev->group, dev->mode);
65                 break;
66         case NUMBER:
67                 dbg_parse("NUMBER name = '%s', bus = '%s', id = '%s'"
68                         " owner = '%s', group = '%s', mode = '%#o'",
69                         dev->name, dev->bus, dev->id,
70                         dev->owner, dev->group, dev->mode);
71                 break;
72         case TOPOLOGY:
73                 dbg_parse("TOPOLOGY name = '%s', bus = '%s', place = '%s'"
74                         " owner = '%s', group = '%s', mode = '%#o'",
75                         dev->name, dev->bus, dev->place,
76                         dev->owner, dev->group, dev->mode);
77                 break;
78         case REPLACE:
79                 dbg_parse("REPLACE name = %s, kernel_name = %s"
80                         " owner = '%s', group = '%s', mode = '%#o'",
81                         dev->name, dev->kernel_name,
82                         dev->owner, dev->group, dev->mode);
83                 break;
84         case CALLOUT:
85                 dbg_parse("CALLOUT name = '%s', program ='%s', bus = '%s', id = '%s'"
86                         " owner = '%s', group = '%s', mode = '%#o'",
87                         dev->name, dev->exec_program, dev->bus, dev->id,
88                         dev->owner, dev->group, dev->mode);
89                 break;
90         default:
91                 dbg_parse("Unknown type of device!");
92         }
93 }
94
95 #define copy_var(a, b, var)             \
96         if (b->var)                     \
97                 a->var = b->var;
98
99 #define copy_string(a, b, var)          \
100         if (strlen(b->var))             \
101                 strcpy(a->var, b->var);
102
103 static int add_dev(struct config_device *new_dev)
104 {
105         struct list_head *tmp;
106         struct config_device *tmp_dev;
107
108         /* loop through the whole list of devices to see if we already have
109          * this one... */
110         list_for_each(tmp, &config_device_list) {
111                 struct config_device *dev = list_entry(tmp, struct config_device, node);
112                 if (strcmp(dev->name, new_dev->name) == 0) {
113                         /* the same, copy the new info into this structure */
114                         copy_var(dev, new_dev, type);
115                         copy_var(dev, new_dev, mode);
116                         copy_string(dev, new_dev, bus);
117                         copy_string(dev, new_dev, sysfs_file);
118                         copy_string(dev, new_dev, sysfs_value);
119                         copy_string(dev, new_dev, id);
120                         copy_string(dev, new_dev, place);
121                         copy_string(dev, new_dev, kernel_name);
122                         copy_string(dev, new_dev, owner);
123                         copy_string(dev, new_dev, group);
124                         return 0;
125                 }
126         }
127
128         /* not found, lets create a new structure, and add it to the list */
129         tmp_dev = malloc(sizeof(*tmp_dev));
130         if (!tmp_dev)
131                 return -ENOMEM;
132         memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
133         list_add(&tmp_dev->node, &config_device_list);
134         //dump_dev(tmp_dev);
135         return 0;
136 }
137
138 static void dump_dev_list(void)
139 {
140         struct list_head *tmp;
141
142         list_for_each(tmp, &config_device_list) {
143                 struct config_device *dev = list_entry(tmp, struct config_device, node);
144                 dump_dev(dev);
145         }
146 }
147
148 static int get_value(const char *left, char **orig_string, char **ret_string)
149 {
150         char *temp;
151         char *string = *orig_string;
152
153         /* eat any whitespace */
154         while (isspace(*string))
155                 ++string;
156
157         /* split based on '=' */
158         temp = strsep(&string, "=");
159         if (strcasecmp(temp, left) == 0) {
160                 /* got it, now strip off the '"' */
161                 while (isspace(*string))
162                         ++string;
163                 if (*string == '"')
164                         ++string;
165                 temp = strsep(&string, "\"");
166                 *ret_string = temp;
167                 *orig_string = string;
168                 return 0;
169         }
170         return -ENODEV;
171 }
172         
173 static int get_pair(char **orig_string, char **left, char **right)
174 {
175         char *temp;
176         char *string = *orig_string;
177
178         /* eat any whitespace */
179         while (isspace(*string))
180                 ++string;
181
182         /* split based on '=' */
183         temp = strsep(&string, "=");
184         *left = temp;
185
186         /* take the right side and strip off the '"' */
187         while (isspace(*string))
188                 ++string;
189         if (*string == '"')
190                 ++string;
191         temp = strsep(&string, "\"");
192         *right = temp;
193         *orig_string = string;
194         
195         return 0;
196 }
197
198 static int namedev_init_config(void)
199 {
200         char line[255];
201         char *temp;
202         char *temp2;
203         char *temp3;
204         FILE *fd;
205         int retval = 0;
206         struct config_device dev;
207
208         dbg("opening %s to read as config", udev_config_filename);
209         fd = fopen(udev_config_filename, "r");
210         if (fd == NULL) {
211                 dbg("Can't open %s", udev_config_filename);
212                 return -ENODEV;
213         }
214
215         /* loop through the whole file */
216         while (1) {
217                 /* get a line */
218                 temp = fgets(line, sizeof(line), fd);
219                 if (temp == NULL)
220                         break;
221
222                 dbg_parse("read %s", temp);
223
224                 /* eat the whitespace at the beginning of the line */
225                 while (isspace(*temp))
226                         ++temp;
227
228                 /* no more line? */
229                 if (*temp == 0x00)
230                         continue;
231
232                 /* see if this is a comment */
233                 if (*temp == COMMENT_CHARACTER)
234                         continue;
235
236                 memset(&dev, 0x00, sizeof(struct config_device));
237
238                 /* parse the line */
239                 temp2 = strsep(&temp, ",");
240                 if (strcasecmp(temp2, TYPE_LABEL) == 0) {
241                         /* label type */
242                         dev.type = LABEL;
243
244                         /* BUS="bus" */
245                         retval = get_value("BUS", &temp, &temp3);
246                         if (retval)
247                                 continue;
248                         strcpy(dev.bus, temp3);
249
250                         /* file="value" */
251                         temp2 = strsep(&temp, ",");
252                         retval = get_pair(&temp, &temp2, &temp3);
253                         if (retval)
254                                 continue;
255                         strcpy(dev.sysfs_file, temp2);
256                         strcpy(dev.sysfs_value, temp3);
257
258                         /* NAME="new_name" */
259                         temp2 = strsep(&temp, ",");
260                         retval = get_value("NAME", &temp, &temp3);
261                         if (retval)
262                                 continue;
263                         strcpy(dev.name, temp3);
264
265                         dbg_parse("LABEL name = '%s', bus = '%s', "
266                                 "sysfs_file = '%s', sysfs_value = '%s'", 
267                                 dev.name, dev.bus, dev.sysfs_file, 
268                                 dev.sysfs_value);
269                 }
270
271                 if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
272                         /* number type */
273                         dev.type = NUMBER;
274
275                         /* BUS="bus" */
276                         retval = get_value("BUS", &temp, &temp3);
277                         if (retval)
278                                 continue;
279                         strcpy(dev.bus, temp3);
280
281                         /* ID="id" */
282                         temp2 = strsep(&temp, ",");
283                         retval = get_value("id", &temp, &temp3);
284                         if (retval)
285                                 continue;
286                         strcpy(dev.id, temp3);
287
288                         /* NAME="new_name" */
289                         temp2 = strsep(&temp, ",");
290                         retval = get_value("NAME", &temp, &temp3);
291                         if (retval)
292                                 continue;
293                         strcpy(dev.name, temp3);
294
295                         dbg_parse("NUMBER name = '%s', bus = '%s', id = '%s'",
296                                         dev.name, dev.bus, dev.id);
297                 }
298
299                 if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
300                         /* number type */
301                         dev.type = TOPOLOGY;
302
303                         /* BUS="bus" */
304                         retval = get_value("BUS", &temp, &temp3);
305                         if (retval)
306                                 continue;
307                         strcpy(dev.bus, temp3);
308
309                         /* PLACE="place" */
310                         temp2 = strsep(&temp, ",");
311                         retval = get_value("place", &temp, &temp3);
312                         if (retval)
313                                 continue;
314                         strcpy(dev.place, temp3);
315
316                         /* NAME="new_name" */
317                         temp2 = strsep(&temp, ",");
318                         retval = get_value("NAME", &temp, &temp3);
319                         if (retval)
320                                 continue;
321                         strcpy(dev.name, temp3);
322
323                         dbg_parse("TOPOLOGY name = '%s', bus = '%s', place = '%s'",
324                                         dev.name, dev.bus, dev.place);
325                 }
326
327                 if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
328                         /* number type */
329                         dev.type = REPLACE;
330
331                         /* KERNEL="kernel_name" */
332                         retval = get_value("KERNEL", &temp, &temp3);
333                         if (retval)
334                                 continue;
335                         strcpy(dev.kernel_name, temp3);
336
337                         /* NAME="new_name" */
338                         temp2 = strsep(&temp, ",");
339                         retval = get_value("NAME", &temp, &temp3);
340                         if (retval)
341                                 continue;
342                         strcpy(dev.name, temp3);
343                         dbg_parse("REPLACE name = %s, kernel_name = %s",
344                                         dev.name, dev.kernel_name);
345                 }
346                 if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
347                         /* number type */
348                         dev.type = CALLOUT;
349
350                         /* PROGRAM="executable" */
351                         retval = get_value("PROGRAM", &temp, &temp3);
352                         if (retval)
353                                 continue;
354                         strcpy(dev.exec_program, temp3);
355
356                         /* BUS="bus" */
357                         temp2 = strsep(&temp, ",");
358                         retval = get_value("BUS", &temp, &temp3);
359                         if (retval)
360                                 continue;
361                         strcpy(dev.bus, temp3);
362
363                         /* ID="id" */
364                         temp2 = strsep(&temp, ",");
365                         retval = get_value("ID", &temp, &temp3);
366                         if (retval)
367                                 continue;
368                         strcpy(dev.id, temp3);
369
370                         /* NAME="new_name" */
371                         temp2 = strsep(&temp, ",");
372                         retval = get_value("NAME", &temp, &temp3);
373                         if (retval)
374                                 continue;
375                         strcpy(dev.name, temp3);
376                         dbg_parse("CALLOUT name = %s, program = %s",
377                                         dev.name, dev.exec_program);
378                 }
379
380                 retval = add_dev(&dev);
381                 if (retval) {
382                         dbg("add_dev returned with error %d", retval);
383                         goto exit;
384                 }
385         }
386
387 exit:
388         fclose(fd);
389         return retval;
390 }       
391
392
393 static int namedev_init_permissions(void)
394 {
395         char line[255];
396         char *temp;
397         char *temp2;
398         FILE *fd;
399         int retval = 0;
400         struct config_device dev;
401
402         dbg("opening %s to read as permissions config", udev_config_permission_filename);
403         fd = fopen(udev_config_permission_filename, "r");
404         if (fd == NULL) {
405                 dbg("Can't open %s", udev_config_permission_filename);
406                 return -ENODEV;
407         }
408
409         /* loop through the whole file */
410         while (1) {
411                 /* get a line */
412                 temp = fgets(line, sizeof(line), fd);
413                 if (temp == NULL)
414                         break;
415
416                 dbg_parse("read %s", temp);
417
418                 /* eat the whitespace at the beginning of the line */
419                 while (isspace(*temp))
420                         ++temp;
421
422                 /* no more line? */
423                 if (*temp == 0x00)
424                         continue;
425
426                 /* see if this is a comment */
427                 if (*temp == COMMENT_CHARACTER)
428                         continue;
429
430                 memset(&dev, 0x00, sizeof(dev));
431
432                 /* parse the line */
433                 temp2 = strsep(&temp, ":");
434                 strncpy(dev.name, temp2, sizeof(dev.name));
435
436                 temp2 = strsep(&temp, ":");
437                 strncpy(dev.owner, temp2, sizeof(dev.owner));
438
439                 temp2 = strsep(&temp, ":");
440                 strncpy(dev.group, temp2, sizeof(dev.owner));
441
442                 dev.mode = strtol(temp, NULL, 8);
443
444                 dbg_parse("name = %s, owner = %s, group = %s, mode = %#o",
445                                 dev.name, dev.owner, dev.group,
446                                 dev.mode);
447                 retval = add_dev(&dev);
448                 if (retval) {
449                         dbg("add_dev returned with error %d", retval);
450                         goto exit;
451                 }
452         }
453
454 exit:
455         fclose(fd);
456         return retval;
457 }       
458
459 static mode_t get_default_mode(struct sysfs_class_device *class_dev)
460 {
461         /* just default everyone to rw for the world! */
462         return 0666;
463 }
464
465
466 static int exec_callout(struct config_device *dev, char *value, int len)
467 {
468         int retval;
469         int res;
470         int status;
471         int fds[2];
472         pid_t pid;
473         int value_set = 0;
474         char buffer[256];
475
476         dbg("callout to %s\n", dev->exec_program);
477         retval = pipe(fds);
478         if (retval != 0) {
479                 dbg("pipe failed");
480                 return -1;
481         }
482         pid = fork();
483         if (pid == -1) {
484                 dbg("fork failed");
485                 return -1;
486         }
487
488         if (pid == 0) {
489                 /*
490                  * child 
491                  */
492                 close(STDOUT_FILENO);
493                 dup(fds[1]);    /* dup write side of pipe to STDOUT */
494                 retval = execve(dev->exec_program, main_argv, main_envp);
495                 if (retval != 0) {
496                         dbg("child execve failed");
497                         exit(1);
498                 }
499                 return -1; /* avoid compiler warning */
500         } else {
501                 /*
502                  * Parent reads from fds[0].
503                  */
504                 close(fds[1]);
505                 retval = 0;
506                 while (1) {
507                         res = read(fds[0], buffer, sizeof(buffer) - 1);
508                         if (res <= 0)
509                                 break;
510                         buffer[res] = '\0';
511                         if (res > len) {
512                                 dbg("callout len %d too short\n", len);
513                                 retval = -1;
514                         }
515                         if (value_set) {
516                                 dbg("callout value already set");
517                                 retval = -1;
518                         } else {
519                                 value_set = 1;
520                                 strncpy(value, buffer, len);
521                         }
522                 }
523                 close(fds[0]);
524                 res = wait(&status);
525                 if (res < 0) {
526                         dbg("wait failed result %d", res);
527                         retval = -1;
528                 }
529
530 #ifndef __KLIBC__
531                 if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
532                         dbg("callout program status 0x%x", status);
533                         retval = -1;
534                 }
535 #endif
536         }
537         return retval;
538 }
539
540 static int do_callout(struct sysfs_class_device *class_dev, struct udevice *udev)
541 {
542         struct config_device *dev;
543         struct list_head *tmp;
544         char value[ID_SIZE];
545
546         list_for_each(tmp, &config_device_list) {
547                 dev = list_entry(tmp, struct config_device, node);
548                 if (dev->type != CALLOUT)
549                         continue;
550
551                 if (exec_callout(dev, value, sizeof(value)))
552                         continue;
553                 if (strncmp(value, dev->id, sizeof(value)) != 0)
554                         continue;
555                 strcpy(udev->name, dev->name);
556                 if (dev->mode != 0) {
557                         udev->mode = dev->mode;
558                         strcpy(udev->owner, dev->owner);
559                         strcpy(udev->group, dev->group);
560                 }
561                 dbg_parse("device callout '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
562                         dev->id, udev->name, 
563                         dev->owner, dev->group, dev->mode);
564                 return 0;
565         }
566         return -ENODEV;
567 }
568
569 static int do_replace(struct sysfs_class_device *class_dev, struct udevice *udev)
570 {
571         struct config_device *dev;
572         struct list_head *tmp;
573
574         list_for_each(tmp, &config_device_list) {
575                 dev = list_entry(tmp, struct config_device, node);
576                 if (dev->type != REPLACE)
577                         continue;
578
579                 dbg_parse("REPLACE: replace name '%s' with '%s'",
580                           dev->kernel_name, dev->name);
581                 if (strcmp(dev->kernel_name, class_dev->name) != 0)
582                         continue;
583
584                 strcpy(udev->name, dev->name);
585                 if (dev->mode != 0) {
586                         udev->mode = dev->mode;
587                         strcpy(udev->owner, dev->owner);
588                         strcpy(udev->group, dev->group);
589                 }
590                 dbg_parse("'%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
591                         dev->kernel_name, udev->name, 
592                         dev->owner, dev->group, dev->mode);
593                 
594                 return 0;
595         }
596         return -ENODEV;
597 }
598
599 static int get_attr(struct sysfs_class_device *class_dev, struct udevice *udev)
600 {
601         struct list_head *tmp;
602         struct sysfs_device *sysfs_device = NULL;
603         struct sysfs_class_device *class_dev_parent = NULL;
604         int retval = 0;
605         int found;
606         char *temp = NULL;
607
608         udev->mode = 0;
609
610         /* find the sysfs_device for this class device */
611         if (class_dev->sysdevice) {
612                 sysfs_device = class_dev->sysdevice;
613         } else {
614                 /* bah, let's go backwards up a level to see if the device is there,
615                  * as block partitions don't point to the physical device.  Need to fix that
616                  * up in the kernel...
617                  */
618                 if (strstr(class_dev->path, "block")) {
619                         dbg_parse("looking at block device...");
620                         if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
621                                 char path[SYSFS_PATH_MAX];
622
623                                 dbg_parse("really is a partition...");
624                                 strcpy(path, class_dev->path);
625                                 temp = strrchr(path, '/');
626                                 *temp = 0x00;
627                                 dbg_parse("looking for a class device at '%s'", path);
628                                 class_dev_parent = sysfs_open_class_device(path);
629                                 if (class_dev_parent == NULL) {
630                                         dbg("sysfs_open_class_device at '%s' failed", path);
631                                 } else {
632                                         dbg_parse("class_dev_parent->name = %s", class_dev_parent->name);
633                                         if (class_dev_parent->sysdevice)
634                                                 sysfs_device = class_dev_parent->sysdevice;
635                                 }
636                         }
637                 }
638         }
639                 
640         if (sysfs_device) {
641                 dbg_parse("sysfs_device->path = '%s'", sysfs_device->path);
642                 dbg_parse("sysfs_device->bus_id = '%s'", sysfs_device->bus_id);
643         } else {
644                 dbg_parse("class_dev->name = '%s'", class_dev->name);
645         }
646         list_for_each(tmp, &config_device_list) {
647                 struct config_device *dev = list_entry(tmp, struct config_device, node);
648                 switch (dev->type) {
649                 case LABEL:
650                         {
651                         struct sysfs_attribute *tmpattr = NULL;
652
653                         dbg_parse("LABEL: match file '%s' with value '%s'",
654                                         dev->sysfs_file, dev->sysfs_value);
655                         /* try to find the attribute in the class device directory */
656                         tmpattr = sysfs_get_classdev_attr(class_dev, dev->sysfs_file);
657                         if (tmpattr)
658                                 goto label_found;
659
660                         /* look in the class device directory if present */
661                         if (sysfs_device) {
662                                 tmpattr = sysfs_get_device_attr(sysfs_device, dev->sysfs_file);
663                                 if (tmpattr)
664                                         goto label_found;
665                         }
666
667                         continue;
668
669 label_found:
670                         tmpattr->value[strlen(tmpattr->value)-1] = 0x00;
671                         dbg_parse("file '%s' found with value '%s' compare with '%s'", dev->sysfs_file, tmpattr->value, dev->sysfs_value);
672                         if (strcmp(dev->sysfs_value, tmpattr->value) != 0)
673                                 continue;
674
675                         strcpy(udev->name, dev->name);
676                         if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
677                                 temp = &class_dev->path[strlen(class_dev->path)-1];
678                                 strcat(udev->name, temp);
679                         }
680                         if (dev->mode != 0) {
681                                 udev->mode = dev->mode;
682                                 strcpy(udev->owner, dev->owner);
683                                 strcpy(udev->group, dev->group);
684                         }
685                         dbg_parse("file '%s' with value '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
686                                 dev->sysfs_file, dev->sysfs_value, udev->name, 
687                                 dev->owner, dev->group, dev->mode);
688                         goto done;
689                         break;
690                         }
691                 case NUMBER:
692                         {
693                         char path[SYSFS_PATH_MAX];
694                         char *temp;
695
696                         found = 0;
697                         if (!class_dev->sysdevice)
698                                 continue;
699                         strcpy(path, class_dev->sysdevice->path);
700                         temp = strrchr(path, '/');
701                         dbg_parse("NUMBER path = '%s'", path);
702                         dbg_parse("NUMBER temp = '%s' id = '%s'", temp, dev->id);
703                         if (strstr(temp, dev->id) != NULL) {
704                                 found = 1;
705                         } else {
706                                 *temp = 0x00;
707                                 temp = strrchr(path, '/');
708                                 dbg_parse("NUMBERY temp = '%s' id = '%s'", temp, dev->id);
709                                 if (strstr(temp, dev->id) != NULL)
710                                         found = 1;
711                         }
712                         if (!found)
713                                 continue;
714
715                         strcpy(udev->name, dev->name);
716                         if (dev->mode != 0) {
717                                 udev->mode = dev->mode;
718                                 strcpy(udev->owner, dev->owner);
719                                 strcpy(udev->group, dev->group);
720                         }
721                         dbg_parse("device id '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
722                                 dev->id, udev->name, 
723                                 dev->owner, dev->group, dev->mode);
724                         goto done;
725                         break;
726                         }
727                 case TOPOLOGY:
728                         {
729                         char path[SYSFS_PATH_MAX];
730                         char *temp;
731
732                         if (!class_dev->sysdevice)
733                                 continue;
734                         found = 0;      
735                         strcpy(path, class_dev->sysdevice->path);
736                         temp = strrchr(path, '/');
737                         dbg_parse("TOPOLOGY path = '%s'", path);
738                         dbg_parse("TOPOLOGY temp = '%s' place = '%s'", temp, dev->place);
739                         if (strstr(temp, dev->place) != NULL) {
740                                 found = 1;
741                         } else {
742                                 *temp = 0x00;
743                                 temp = strrchr(path, '/');
744                                 dbg_parse("TOPOLOGY temp = '%s' place = '%s'", temp, dev->place);
745                                 if (strstr(temp, dev->place) != NULL)
746                                         found = 1;
747                         }
748                         if (!found)
749                                 continue;
750
751                         strcpy(udev->name, dev->name);
752                         if (dev->mode != 0) {
753                                 udev->mode = dev->mode;
754                                 strcpy(udev->owner, dev->owner);
755                                 strcpy(udev->group, dev->group);
756                         }
757                         dbg_parse("device at '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
758                                 dev->place, udev->name, 
759                                 dev->owner, dev->group, dev->mode);
760                         goto done;
761                         break;
762                         }
763                 case KERNEL_NAME:
764                 default:
765                         break;
766                 }       
767         }
768
769         /* rules are looked at in priority order */
770
771         retval = do_callout(class_dev, udev);
772         if (retval == 0)
773                 goto done;
774
775         retval = do_replace(class_dev, udev);
776         if (retval == 0)
777                 goto done;
778
779         strcpy(udev->name, class_dev->name);
780
781 done:
782         /* mode was never set above */
783         if (!udev->mode) {
784                 udev->mode = get_default_mode(class_dev);
785                 udev->owner[0] = 0x00;
786                 udev->group[0] = 0x00;
787         }
788
789         if (class_dev_parent)
790                 sysfs_close_class_device(class_dev_parent);
791
792         return 0;
793 }
794
795 int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *dev)
796 {
797         int retval;
798
799         retval = get_attr(class_dev, dev);
800         if (retval)
801                 dbg("get_attr failed");
802
803         return retval;
804 }
805
806 int namedev_init(void)
807 {
808         int retval;
809         
810         retval = namedev_init_config();
811         if (retval)
812                 return retval;
813
814         retval = namedev_init_permissions();
815         if (retval)
816                 return retval;
817
818         dump_dev_list();
819         return retval;
820 }
821
822