]>
git.ipfire.org Git - thirdparty/systemd.git/blob - namedev.c
86685f8393fd05859f6e3d327ef18ebe2523b3c4
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.
36 #include "udev_version.h"
38 #include "libsysfs/libsysfs.h"
39 #include "klibc_fixups.h"
41 LIST_HEAD(config_device_list
);
43 /* s2 may end with '*' to match everything */
44 static int strncmp_wildcard(char *s1
, char *s2
, int max
)
53 return strncmp(s1
, s2
, len
);
56 #define copy_var(a, b, var) \
60 #define copy_string(a, b, var) \
62 strcpy(a->var, b->var);
64 int add_config_dev(struct config_device
*new_dev
)
66 struct list_head
*tmp
;
67 struct config_device
*tmp_dev
;
69 /* update the values if we already have the device */
70 list_for_each(tmp
, &config_device_list
) {
71 struct config_device
*dev
= list_entry(tmp
, struct config_device
, node
);
72 if (strncmp_wildcard(dev
->name
, new_dev
->name
, sizeof(dev
->name
)))
74 if (strncmp(dev
->bus
, new_dev
->bus
, sizeof(dev
->name
)))
76 copy_var(dev
, new_dev
, type
);
77 copy_var(dev
, new_dev
, mode
);
78 copy_string(dev
, new_dev
, bus
);
79 copy_string(dev
, new_dev
, sysfs_file
);
80 copy_string(dev
, new_dev
, sysfs_value
);
81 copy_string(dev
, new_dev
, id
);
82 copy_string(dev
, new_dev
, place
);
83 copy_string(dev
, new_dev
, kernel_name
);
84 copy_string(dev
, new_dev
, exec_program
);
85 copy_string(dev
, new_dev
, owner
);
86 copy_string(dev
, new_dev
, group
);
90 /* not found, add new structure to the device list */
91 tmp_dev
= malloc(sizeof(*tmp_dev
));
94 memcpy(tmp_dev
, new_dev
, sizeof(*tmp_dev
));
95 list_add_tail(&tmp_dev
->node
, &config_device_list
);
96 //dump_config_dev(tmp_dev);
100 static mode_t
get_default_mode(struct sysfs_class_device
*class_dev
)
102 /* just default everyone to rw for the world! */
106 static void build_kernel_number(struct sysfs_class_device
*class_dev
, struct udevice
*udev
)
110 /* FIXME, figure out how to handle stuff like sdaj which will not work right now. */
111 dig
= class_dev
->name
+ strlen(class_dev
->name
);
112 while (isdigit(*(dig
-1)))
114 strfieldcpy(udev
->kernel_number
, dig
);
115 dbg("kernel_number='%s'", udev
->kernel_number
);
118 static void apply_format(struct udevice
*udev
, unsigned char *string
)
120 char name
[NAME_SIZE
];
124 pos
= strchr(string
, '%');
127 strfieldcpy(name
, pos
+2);
131 if (strlen(udev
->bus_id
) == 0)
133 strcat(pos
, udev
->bus_id
);
134 dbg("substitute bus_id '%s'", udev
->bus_id
);
137 if (strlen(udev
->kernel_number
) == 0)
139 strcat(pos
, udev
->kernel_number
);
140 dbg("substitute kernel number '%s'", udev
->kernel_number
);
143 if (strlen(udev
->kernel_number
) == 0) {
148 strcat(pos
, udev
->kernel_number
);
149 dbg("substitute kernel number '%s'", udev
->kernel_number
);
152 sprintf(pos
, "%u", udev
->minor
);
153 dbg("substitute minor number '%u'", udev
->minor
);
156 sprintf(pos
, "%u", udev
->major
);
157 dbg("substitute major number '%u'", udev
->major
);
160 if (strlen(udev
->callout_value
) == 0)
162 strcat(pos
, udev
->callout_value
);
163 dbg("substitute callout output '%s'", udev
->callout_value
);
166 dbg("unknown substitution type '%%%c'", pos
[1]);
169 strcat(string
, name
);
176 static int exec_callout(struct config_device
*dev
, char *value
, int len
)
186 char *args
[CALLOUT_MAXARG
];
189 dbg("callout to '%s'", dev
->exec_program
);
203 close(STDOUT_FILENO
);
204 dup(fds
[1]); /* dup write side of pipe to STDOUT */
205 if (strchr(dev
->exec_program
, ' ')) {
206 /* callout with arguments */
207 arg
= dev
->exec_program
;
208 for (i
=0; i
< CALLOUT_MAXARG
-1; i
++) {
209 args
[i
] = strsep(&arg
, " ");
214 dbg("too many args - %d", i
);
217 retval
= execve(args
[0], args
, main_envp
);
219 retval
= execve(dev
->exec_program
, main_argv
, main_envp
);
222 dbg("child execve failed");
225 return -1; /* avoid compiler warning */
227 /* parent reads from fds[0] */
231 res
= read(fds
[0], buffer
, sizeof(buffer
) - 1);
236 dbg("callout len %d too short", len
);
240 dbg("callout value already set");
244 strncpy(value
, buffer
, len
);
247 dbg("callout returned '%s'", value
);
251 dbg("wait failed result %d", res
);
256 if (!WIFEXITED(status
) || (WEXITSTATUS(status
) != 0)) {
257 dbg("callout program status 0x%x", status
);
265 static int do_callout(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
267 struct config_device
*dev
;
268 struct list_head
*tmp
;
270 list_for_each(tmp
, &config_device_list
) {
271 dev
= list_entry(tmp
, struct config_device
, node
);
272 if (dev
->type
!= CALLOUT
)
276 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
277 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
281 /* substitute anything that needs to be in the program name */
282 apply_format(udev
, dev
->exec_program
);
283 if (exec_callout(dev
, udev
->callout_value
, NAME_SIZE
))
285 if (strncmp_wildcard(udev
->callout_value
, dev
->id
, NAME_SIZE
) != 0)
287 strfieldcpy(udev
->name
, dev
->name
);
288 if (dev
->mode
!= 0) {
289 udev
->mode
= dev
->mode
;
290 strfieldcpy(udev
->owner
, dev
->owner
);
291 strfieldcpy(udev
->group
, dev
->group
);
293 dbg("callout returned matching value '%s', '%s' becomes '%s'"
294 " - owner='%s', group='%s', mode=%#o",
295 dev
->id
, class_dev
->name
, udev
->name
,
296 dev
->owner
, dev
->group
, dev
->mode
);
302 static int do_label(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
304 struct sysfs_attribute
*tmpattr
= NULL
;
305 struct config_device
*dev
;
306 struct list_head
*tmp
;
308 list_for_each(tmp
, &config_device_list
) {
309 dev
= list_entry(tmp
, struct config_device
, node
);
310 if (dev
->type
!= LABEL
)
314 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
315 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
319 dbg("look for device attribute '%s'", dev
->sysfs_file
);
320 /* try to find the attribute in the class device directory */
321 tmpattr
= sysfs_get_classdev_attr(class_dev
, dev
->sysfs_file
);
325 /* look in the class device directory if present */
327 tmpattr
= sysfs_get_device_attr(sysfs_device
, dev
->sysfs_file
);
335 tmpattr
->value
[strlen(tmpattr
->value
)-1] = 0x00;
336 dbg("compare attribute '%s' value '%s' with '%s'",
337 dev
->sysfs_file
, tmpattr
->value
, dev
->sysfs_value
);
338 if (strcmp(dev
->sysfs_value
, tmpattr
->value
) != 0)
341 strfieldcpy(udev
->name
, dev
->name
);
342 if (dev
->mode
!= 0) {
343 udev
->mode
= dev
->mode
;
344 strfieldcpy(udev
->owner
, dev
->owner
);
345 strfieldcpy(udev
->group
, dev
->group
);
347 dbg("found matching attribute '%s', '%s' becomes '%s' "
348 "- owner='%s', group='%s', mode=%#o",
349 dev
->sysfs_file
, class_dev
->name
, udev
->name
,
350 dev
->owner
, dev
->group
, dev
->mode
);
357 static int do_number(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
359 struct config_device
*dev
;
360 struct list_head
*tmp
;
361 char path
[SYSFS_PATH_MAX
];
365 /* we have to have a sysfs device for NUMBER to work */
369 list_for_each(tmp
, &config_device_list
) {
370 dev
= list_entry(tmp
, struct config_device
, node
);
371 if (dev
->type
!= NUMBER
)
374 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
375 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
379 strfieldcpy(path
, sysfs_device
->path
);
380 temp
= strrchr(path
, '/');
381 dbg("search '%s' in '%s', path='%s'", dev
->id
, temp
, path
);
382 if (strstr(temp
, dev
->id
) != NULL
) {
386 temp
= strrchr(path
, '/');
387 dbg("search '%s' in '%s', path='%s'", dev
->id
, temp
, path
);
388 if (strstr(temp
, dev
->id
) != NULL
)
393 strfieldcpy(udev
->name
, dev
->name
);
394 if (dev
->mode
!= 0) {
395 udev
->mode
= dev
->mode
;
396 strfieldcpy(udev
->owner
, dev
->owner
);
397 strfieldcpy(udev
->group
, dev
->group
);
399 dbg("found matching id '%s', '%s' becomes '%s'"
400 " - owner='%s', group ='%s', mode=%#o",
401 dev
->id
, class_dev
->name
, udev
->name
,
402 dev
->owner
, dev
->group
, dev
->mode
);
408 static int do_topology(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
410 struct config_device
*dev
;
411 struct list_head
*tmp
;
412 char path
[SYSFS_PATH_MAX
];
416 /* we have to have a sysfs device for TOPOLOGY to work */
420 list_for_each(tmp
, &config_device_list
) {
421 dev
= list_entry(tmp
, struct config_device
, node
);
422 if (dev
->type
!= TOPOLOGY
)
425 dbg("dev->bus='%s' sysfs_device->bus='%s'", dev
->bus
, sysfs_device
->bus
);
426 if (strcasecmp(dev
->bus
, sysfs_device
->bus
) != 0)
430 strfieldcpy(path
, sysfs_device
->path
);
431 temp
= strrchr(path
, '/');
432 dbg("search '%s' in '%s', path='%s'", dev
->place
, temp
, path
);
433 if (strstr(temp
, dev
->place
) != NULL
) {
437 temp
= strrchr(path
, '/');
438 dbg("search '%s' in '%s', path='%s'", dev
->place
, temp
, path
);
439 if (strstr(temp
, dev
->place
) != NULL
)
445 strfieldcpy(udev
->name
, dev
->name
);
446 if (dev
->mode
!= 0) {
447 udev
->mode
= dev
->mode
;
448 strfieldcpy(udev
->owner
, dev
->owner
);
449 strfieldcpy(udev
->group
, dev
->group
);
451 dbg("found matching place '%s', '%s' becomes '%s'"
452 " - owner='%s', group ='%s', mode=%#o",
453 dev
->place
, class_dev
->name
, udev
->name
,
454 dev
->owner
, dev
->group
, dev
->mode
);
460 static int do_replace(struct sysfs_class_device
*class_dev
, struct udevice
*udev
, struct sysfs_device
*sysfs_device
)
462 struct config_device
*dev
;
463 struct list_head
*tmp
;
465 list_for_each(tmp
, &config_device_list
) {
466 dev
= list_entry(tmp
, struct config_device
, node
);
467 if (dev
->type
!= REPLACE
)
470 dbg("compare name '%s' with '%s'", dev
->kernel_name
, class_dev
->name
);
471 if (strncmp_wildcard(class_dev
->name
, dev
->kernel_name
, NAME_SIZE
) != 0)
474 strfieldcpy(udev
->name
, dev
->name
);
475 if (dev
->mode
!= 0) {
476 udev
->mode
= dev
->mode
;
477 strfieldcpy(udev
->owner
, dev
->owner
);
478 strfieldcpy(udev
->group
, dev
->group
);
480 dbg("found name, '%s' becomes '%s'"
481 " - owner='%s', group='%s', mode = %#o",
482 dev
->kernel_name
, udev
->name
,
483 dev
->owner
, dev
->group
, dev
->mode
);
490 static void do_kernelname(struct sysfs_class_device
*class_dev
, struct udevice
*udev
)
492 struct config_device
*dev
;
493 struct list_head
*tmp
;
496 strfieldcpy(udev
->name
, class_dev
->name
);
497 /* look for permissions */
498 list_for_each(tmp
, &config_device_list
) {
499 dev
= list_entry(tmp
, struct config_device
, node
);
500 len
= strlen(dev
->name
);
501 if (strncmp_wildcard(class_dev
->name
, dev
->name
, sizeof(dev
->name
)))
503 if (dev
->mode
!= 0) {
504 dbg("found permissions for '%s'", class_dev
->name
);
505 udev
->mode
= dev
->mode
;
506 strfieldcpy(udev
->owner
, dev
->owner
);
507 strfieldcpy(udev
->group
, dev
->group
);
512 int namedev_name_device(struct sysfs_class_device
*class_dev
, struct udevice
*udev
)
514 struct sysfs_device
*sysfs_device
= NULL
;
515 struct sysfs_class_device
*class_dev_parent
= NULL
;
521 /* find the sysfs_device for this class device */
522 /* Wouldn't it really be nice if libsysfs could do this for us? */
523 if (class_dev
->sysdevice
) {
524 sysfs_device
= class_dev
->sysdevice
;
526 /* bah, let's go backwards up a level to see if the device is there,
527 * as block partitions don't point to the physical device. Need to fix that
528 * up in the kernel...
530 if (strstr(class_dev
->path
, "block")) {
531 dbg("looking at block device");
532 if (isdigit(class_dev
->path
[strlen(class_dev
->path
)-1])) {
533 char path
[SYSFS_PATH_MAX
];
535 dbg("really is a partition");
536 strfieldcpy(path
, class_dev
->path
);
537 temp
= strrchr(path
, '/');
539 dbg("looking for a class device at '%s'", path
);
540 class_dev_parent
= sysfs_open_class_device(path
);
541 if (class_dev_parent
== NULL
) {
542 dbg("sysfs_open_class_device at '%s' failed", path
);
544 dbg("class_dev_parent->name='%s'", class_dev_parent
->name
);
545 if (class_dev_parent
->sysdevice
)
546 sysfs_device
= class_dev_parent
->sysdevice
;
553 dbg("sysfs_device->path='%s'", sysfs_device
->path
);
554 dbg("sysfs_device->bus_id='%s'", sysfs_device
->bus_id
);
555 dbg("sysfs_device->bus='%s'", sysfs_device
->bus
);
556 strfieldcpy(udev
->bus_id
, sysfs_device
->bus_id
);
558 dbg("class_dev->name = '%s'", class_dev
->name
);
561 build_kernel_number(class_dev
, udev
);
563 /* rules are looked at in priority order */
564 retval
= do_callout(class_dev
, udev
, sysfs_device
);
568 retval
= do_label(class_dev
, udev
, sysfs_device
);
572 retval
= do_number(class_dev
, udev
, sysfs_device
);
576 retval
= do_topology(class_dev
, udev
, sysfs_device
);
580 retval
= do_replace(class_dev
, udev
, sysfs_device
);
584 do_kernelname(class_dev
, udev
);
588 /* substitute placeholder in NAME */
589 apply_format(udev
, udev
->name
);
592 /* mode was never set above */
594 udev
->mode
= get_default_mode(class_dev
);
595 udev
->owner
[0] = 0x00;
596 udev
->group
[0] = 0x00;
599 if (class_dev_parent
)
600 sysfs_close_class_device(class_dev_parent
);
605 int namedev_init(void)
609 retval
= namedev_init_config();
613 retval
= namedev_init_permissions();
617 dump_config_dev_list();