6 * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
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.
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.
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.
35 #include "udev_version.h"
37 #include "libsysfs/libsysfs.h"
39 #define TYPE_LABEL "LABEL"
40 #define TYPE_NUMBER "NUMBER"
41 #define TYPE_TOPOLOGY "TOPOLOGY"
42 #define TYPE_REPLACE "REPLACE"
44 static LIST_HEAD(config_device_list
);
46 static void dump_dev(struct config_device
*dev
)
50 dbg("KERNEL name ='%s'"
51 " owner = '%s', group = '%s', mode = '%#o'",
53 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
56 dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'"
57 " owner = '%s', group = '%s', mode = '%#o'",
58 dev
->attr
.name
, dev
->bus
, dev
->sysfs_file
, dev
->sysfs_value
,
59 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
62 dbg("NUMBER name = '%s', bus = '%s', id = '%s'"
63 " owner = '%s', group = '%s', mode = '%#o'",
64 dev
->attr
.name
, dev
->bus
, dev
->id
,
65 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
68 dbg("TOPOLOGY name = '%s', bus = '%s', place = '%s'"
69 " owner = '%s', group = '%s', mode = '%#o'",
70 dev
->attr
.name
, dev
->bus
, dev
->place
,
71 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
74 dbg("REPLACE name = %s, kernel_name = %s"
75 " owner = '%s', group = '%s', mode = '%#o'",
76 dev
->attr
.name
, dev
->kernel_name
,
77 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
80 dbg("Unknown type of device!");
84 #define copy_var(a, b, var) \
88 #define copy_string(a, b, var) \
90 strcpy(a->var, b->var);
92 static int add_dev(struct config_device
*new_dev
)
94 struct list_head
*tmp
;
95 struct config_device
*tmp_dev
;
97 /* loop through the whole list of devices to see if we already have
99 list_for_each(tmp
, &config_device_list
) {
100 struct config_device
*dev
= list_entry(tmp
, struct config_device
, node
);
101 if (strcmp(dev
->attr
.name
, new_dev
->attr
.name
) == 0) {
102 /* the same, copy the new info into this structure */
103 copy_var(dev
, new_dev
, type
);
104 copy_var(dev
, new_dev
, attr
.mode
);
105 copy_string(dev
, new_dev
, bus
);
106 copy_string(dev
, new_dev
, sysfs_file
);
107 copy_string(dev
, new_dev
, sysfs_value
);
108 copy_string(dev
, new_dev
, id
);
109 copy_string(dev
, new_dev
, place
);
110 copy_string(dev
, new_dev
, kernel_name
);
111 copy_string(dev
, new_dev
, attr
.owner
);
112 copy_string(dev
, new_dev
, attr
.group
);
117 /* not found, lets create a new structure, and add it to the list */
118 tmp_dev
= malloc(sizeof(*tmp_dev
));
121 memcpy(tmp_dev
, new_dev
, sizeof(*tmp_dev
));
122 list_add(&tmp_dev
->node
, &config_device_list
);
127 static void dump_dev_list(void)
129 struct list_head
*tmp
;
131 list_for_each(tmp
, &config_device_list
) {
132 struct config_device
*dev
= list_entry(tmp
, struct config_device
, node
);
137 static int get_value(const char *left
, char **orig_string
, char **ret_string
)
140 char *string
= *orig_string
;
142 /* eat any whitespace */
143 while (isspace(*string
))
146 /* split based on '=' */
147 temp
= strsep(&string
, "=");
148 if (strcasecmp(temp
, left
) == 0) {
149 /* got it, now strip off the '"' */
150 while (isspace(*string
))
154 temp
= strsep(&string
, "\"");
156 *orig_string
= string
;
162 static int get_pair(char **orig_string
, char **left
, char **right
)
165 char *string
= *orig_string
;
167 /* eat any whitespace */
168 while (isspace(*string
))
171 /* split based on '=' */
172 temp
= strsep(&string
, "=");
175 /* take the right side and strip off the '"' */
176 while (isspace(*string
))
180 temp
= strsep(&string
, "\"");
182 *orig_string
= string
;
187 static int namedev_init_config(void)
196 struct config_device dev
;
198 strcpy(filename
, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_FILE
);
199 dbg("opening %s to read as permissions config", filename
);
200 fd
= fopen(filename
, "r");
202 dbg("Can't open %s", filename
);
206 /* loop through the whole file */
209 temp
= fgets(line
, sizeof(line
), fd
);
213 dbg("read %s", temp
);
215 /* eat the whitespace at the beginning of the line */
216 while (isspace(*temp
))
223 /* see if this is a comment */
224 if (*temp
== COMMENT_CHARACTER
)
227 memset(&dev
, 0x00, sizeof(struct config_device
));
230 temp2
= strsep(&temp
, ",");
231 if (strcasecmp(temp2
, TYPE_LABEL
) == 0) {
236 retval
= get_value("BUS", &temp
, &temp3
);
239 strcpy(dev
.bus
, temp3
);
242 temp2
= strsep(&temp
, ",");
243 retval
= get_pair(&temp
, &temp2
, &temp3
);
246 strcpy(dev
.sysfs_file
, temp2
);
247 strcpy(dev
.sysfs_value
, temp3
);
249 /* NAME="new_name" */
250 temp2
= strsep(&temp
, ",");
251 retval
= get_value("NAME", &temp
, &temp3
);
254 strcpy(dev
.attr
.name
, temp3
);
256 dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'", dev
.attr
.name
, dev
.bus
, dev
.sysfs_file
, dev
.sysfs_value
);
259 if (strcasecmp(temp2
, TYPE_NUMBER
) == 0) {
264 retval
= get_value("BUS", &temp
, &temp3
);
267 strcpy(dev
.bus
, temp3
);
270 temp2
= strsep(&temp
, ",");
271 retval
= get_value("id", &temp
, &temp3
);
274 strcpy(dev
.id
, temp3
);
276 /* NAME="new_name" */
277 temp2
= strsep(&temp
, ",");
278 retval
= get_value("NAME", &temp
, &temp3
);
281 strcpy(dev
.attr
.name
, temp3
);
283 dbg("NUMBER name = '%s', bus = '%s', id = '%s'", dev
.attr
.name
, dev
.bus
, dev
.id
);
286 if (strcasecmp(temp2
, TYPE_TOPOLOGY
) == 0) {
291 retval
= get_value("BUS", &temp
, &temp3
);
294 strcpy(dev
.bus
, temp3
);
297 temp2
= strsep(&temp
, ",");
298 retval
= get_value("place", &temp
, &temp3
);
301 strcpy(dev
.place
, temp3
);
303 /* NAME="new_name" */
304 temp2
= strsep(&temp
, ",");
305 retval
= get_value("NAME", &temp
, &temp3
);
308 strcpy(dev
.attr
.name
, temp3
);
310 dbg("TOPOLOGY name = '%s', bus = '%s', place = '%s'", dev
.attr
.name
, dev
.bus
, dev
.place
);
313 if (strcasecmp(temp2
, TYPE_REPLACE
) == 0) {
317 /* KERNEL="kernel_name" */
318 retval
= get_value("KERNEL", &temp
, &temp3
);
321 strcpy(dev
.kernel_name
, temp3
);
323 /* NAME="new_name" */
324 temp2
= strsep(&temp
, ",");
325 retval
= get_value("NAME", &temp
, &temp3
);
328 strcpy(dev
.attr
.name
, temp3
);
329 dbg("REPLACE name = %s, kernel_name = %s", dev
.attr
.name
, dev
.kernel_name
);
332 retval
= add_dev(&dev
);
334 dbg("add_dev returned with error %d", retval
);
345 static int namedev_init_permissions(void)
353 struct config_device dev
;
355 strcpy(filename
, NAMEDEV_CONFIG_ROOT NAMEDEV_CONFIG_PERMISSION_FILE
);
356 dbg("opening %s to read as permissions config", filename
);
357 fd
= fopen(filename
, "r");
359 dbg("Can't open %s", filename
);
363 /* loop through the whole file */
366 temp
= fgets(line
, sizeof(line
), fd
);
370 dbg("read %s", temp
);
372 /* eat the whitespace at the beginning of the line */
373 while (isspace(*temp
))
380 /* see if this is a comment */
381 if (*temp
== COMMENT_CHARACTER
)
384 memset(&dev
, 0x00, sizeof(dev
));
387 temp2
= strsep(&temp
, ":");
388 strncpy(dev
.attr
.name
, temp2
, sizeof(dev
.attr
.name
));
390 temp2
= strsep(&temp
, ":");
391 strncpy(dev
.attr
.owner
, temp2
, sizeof(dev
.attr
.owner
));
393 temp2
= strsep(&temp
, ":");
394 strncpy(dev
.attr
.group
, temp2
, sizeof(dev
.attr
.owner
));
396 dev
.attr
.mode
= strtol(temp
, NULL
, 8);
398 dbg("name = %s, owner = %s, group = %s, mode = %#o", dev
.attr
.name
, dev
.attr
.owner
, dev
.attr
.group
, dev
.attr
.mode
);
399 retval
= add_dev(&dev
);
401 dbg("add_dev returned with error %d", retval
);
411 static int get_default_mode(struct sysfs_class_device
*class_dev
)
413 /* just default everyone to rw for the world! */
418 static int get_attr(struct sysfs_class_device
*class_dev
, struct device_attr
*attr
)
420 struct list_head
*tmp
;
424 if (class_dev
->sysdevice
) {
425 dbg("class_dev->sysdevice->directory->path = '%s'", class_dev
->sysdevice
->directory
->path
);
426 dbg("class_dev->sysdevice->bus_id = '%s'", class_dev
->sysdevice
->bus_id
);
428 dbg("class_dev->name = '%s'", class_dev
->name
);
430 list_for_each(tmp
, &config_device_list
) {
431 struct config_device
*dev
= list_entry(tmp
, struct config_device
, node
);
437 dbg("LABEL: match file '%s' with value '%s'", dev
->sysfs_file
, dev
->sysfs_value
);
438 /* try to find the attribute in the class device directory */
439 temp
= sysfs_get_value_from_attributes(class_dev
->directory
->attributes
, dev
->sysfs_file
);
443 /* look in the class device device directory if present */
444 if (class_dev
->sysdevice
) {
445 temp
= sysfs_get_value_from_attributes(class_dev
->sysdevice
->directory
->attributes
, dev
->sysfs_file
);
450 /* bah, let's go backwards up a level to see if the device is there,
451 * as block partitions don't point to the physical device. Need to fix that
452 * up in the kernel...
454 if (strstr(class_dev
->directory
->path
, "block")) {
455 dbg("looking at block device...");
456 if (isdigit(class_dev
->directory
->path
[strlen(class_dev
->directory
->path
)-1])) {
457 char path
[SYSFS_PATH_MAX
];
458 struct sysfs_class_device
*class_dev_parent
;
460 dbg("really is a partition...");
461 strcpy(path
, class_dev
->directory
->path
);
462 temp
= strrchr(path
, '/');
464 dbg("looking for a class device at '%s'", path
);
465 class_dev_parent
= sysfs_open_class_device(path
);
466 if (class_dev_parent
== NULL
) {
467 dbg ("sysfs_open_class_device failed");
470 dbg("class_dev_parent->name = %s", class_dev_parent
->name
);
472 /* try to find the attribute in the class device directory */
473 temp
= sysfs_get_value_from_attributes(class_dev_parent
->directory
->attributes
, dev
->sysfs_file
);
475 //sysfs_close_class_device(class_dev_parent);
479 /* look in the class device device directory if present */
480 if (class_dev_parent
->sysdevice
) {
481 temp
= sysfs_get_value_from_attributes(class_dev_parent
->sysdevice
->directory
->attributes
, dev
->sysfs_file
);
483 // sysfs_close_class_device(class_dev_parent);
493 dbg("file '%s' found with value '%s'", dev
->sysfs_file
, temp
);
494 if (strcmp(dev
->sysfs_value
, temp
) != 0)
497 strcpy(attr
->name
, dev
->attr
.name
);
498 attr
->mode
= dev
->attr
.mode
;
499 strcpy(attr
->owner
, dev
->attr
.owner
);
500 strcpy(attr
->group
, dev
->attr
.group
);
501 dbg("file '%s' with value '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
502 dev
->sysfs_file
, dev
->sysfs_value
, attr
->name
,
503 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
505 dbg("LABEL name = '%s', bus = '%s', sysfs_file = '%s', sysfs_value = '%s'"
506 " owner = '%s', group = '%s', mode = '%#o'",
507 dev
->attr
.name
, dev
->bus
, dev
->sysfs_file
, dev
->sysfs_value
,
508 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
513 char path
[SYSFS_PATH_MAX
];
517 if (!class_dev
->sysdevice
)
519 strcpy(path
, class_dev
->sysdevice
->directory
->path
);
520 temp
= strrchr(path
, '/');
521 dbg("NUMBER path = '%s'", path
);
522 dbg("NUMBER temp = '%s' id = '%s'", temp
, dev
->id
);
523 if (strstr(temp
, dev
->id
) != NULL
) {
527 temp
= strrchr(path
, '/');
528 dbg("TOPOLOGY temp = '%s' id = '%s'", temp
, dev
->id
);
529 if (strstr(temp
, dev
->id
) != NULL
)
535 strcpy(attr
->name
, dev
->attr
.name
);
536 attr
->mode
= dev
->attr
.mode
;
537 strcpy(attr
->owner
, dev
->attr
.owner
);
538 strcpy(attr
->group
, dev
->attr
.group
);
539 dbg("device id '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
541 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
547 char path
[SYSFS_PATH_MAX
];
550 if (!class_dev
->sysdevice
)
553 strcpy(path
, class_dev
->sysdevice
->directory
->path
);
554 temp
= strrchr(path
, '/');
555 dbg("TOPOLOGY path = '%s'", path
);
556 dbg("TOPOLOGY temp = '%s' place = '%s'", temp
, dev
->place
);
557 if (strstr(temp
, dev
->place
) != NULL
) {
561 temp
= strrchr(path
, '/');
562 dbg("TOPOLOGY temp = '%s' place = '%s'", temp
, dev
->place
);
563 if (strstr(temp
, dev
->place
) != NULL
)
569 strcpy(attr
->name
, dev
->attr
.name
);
570 attr
->mode
= dev
->attr
.mode
;
571 strcpy(attr
->owner
, dev
->attr
.owner
);
572 strcpy(attr
->group
, dev
->attr
.group
);
573 dbg("device at '%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
574 dev
->place
, attr
->name
,
575 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
580 if (strcmp(dev
->kernel_name
, class_dev
->name
) != 0)
582 strcpy(attr
->name
, dev
->attr
.name
);
583 attr
->mode
= dev
->attr
.mode
;
584 strcpy(attr
->owner
, dev
->attr
.owner
);
585 strcpy(attr
->group
, dev
->attr
.group
);
586 dbg("'%s' becomes '%s' - owner = %s, group = %s, mode = %#o",
587 dev
->kernel_name
, attr
->name
,
588 dev
->attr
.owner
, dev
->attr
.group
, dev
->attr
.mode
);
594 dbg("Unknown type of device '%d'", dev
->type
);
598 attr
->mode
= get_default_mode(class_dev
);
599 attr
->owner
[0] = 0x00;
600 attr
->group
[0] = 0x00;
601 strcpy(attr
->name
, class_dev
->name
);
605 int namedev_name_device(struct sysfs_class_device
*class_dev
, struct device_attr
*attr
)
609 retval
= get_attr(class_dev
, attr
);
611 dbg("get_attr failed");
616 int namedev_init(void)
620 retval
= namedev_init_config();
624 retval
= namedev_init_permissions();