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