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