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