2003-07-17 15:24:51 +07:00
|
|
|
/*
|
|
|
|
* namedev.c
|
|
|
|
*
|
|
|
|
* Userspace devfs
|
|
|
|
*
|
|
|
|
* Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation version 2 of the License.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
2003-10-15 13:32:17 +07:00
|
|
|
#include <sys/wait.h>
|
2003-12-20 16:05:13 +07:00
|
|
|
#include <sys/stat.h>
|
2003-07-17 15:24:51 +07:00
|
|
|
|
|
|
|
#include "list.h"
|
|
|
|
#include "udev.h"
|
|
|
|
#include "udev_version.h"
|
|
|
|
#include "namedev.h"
|
2003-07-19 12:48:28 +07:00
|
|
|
#include "libsysfs/libsysfs.h"
|
2003-11-24 11:44:41 +07:00
|
|
|
#include "klibc_fixups.h"
|
2003-07-17 15:24:51 +07:00
|
|
|
|
2003-12-03 09:38:30 +07:00
|
|
|
LIST_HEAD(config_device_list);
|
2003-12-04 09:33:58 +07:00
|
|
|
LIST_HEAD(perm_device_list);
|
2003-07-17 15:24:51 +07:00
|
|
|
|
2003-12-03 21:22:53 +07:00
|
|
|
/* compare string with pattern (supports * ? [0-9] [!A-Z]) */
|
|
|
|
static int strcmp_pattern(const char *p, const char *s)
|
2003-11-24 12:14:33 +07:00
|
|
|
{
|
2003-12-03 21:22:53 +07:00
|
|
|
if (*s == '\0') {
|
|
|
|
while (*p == '*')
|
|
|
|
p++;
|
|
|
|
return (*p != '\0');
|
|
|
|
}
|
|
|
|
switch (*p) {
|
|
|
|
case '[':
|
|
|
|
{
|
|
|
|
int not = 0;
|
|
|
|
p++;
|
|
|
|
if (*p == '!') {
|
|
|
|
not = 1;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
while (*p && (*p != ']')) {
|
|
|
|
int match = 0;
|
|
|
|
if (p[1] == '-') {
|
|
|
|
if ((*s >= *p) && (*s <= p[2]))
|
|
|
|
match = 1;
|
|
|
|
p += 3;
|
|
|
|
} else {
|
|
|
|
match = (*p == *s);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
if (match ^ not) {
|
|
|
|
while (*p && (*p != ']'))
|
|
|
|
p++;
|
|
|
|
return strcmp_pattern(p+1, s+1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case '*':
|
|
|
|
if (strcmp_pattern(p, s+1))
|
|
|
|
return strcmp_pattern(p+1, s);
|
|
|
|
return 0;
|
|
|
|
case '\0':
|
|
|
|
if (*s == '\0') {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if ((*p == *s) || (*p == '?'))
|
|
|
|
return strcmp_pattern(p+1, s+1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 1;
|
2003-11-24 12:14:33 +07:00
|
|
|
}
|
|
|
|
|
2003-07-17 15:24:51 +07:00
|
|
|
#define copy_var(a, b, var) \
|
|
|
|
if (b->var) \
|
2003-07-18 21:46:17 +07:00
|
|
|
a->var = b->var;
|
2003-07-17 15:24:51 +07:00
|
|
|
|
|
|
|
#define copy_string(a, b, var) \
|
|
|
|
if (strlen(b->var)) \
|
2003-07-18 21:46:17 +07:00
|
|
|
strcpy(a->var, b->var);
|
2003-07-17 15:24:51 +07:00
|
|
|
|
2003-12-04 09:33:58 +07:00
|
|
|
int add_perm_dev(struct perm_device *new_dev)
|
|
|
|
{
|
|
|
|
struct list_head *tmp;
|
|
|
|
struct perm_device *tmp_dev;
|
|
|
|
|
|
|
|
/* update the values if we already have the device */
|
|
|
|
list_for_each(tmp, &perm_device_list) {
|
|
|
|
struct perm_device *dev = list_entry(tmp, struct perm_device, node);
|
|
|
|
if (strcmp_pattern(new_dev->name, dev->name))
|
|
|
|
continue;
|
|
|
|
copy_var(dev, new_dev, mode);
|
|
|
|
copy_string(dev, new_dev, owner);
|
|
|
|
copy_string(dev, new_dev, group);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* not found, add new structure to the perm list */
|
|
|
|
tmp_dev = malloc(sizeof(*tmp_dev));
|
|
|
|
if (!tmp_dev)
|
|
|
|
return -ENOMEM;
|
|
|
|
memcpy(tmp_dev, new_dev, sizeof(*tmp_dev));
|
|
|
|
list_add_tail(&tmp_dev->node, &perm_device_list);
|
|
|
|
//dump_perm_dev(tmp_dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct perm_device *find_perm(char *name)
|
|
|
|
{
|
|
|
|
struct list_head *tmp;
|
|
|
|
struct perm_device *perm = NULL;
|
|
|
|
|
|
|
|
list_for_each(tmp, &perm_device_list) {
|
|
|
|
perm = list_entry(tmp, struct perm_device, node);
|
|
|
|
if (strcmp_pattern(perm->name, name))
|
|
|
|
continue;
|
|
|
|
return perm;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2003-10-20 11:56:21 +07:00
|
|
|
static mode_t get_default_mode(struct sysfs_class_device *class_dev)
|
2003-07-19 12:48:28 +07:00
|
|
|
{
|
2003-12-04 08:41:02 +07:00
|
|
|
mode_t mode = 0600; /* default to owner rw only */
|
|
|
|
|
|
|
|
if (strlen(default_mode_str) != 0) {
|
|
|
|
mode = strtol(default_mode_str, NULL, 8);
|
|
|
|
}
|
|
|
|
return mode;
|
2003-07-19 12:48:28 +07:00
|
|
|
}
|
|
|
|
|
2003-11-24 13:25:13 +07:00
|
|
|
static void apply_format(struct udevice *udev, unsigned char *string)
|
|
|
|
{
|
|
|
|
char name[NAME_SIZE];
|
[PATCH] get part of callout return string
Try this patch if you like, to get special parts of the callout output.
This beast works now:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
The callout returned string is separated by spaces and is
addressed by the "len" value of the 'c' format char.
Since we support symlinks, this my be useful for other uses of callout too.
introduce 'len number' for format chars
the first use is 'c'-the callout return to select a part of the output string like:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
(note: first part is requested by len=1, len=0 will return the whole string)
add a test to udev-test.pl
2003-12-16 13:54:38 +07:00
|
|
|
char temp[NAME_SIZE];
|
|
|
|
char *tail;
|
2003-11-24 13:25:13 +07:00
|
|
|
char *pos;
|
[PATCH] get part of callout return string
Try this patch if you like, to get special parts of the callout output.
This beast works now:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
The callout returned string is separated by spaces and is
addressed by the "len" value of the 'c' format char.
Since we support symlinks, this my be useful for other uses of callout too.
introduce 'len number' for format chars
the first use is 'c'-the callout return to select a part of the output string like:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
(note: first part is requested by len=1, len=0 will return the whole string)
add a test to udev-test.pl
2003-12-16 13:54:38 +07:00
|
|
|
char *pos2;
|
|
|
|
char *pos3;
|
|
|
|
int num;
|
2003-11-24 13:25:13 +07:00
|
|
|
|
|
|
|
while (1) {
|
[PATCH] get part of callout return string
Try this patch if you like, to get special parts of the callout output.
This beast works now:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
The callout returned string is separated by spaces and is
addressed by the "len" value of the 'c' format char.
Since we support symlinks, this my be useful for other uses of callout too.
introduce 'len number' for format chars
the first use is 'c'-the callout return to select a part of the output string like:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
(note: first part is requested by len=1, len=0 will return the whole string)
add a test to udev-test.pl
2003-12-16 13:54:38 +07:00
|
|
|
num = 0;
|
2003-11-24 13:25:13 +07:00
|
|
|
pos = strchr(string, '%');
|
|
|
|
|
|
|
|
if (pos) {
|
[PATCH] get part of callout return string
Try this patch if you like, to get special parts of the callout output.
This beast works now:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
The callout returned string is separated by spaces and is
addressed by the "len" value of the 'c' format char.
Since we support symlinks, this my be useful for other uses of callout too.
introduce 'len number' for format chars
the first use is 'c'-the callout return to select a part of the output string like:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
(note: first part is requested by len=1, len=0 will return the whole string)
add a test to udev-test.pl
2003-12-16 13:54:38 +07:00
|
|
|
*pos = '\0';
|
|
|
|
tail = pos+1;
|
|
|
|
if (isdigit(tail[0])) {
|
|
|
|
num = (int) strtoul(&pos[1], &tail, 10);
|
|
|
|
if (tail == NULL) {
|
|
|
|
dbg("format parsing error '%s'", pos+1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strfieldcpy(name, tail+1);
|
|
|
|
|
|
|
|
switch (tail[0]) {
|
2003-11-24 13:25:13 +07:00
|
|
|
case 'b':
|
|
|
|
if (strlen(udev->bus_id) == 0)
|
|
|
|
break;
|
2003-11-25 13:27:20 +07:00
|
|
|
strcat(pos, udev->bus_id);
|
2003-11-24 13:25:13 +07:00
|
|
|
dbg("substitute bus_id '%s'", udev->bus_id);
|
|
|
|
break;
|
2003-12-23 10:13:19 +07:00
|
|
|
case 'k':
|
|
|
|
if (strlen(udev->kernel_name) == 0)
|
|
|
|
break;
|
|
|
|
strcat(pos, udev->kernel_name);
|
|
|
|
dbg("substitute kernel name '%s'", udev->kernel_name);
|
|
|
|
break;
|
2003-11-24 13:25:13 +07:00
|
|
|
case 'n':
|
|
|
|
if (strlen(udev->kernel_number) == 0)
|
|
|
|
break;
|
|
|
|
strcat(pos, udev->kernel_number);
|
|
|
|
dbg("substitute kernel number '%s'", udev->kernel_number);
|
|
|
|
break;
|
2003-11-25 14:41:40 +07:00
|
|
|
case 'D':
|
|
|
|
if (strlen(udev->kernel_number) == 0) {
|
2003-12-11 13:12:30 +07:00
|
|
|
strcat(pos, "disc");
|
2003-11-25 14:41:40 +07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
strcat(pos, "part");
|
|
|
|
strcat(pos, udev->kernel_number);
|
|
|
|
dbg("substitute kernel number '%s'", udev->kernel_number);
|
|
|
|
break;
|
2003-11-24 13:25:13 +07:00
|
|
|
case 'm':
|
|
|
|
sprintf(pos, "%u", udev->minor);
|
|
|
|
dbg("substitute minor number '%u'", udev->minor);
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
sprintf(pos, "%u", udev->major);
|
|
|
|
dbg("substitute major number '%u'", udev->major);
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (strlen(udev->callout_value) == 0)
|
|
|
|
break;
|
[PATCH] get part of callout return string
Try this patch if you like, to get special parts of the callout output.
This beast works now:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
The callout returned string is separated by spaces and is
addressed by the "len" value of the 'c' format char.
Since we support symlinks, this my be useful for other uses of callout too.
introduce 'len number' for format chars
the first use is 'c'-the callout return to select a part of the output string like:
CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n node link1 link2", ID="node *", NAME="%1c", SYMLINK="%2c %3c"
(note: first part is requested by len=1, len=0 will return the whole string)
add a test to udev-test.pl
2003-12-16 13:54:38 +07:00
|
|
|
if (num) {
|
|
|
|
/* get part of return string */
|
|
|
|
strncpy(temp, udev->callout_value, sizeof(temp));
|
|
|
|
pos2 = temp;
|
|
|
|
while (num) {
|
|
|
|
num--;
|
|
|
|
pos3 = strsep(&pos2, " ");
|
|
|
|
if (pos3 == NULL) {
|
|
|
|
dbg("requested part of callout string not found");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcat(pos, pos3);
|
|
|
|
dbg("substitute partial callout output '%s'", pos3);
|
|
|
|
} else {
|
|
|
|
strcat(pos, udev->callout_value);
|
|
|
|
dbg("substitute callout output '%s'", udev->callout_value);
|
|
|
|
}
|
2003-11-24 13:25:13 +07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
dbg("unknown substitution type '%%%c'", pos[1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
strcat(string, name);
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-20 16:05:13 +07:00
|
|
|
static struct bus_file {
|
|
|
|
char *bus;
|
|
|
|
char *file;
|
|
|
|
} bus_files[] = {
|
|
|
|
{ .bus = "scsi", .file = "vendor" },
|
|
|
|
{ .bus = "usb", .file = "idVendor" },
|
2003-12-25 13:51:16 +07:00
|
|
|
{ .bus = "pci", .file = "vendor" },
|
2003-12-20 16:05:13 +07:00
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
#define SECONDS_TO_WAIT_FOR_FILE 10
|
|
|
|
static void wait_for_device_to_initialize(struct sysfs_device *sysfs_device)
|
|
|
|
{
|
|
|
|
/* sleep until we see the file for this specific bus type show up this
|
|
|
|
* is needed because we can easily out-run the kernel in looking for
|
|
|
|
* these files before the paticular subsystem has created them in the
|
|
|
|
* sysfs tree properly.
|
|
|
|
*
|
|
|
|
* And people thought that the /sbin/hotplug event system was going to
|
|
|
|
* be slow, poo on you for arguing that before even testing it...
|
|
|
|
*/
|
|
|
|
struct bus_file *b = &bus_files[0];
|
|
|
|
struct sysfs_attribute *tmpattr;
|
|
|
|
int loop;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
if (b->bus == NULL)
|
|
|
|
break;
|
|
|
|
if (strcmp(sysfs_device->bus, b->bus) == 0) {
|
|
|
|
tmpattr = NULL;
|
|
|
|
loop = SECONDS_TO_WAIT_FOR_FILE;
|
|
|
|
while (loop--) {
|
|
|
|
dbg("looking for file '%s' on bus '%s'", b->file, b->bus);
|
|
|
|
tmpattr = sysfs_get_device_attr(sysfs_device, b->file);
|
|
|
|
if (tmpattr) {
|
|
|
|
/* found it! */
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
/* sleep to give the kernel a chance to create the file */
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
dbg("Timed out waiting for '%s' file, continuing on anyway...", b->file);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
b++;
|
|
|
|
}
|
|
|
|
dbg("Did not find bus type '%s' on list of bus_id_files, contact greg@kroah.com", sysfs_device->bus);
|
|
|
|
exit:
|
|
|
|
return; /* here to prevent compiler warning... */
|
|
|
|
}
|
2003-07-19 19:06:55 +07:00
|
|
|
|
2003-10-15 13:32:17 +07:00
|
|
|
static int exec_callout(struct config_device *dev, char *value, int len)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
int res;
|
|
|
|
int status;
|
|
|
|
int fds[2];
|
|
|
|
pid_t pid;
|
|
|
|
int value_set = 0;
|
|
|
|
char buffer[256];
|
2003-12-16 13:38:18 +07:00
|
|
|
char *pos;
|
2003-11-21 21:48:01 +07:00
|
|
|
char *args[CALLOUT_MAXARG];
|
|
|
|
int i;
|
2003-10-15 13:32:17 +07:00
|
|
|
|
[PATCH] namedev.c whitespace + debug text cleanup
here is mainly a whitespace cleanup for namedev.c. I changed the
dbg_parse() output a bit for better readability:
current:
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='00:07.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1' id='00:07.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='00:0b.0'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1' id='00:0b.0'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: device id '2-1.1' becomes 'webcam%n' - owner='', group ='', mode=0
becomes:
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:07.1' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:07.1' in '/2-1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:0b.0' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:0b.0' in '/2-1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '2-1.1' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: found id '2-1.1', 'video0' becomes 'webcam%n' - owner='', group ='', mode=0
2003-11-21 09:37:01 +07:00
|
|
|
dbg("callout to '%s'", dev->exec_program);
|
2003-10-15 13:32:17 +07:00
|
|
|
retval = pipe(fds);
|
|
|
|
if (retval != 0) {
|
|
|
|
dbg("pipe failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
pid = fork();
|
|
|
|
if (pid == -1) {
|
|
|
|
dbg("fork failed");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid == 0) {
|
[PATCH] namedev.c whitespace + debug text cleanup
here is mainly a whitespace cleanup for namedev.c. I changed the
dbg_parse() output a bit for better readability:
current:
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='00:07.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1' id='00:07.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='00:0b.0'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1' id='00:0b.0'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: device id '2-1.1' becomes 'webcam%n' - owner='', group ='', mode=0
becomes:
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:07.1' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:07.1' in '/2-1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:0b.0' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:0b.0' in '/2-1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '2-1.1' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: found id '2-1.1', 'video0' becomes 'webcam%n' - owner='', group ='', mode=0
2003-11-21 09:37:01 +07:00
|
|
|
/* child */
|
2003-10-15 13:32:17 +07:00
|
|
|
close(STDOUT_FILENO);
|
|
|
|
dup(fds[1]); /* dup write side of pipe to STDOUT */
|
2003-11-21 21:48:01 +07:00
|
|
|
if (strchr(dev->exec_program, ' ')) {
|
|
|
|
/* callout with arguments */
|
2003-12-16 13:38:18 +07:00
|
|
|
pos = dev->exec_program;
|
2003-11-21 21:48:01 +07:00
|
|
|
for (i=0; i < CALLOUT_MAXARG-1; i++) {
|
2003-12-16 13:38:18 +07:00
|
|
|
args[i] = strsep(&pos, " ");
|
2003-11-21 21:48:01 +07:00
|
|
|
if (args[i] == NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (args[i]) {
|
2003-11-24 12:14:10 +07:00
|
|
|
dbg("too many args - %d", i);
|
2003-11-21 21:48:01 +07:00
|
|
|
args[i] = NULL;
|
|
|
|
}
|
|
|
|
retval = execve(args[0], args, main_envp);
|
|
|
|
} else {
|
|
|
|
retval = execve(dev->exec_program, main_argv, main_envp);
|
|
|
|
}
|
2003-10-15 13:32:17 +07:00
|
|
|
if (retval != 0) {
|
|
|
|
dbg("child execve failed");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return -1; /* avoid compiler warning */
|
|
|
|
} else {
|
[PATCH] namedev.c whitespace + debug text cleanup
here is mainly a whitespace cleanup for namedev.c. I changed the
dbg_parse() output a bit for better readability:
current:
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='00:07.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1' id='00:07.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='00:0b.0'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1' id='00:0b.0'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: NUMBER temp='/2-1.1' id='2-1.1'
Nov 19 19:00:59 pim udev[25582]: do_number: device id '2-1.1' becomes 'webcam%n' - owner='', group ='', mode=0
becomes:
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:07.1' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:07.1' in '/2-1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:0b.0' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '00:0b.0' in '/2-1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1'
Nov 19 19:23:40 pim udev[26091]: do_number: search '2-1.1' in '/2-1.1', path='/sys/devices/pci0000:00/0000:00:1d.1/usb2/2-1/2-1.1'
Nov 19 19:23:40 pim udev[26091]: do_number: found id '2-1.1', 'video0' becomes 'webcam%n' - owner='', group ='', mode=0
2003-11-21 09:37:01 +07:00
|
|
|
/* parent reads from fds[0] */
|
2003-10-15 13:32:17 +07:00
|
|
|
close(fds[1]);
|
|
|
|
retval = 0;
|
|
|
|
while (1) {
|
|
|
|
res = read(fds[0], buffer, sizeof(buffer) - 1);
|
|
|
|
if (res <= 0)
|
|
|
|
break;
|
|
|
|
buffer[res] = '\0';
|
|
|
|
if (res > len) {
|
2003-11-25 13:27:17 +07:00
|
|
|
dbg("callout len %d too short", len);
|
2003-10-15 13:32:17 +07:00
|
|
|
retval = -1;
|
|
|
|
}
|
|
|
|
if (value_set) {
|
|
|
|
dbg("callout value already set");
|
|
|
|
retval = -1;
|
|
|
|
} else {
|
|
|
|
value_set = 1;
|
|
|
|
strncpy(value, buffer, len);
|
2003-12-16 13:38:18 +07:00
|
|
|
pos = value + strlen(value)-1;
|
|
|
|
if (pos[0] == '\n')
|
|
|
|
pos[0] = '\0';
|
|
|
|
dbg("callout returned '%s'", value);
|
2003-10-15 13:32:17 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
close(fds[0]);
|
|
|
|
res = wait(&status);
|
|
|
|
if (res < 0) {
|
|
|
|
dbg("wait failed result %d", res);
|
|
|
|
retval = -1;
|
|
|
|
}
|
|
|
|
|
2003-10-23 13:48:55 +07:00
|
|
|
#ifndef __KLIBC__
|
2003-10-15 13:32:17 +07:00
|
|
|
if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) {
|
|
|
|
dbg("callout program status 0x%x", status);
|
|
|
|
retval = -1;
|
|
|
|
}
|
2003-10-23 13:48:55 +07:00
|
|
|
#endif
|
2003-10-15 13:32:17 +07:00
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2003-11-27 08:45:05 +07:00
|
|
|
static int do_callout(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
|
2003-11-12 23:26:08 +07:00
|
|
|
{
|
|
|
|
struct config_device *dev;
|
|
|
|
struct list_head *tmp;
|
|
|
|
|
|
|
|
list_for_each(tmp, &config_device_list) {
|
|
|
|
dev = list_entry(tmp, struct config_device, node);
|
|
|
|
if (dev->type != CALLOUT)
|
|
|
|
continue;
|
2003-11-24 13:25:13 +07:00
|
|
|
|
2003-12-25 15:05:28 +07:00
|
|
|
if (dev->bus[0] != '\0') {
|
|
|
|
/* as the user specified a bus, we must match it up */
|
|
|
|
if (!sysfs_device)
|
|
|
|
continue;
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
|
2003-11-27 08:45:05 +07:00
|
|
|
if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2003-11-24 13:25:13 +07:00
|
|
|
/* substitute anything that needs to be in the program name */
|
|
|
|
apply_format(udev, dev->exec_program);
|
|
|
|
if (exec_callout(dev, udev->callout_value, NAME_SIZE))
|
2003-11-12 23:26:08 +07:00
|
|
|
continue;
|
2003-12-03 21:22:53 +07:00
|
|
|
if (strcmp_pattern(dev->id, udev->callout_value) != 0)
|
2003-11-12 23:26:08 +07:00
|
|
|
continue;
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(udev->name, dev->name);
|
2003-12-08 00:12:07 +07:00
|
|
|
strfieldcpy(udev->symlink, dev->symlink);
|
2003-12-04 09:33:58 +07:00
|
|
|
dbg("callout returned matching value '%s', '%s' becomes '%s'",
|
|
|
|
dev->id, class_dev->name, udev->name);
|
2003-11-12 23:26:08 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2003-12-23 13:31:35 +07:00
|
|
|
static int match_pair(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, struct sysfs_pair *pair)
|
2003-11-13 20:52:08 +07:00
|
|
|
{
|
|
|
|
struct sysfs_attribute *tmpattr = NULL;
|
2003-12-23 13:31:35 +07:00
|
|
|
char *c;
|
|
|
|
|
|
|
|
if ((pair == NULL) || (pair->file[0] == '\0') || (pair->value == '\0'))
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
dbg("look for device attribute '%s'", pair->file);
|
|
|
|
/* try to find the attribute in the class device directory */
|
|
|
|
tmpattr = sysfs_get_classdev_attr(class_dev, pair->file);
|
|
|
|
if (tmpattr)
|
|
|
|
goto label_found;
|
|
|
|
|
|
|
|
/* look in the class device directory if present */
|
|
|
|
if (sysfs_device) {
|
|
|
|
tmpattr = sysfs_get_device_attr(sysfs_device, pair->file);
|
|
|
|
if (tmpattr)
|
|
|
|
goto label_found;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
label_found:
|
|
|
|
c = tmpattr->value + strlen(tmpattr->value)-1;
|
|
|
|
if (*c == '\n')
|
|
|
|
*c = 0x00;
|
|
|
|
dbg("compare attribute '%s' value '%s' with '%s'",
|
|
|
|
pair->file, tmpattr->value, pair->value);
|
|
|
|
if (strcmp_pattern(pair->value, tmpattr->value) != 0)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
dbg("found matching attribute '%s' with value '%s'",
|
|
|
|
pair->file, pair->value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_label(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
|
|
|
|
{
|
|
|
|
struct sysfs_pair *pair;
|
2003-11-13 20:52:08 +07:00
|
|
|
struct config_device *dev;
|
|
|
|
struct list_head *tmp;
|
2003-12-23 13:31:35 +07:00
|
|
|
int i;
|
|
|
|
int match;
|
2003-11-13 20:52:08 +07:00
|
|
|
|
|
|
|
list_for_each(tmp, &config_device_list) {
|
|
|
|
dev = list_entry(tmp, struct config_device, node);
|
|
|
|
if (dev->type != LABEL)
|
|
|
|
continue;
|
|
|
|
|
2003-12-25 15:33:00 +07:00
|
|
|
if (dev->bus[0] != '\0') {
|
|
|
|
/* as the user specified a bus, we must match it up */
|
|
|
|
if (!sysfs_device)
|
|
|
|
continue;
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
|
2003-11-27 08:45:05 +07:00
|
|
|
if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2003-12-23 13:31:35 +07:00
|
|
|
match = 1;
|
|
|
|
for (i = 0; i < MAX_SYSFS_PAIRS; ++i) {
|
|
|
|
pair = &dev->sysfs_pair[i];
|
|
|
|
if ((pair->file[0] == '\0') || (pair->value[0] == '\0'))
|
|
|
|
break;
|
|
|
|
if (match_pair(class_dev, sysfs_device, pair) != 0) {
|
|
|
|
match = 0;
|
|
|
|
break;
|
|
|
|
}
|
2003-11-13 20:52:08 +07:00
|
|
|
}
|
2003-12-23 13:31:35 +07:00
|
|
|
if (match == 0)
|
2003-11-13 20:52:08 +07:00
|
|
|
continue;
|
|
|
|
|
2003-12-23 13:31:35 +07:00
|
|
|
/* found match */
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(udev->name, dev->name);
|
2003-12-08 00:12:07 +07:00
|
|
|
strfieldcpy(udev->symlink, dev->symlink);
|
2003-12-23 13:31:35 +07:00
|
|
|
dbg("found matching attribute, '%s' becomes '%s' ",
|
|
|
|
class_dev->name, udev->name);
|
2003-11-13 20:52:08 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int do_number(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
|
|
|
|
{
|
|
|
|
struct config_device *dev;
|
|
|
|
struct list_head *tmp;
|
|
|
|
char path[SYSFS_PATH_MAX];
|
|
|
|
int found;
|
|
|
|
char *temp = NULL;
|
|
|
|
|
|
|
|
/* we have to have a sysfs device for NUMBER to work */
|
|
|
|
if (!sysfs_device)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
list_for_each(tmp, &config_device_list) {
|
|
|
|
dev = list_entry(tmp, struct config_device, node);
|
|
|
|
if (dev->type != NUMBER)
|
|
|
|
continue;
|
|
|
|
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
|
2003-11-27 08:45:05 +07:00
|
|
|
if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
|
|
|
|
continue;
|
|
|
|
|
2003-11-13 20:52:08 +07:00
|
|
|
found = 0;
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(path, sysfs_device->path);
|
2003-11-13 20:52:08 +07:00
|
|
|
temp = strrchr(path, '/');
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("search '%s' in '%s', path='%s'", dev->id, temp, path);
|
2003-11-13 20:52:08 +07:00
|
|
|
if (strstr(temp, dev->id) != NULL) {
|
|
|
|
found = 1;
|
|
|
|
} else {
|
|
|
|
*temp = 0x00;
|
|
|
|
temp = strrchr(path, '/');
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("search '%s' in '%s', path='%s'", dev->id, temp, path);
|
2003-11-13 20:52:08 +07:00
|
|
|
if (strstr(temp, dev->id) != NULL)
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
continue;
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(udev->name, dev->name);
|
2003-12-08 00:12:07 +07:00
|
|
|
strfieldcpy(udev->symlink, dev->symlink);
|
2003-12-04 09:33:58 +07:00
|
|
|
dbg("found matching id '%s', '%s' becomes '%s'",
|
|
|
|
dev->id, class_dev->name, udev->name);
|
2003-11-13 20:52:08 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2003-11-13 09:08:19 +07:00
|
|
|
static int do_topology(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
|
|
|
|
{
|
|
|
|
struct config_device *dev;
|
|
|
|
struct list_head *tmp;
|
|
|
|
char path[SYSFS_PATH_MAX];
|
|
|
|
int found;
|
|
|
|
char *temp = NULL;
|
|
|
|
|
|
|
|
/* we have to have a sysfs device for TOPOLOGY to work */
|
|
|
|
if (!sysfs_device)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
list_for_each(tmp, &config_device_list) {
|
|
|
|
dev = list_entry(tmp, struct config_device, node);
|
|
|
|
if (dev->type != TOPOLOGY)
|
|
|
|
continue;
|
|
|
|
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("dev->bus='%s' sysfs_device->bus='%s'", dev->bus, sysfs_device->bus);
|
2003-11-27 08:45:05 +07:00
|
|
|
if (strcasecmp(dev->bus, sysfs_device->bus) != 0)
|
|
|
|
continue;
|
|
|
|
|
2003-11-13 21:24:09 +07:00
|
|
|
found = 0;
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(path, sysfs_device->path);
|
2003-11-13 09:08:19 +07:00
|
|
|
temp = strrchr(path, '/');
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("search '%s' in '%s', path='%s'", dev->place, temp, path);
|
2003-11-13 09:08:19 +07:00
|
|
|
if (strstr(temp, dev->place) != NULL) {
|
|
|
|
found = 1;
|
|
|
|
} else {
|
|
|
|
*temp = 0x00;
|
|
|
|
temp = strrchr(path, '/');
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("search '%s' in '%s', path='%s'", dev->place, temp, path);
|
2003-11-13 09:08:19 +07:00
|
|
|
if (strstr(temp, dev->place) != NULL)
|
|
|
|
found = 1;
|
|
|
|
}
|
|
|
|
if (!found)
|
|
|
|
continue;
|
|
|
|
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(udev->name, dev->name);
|
2003-12-08 00:12:07 +07:00
|
|
|
strfieldcpy(udev->symlink, dev->symlink);
|
2003-12-04 09:33:58 +07:00
|
|
|
dbg("found matching place '%s', '%s' becomes '%s'",
|
|
|
|
dev->place, class_dev->name, udev->name);
|
2003-11-13 09:08:19 +07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2003-11-27 08:45:05 +07:00
|
|
|
static int do_replace(struct sysfs_class_device *class_dev, struct udevice *udev, struct sysfs_device *sysfs_device)
|
2003-11-12 23:26:08 +07:00
|
|
|
{
|
|
|
|
struct config_device *dev;
|
|
|
|
struct list_head *tmp;
|
|
|
|
|
|
|
|
list_for_each(tmp, &config_device_list) {
|
|
|
|
dev = list_entry(tmp, struct config_device, node);
|
|
|
|
if (dev->type != REPLACE)
|
|
|
|
continue;
|
|
|
|
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("compare name '%s' with '%s'", dev->kernel_name, class_dev->name);
|
2003-12-03 21:22:53 +07:00
|
|
|
if (strcmp_pattern(dev->kernel_name, class_dev->name) != 0)
|
2003-11-12 23:26:08 +07:00
|
|
|
continue;
|
|
|
|
|
2003-11-19 12:39:30 +07:00
|
|
|
strfieldcpy(udev->name, dev->name);
|
2003-12-08 00:12:07 +07:00
|
|
|
strfieldcpy(udev->symlink, dev->symlink);
|
2003-12-04 09:33:58 +07:00
|
|
|
dbg("found name, '%s' becomes '%s'", dev->kernel_name, udev->name);
|
2003-11-12 23:26:08 +07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2003-11-19 21:19:06 +07:00
|
|
|
static void do_kernelname(struct sysfs_class_device *class_dev, struct udevice *udev)
|
|
|
|
{
|
2003-12-04 09:33:58 +07:00
|
|
|
/* heh, this is pretty simple... */
|
2003-11-19 21:19:06 +07:00
|
|
|
strfieldcpy(udev->name, class_dev->name);
|
|
|
|
}
|
|
|
|
|
2003-12-20 16:05:13 +07:00
|
|
|
static struct sysfs_device *get_sysfs_device(struct sysfs_class_device *class_dev)
|
2003-07-19 12:48:28 +07:00
|
|
|
{
|
2003-12-20 16:05:13 +07:00
|
|
|
struct sysfs_device *sysfs_device;
|
|
|
|
struct sysfs_class_device *class_dev_parent;
|
|
|
|
int loop;
|
2003-12-25 10:44:19 +07:00
|
|
|
char filename[SYSFS_PATH_MAX + 6];
|
|
|
|
int retval;
|
|
|
|
char *temp;
|
|
|
|
int partition = 0;
|
|
|
|
|
|
|
|
/* Figure out where the device symlink is at. For char devices this will
|
|
|
|
* always be in the class_dev->path. But for block devices, it's different.
|
|
|
|
* The main block device will have the device symlink in it's path, but
|
|
|
|
* all partitions have the symlink in its parent directory.
|
|
|
|
* But we need to watch out for block devices that do not have parents, yet
|
|
|
|
* look like a partition (fd0, loop0, etc.) They all do not have a device
|
|
|
|
* symlink yet. We do sit and spin on waiting for them right now, we should
|
|
|
|
* possibly have a whitelist for these devices here...
|
2003-12-20 16:05:13 +07:00
|
|
|
*/
|
2003-12-25 10:44:19 +07:00
|
|
|
strcpy(filename, class_dev->path);
|
|
|
|
dbg("filename = %s", filename);
|
|
|
|
if (strcmp(class_dev->classname, SYSFS_BLOCK_NAME) == 0) {
|
|
|
|
if (isdigit(class_dev->path[strlen(class_dev->path)-1])) {
|
|
|
|
temp = strrchr(filename, '/');
|
|
|
|
if (temp) {
|
|
|
|
partition = 1;
|
|
|
|
*temp = 0x00;
|
|
|
|
char *temp2 = strrchr(filename, '/');
|
|
|
|
dbg("temp2 = %s", temp2);
|
|
|
|
if (temp2 && (strcmp(temp2, "/block") == 0)) {
|
|
|
|
/* oops, we have no parent block device, so go back to original directory */
|
|
|
|
strcpy(filename, class_dev->path);
|
|
|
|
partition = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strcat(filename, "/device");
|
2003-12-23 10:07:08 +07:00
|
|
|
|
2003-12-25 10:44:19 +07:00
|
|
|
loop = 2;
|
2003-12-20 16:05:13 +07:00
|
|
|
while (loop--) {
|
|
|
|
struct stat buf;
|
|
|
|
dbg("looking for '%s'", filename);
|
|
|
|
retval = stat(filename, &buf);
|
|
|
|
if (!retval)
|
|
|
|
break;
|
|
|
|
/* sleep to give the kernel a chance to create the device file */
|
|
|
|
sleep(1);
|
|
|
|
}
|
2003-12-25 10:44:19 +07:00
|
|
|
|
2003-12-20 16:05:13 +07:00
|
|
|
loop = 1; /* FIXME put a real value in here for when everything is fixed... */
|
|
|
|
while (loop--) {
|
|
|
|
/* find the sysfs_device for this class device */
|
|
|
|
/* Wouldn't it really be nice if libsysfs could do this for us? */
|
|
|
|
sysfs_device = sysfs_get_classdev_device(class_dev);
|
|
|
|
if (sysfs_device != NULL)
|
|
|
|
goto exit;
|
2003-11-13 08:38:14 +07:00
|
|
|
|
2003-12-25 10:44:19 +07:00
|
|
|
/* if it's a partition, we need to get the parent device */
|
|
|
|
if (partition) {
|
|
|
|
/* FIXME HACK HACK HACK HACK
|
|
|
|
* for some reason partitions need this extra sleep here, in order
|
|
|
|
* to wait for the device properly. Once the libsysfs code is
|
|
|
|
* fixed properly, this sleep should go away, and we can just loop above.
|
|
|
|
*/
|
|
|
|
sleep(1);
|
|
|
|
dbg("really is a partition");
|
|
|
|
class_dev_parent = sysfs_get_classdev_parent(class_dev);
|
|
|
|
if (class_dev_parent == NULL) {
|
|
|
|
dbg("sysfs_get_classdev_parent for class device '%s' failed", class_dev->name);
|
|
|
|
} else {
|
|
|
|
dbg("class_dev_parent->name='%s'", class_dev_parent->name);
|
|
|
|
sysfs_device = sysfs_get_classdev_device(class_dev_parent);
|
|
|
|
if (sysfs_device != NULL)
|
|
|
|
goto exit;
|
2003-11-13 08:38:14 +07:00
|
|
|
}
|
|
|
|
}
|
2003-12-20 16:05:13 +07:00
|
|
|
/* sleep to give the kernel a chance to create the link */
|
2003-12-25 10:44:19 +07:00
|
|
|
/* FIXME remove comment...
|
|
|
|
sleep(1); */
|
2003-11-13 08:38:14 +07:00
|
|
|
}
|
2003-12-23 10:07:08 +07:00
|
|
|
dbg("Timed out waiting for device symlink, continuing on anyway...");
|
2003-12-20 16:05:13 +07:00
|
|
|
exit:
|
|
|
|
return sysfs_device;
|
|
|
|
}
|
|
|
|
|
|
|
|
int namedev_name_device(struct sysfs_class_device *class_dev, struct udevice *udev)
|
|
|
|
{
|
|
|
|
struct sysfs_device *sysfs_device = NULL;
|
|
|
|
int retval = 0;
|
|
|
|
struct perm_device *perm;
|
2003-12-23 10:13:19 +07:00
|
|
|
char *pos;
|
2003-12-20 16:05:13 +07:00
|
|
|
|
|
|
|
udev->mode = 0;
|
2003-12-05 10:21:27 +07:00
|
|
|
|
2003-12-20 16:05:13 +07:00
|
|
|
/* find the sysfs_device associated with this class device */
|
|
|
|
sysfs_device = get_sysfs_device(class_dev);
|
2003-11-13 08:38:14 +07:00
|
|
|
if (sysfs_device) {
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("sysfs_device->path='%s'", sysfs_device->path);
|
|
|
|
dbg("sysfs_device->bus_id='%s'", sysfs_device->bus_id);
|
|
|
|
dbg("sysfs_device->bus='%s'", sysfs_device->bus);
|
2003-11-24 13:25:13 +07:00
|
|
|
strfieldcpy(udev->bus_id, sysfs_device->bus_id);
|
2003-12-20 16:05:13 +07:00
|
|
|
wait_for_device_to_initialize(sysfs_device);
|
2003-07-24 21:27:06 +07:00
|
|
|
} else {
|
2003-12-03 09:38:30 +07:00
|
|
|
dbg("class_dev->name = '%s'", class_dev->name);
|
2003-07-24 21:27:06 +07:00
|
|
|
}
|
2003-11-12 23:26:08 +07:00
|
|
|
|
2003-12-23 10:13:19 +07:00
|
|
|
strfieldcpy(udev->kernel_name, class_dev->name);
|
|
|
|
|
|
|
|
/* get kernel number */
|
|
|
|
pos = class_dev->name + strlen(class_dev->name);
|
|
|
|
while (isdigit(*(pos-1)))
|
|
|
|
pos--;
|
|
|
|
strfieldcpy(udev->kernel_number, pos);
|
|
|
|
dbg("kernel_number='%s'", udev->kernel_number);
|
2003-11-24 13:25:13 +07:00
|
|
|
|
2003-11-12 23:26:08 +07:00
|
|
|
/* rules are looked at in priority order */
|
2003-11-27 08:45:05 +07:00
|
|
|
retval = do_callout(class_dev, udev, sysfs_device);
|
2003-11-12 23:26:08 +07:00
|
|
|
if (retval == 0)
|
2003-11-19 21:19:06 +07:00
|
|
|
goto found;
|
2003-11-12 23:26:08 +07:00
|
|
|
|
2003-11-13 20:52:08 +07:00
|
|
|
retval = do_label(class_dev, udev, sysfs_device);
|
|
|
|
if (retval == 0)
|
2003-11-19 21:19:06 +07:00
|
|
|
goto found;
|
2003-11-13 20:52:08 +07:00
|
|
|
|
|
|
|
retval = do_number(class_dev, udev, sysfs_device);
|
|
|
|
if (retval == 0)
|
2003-11-19 21:19:06 +07:00
|
|
|
goto found;
|
2003-11-13 20:52:08 +07:00
|
|
|
|
2003-11-13 09:08:19 +07:00
|
|
|
retval = do_topology(class_dev, udev, sysfs_device);
|
|
|
|
if (retval == 0)
|
2003-11-19 21:19:06 +07:00
|
|
|
goto found;
|
2003-11-13 09:08:19 +07:00
|
|
|
|
2003-11-27 08:45:05 +07:00
|
|
|
retval = do_replace(class_dev, udev, sysfs_device);
|
2003-11-12 23:26:08 +07:00
|
|
|
if (retval == 0)
|
2003-11-19 21:19:06 +07:00
|
|
|
goto found;
|
2003-11-12 23:26:08 +07:00
|
|
|
|
2003-11-19 21:19:06 +07:00
|
|
|
do_kernelname(class_dev, udev);
|
|
|
|
goto done;
|
2003-10-20 11:56:21 +07:00
|
|
|
|
2003-11-19 21:19:06 +07:00
|
|
|
found:
|
2003-12-08 00:12:07 +07:00
|
|
|
/* substitute placeholder */
|
2003-11-24 13:25:13 +07:00
|
|
|
apply_format(udev, udev->name);
|
2003-12-08 00:12:07 +07:00
|
|
|
apply_format(udev, udev->symlink);
|
[PATCH] implement printf-like placeholder support for NAME
> Problem is, if you use the LABEL rule to match a device, like a SCSI
> vendor, then all of the partitions, as well as the main block device,
> will end up with the same name. That's why I added the "add the number"
> hack to the LABEL rule.
>
> So yes, your patch is correct in that we shouldn't always be adding the
> number to any match for LABEL (like for char devices), but if we do
> that, then we break partitions. Your '%' patch fixes this, but I'd just
> like to extend it a bit. Let me see what I can come up with...
Oh, I see. Do you mean something like this:
LABEL, BUS="usb", model="Creative Labs WebCam 3", NAME="webcam%n-%M:%m-test"
results in: "webcam0-81:0-test"
Nov 15 16:51:53 pim udev[16193]: get_class_dev: looking at /sys/class/video4linux/video0
Nov 15 16:51:53 pim udev[16193]: get_class_dev: class_dev->name = video0
Nov 15 16:51:53 pim udev[16193]: get_major_minor: dev = 81:0
Nov 15 16:51:53 pim udev[16193]: get_major_minor: found major = 81, minor = 0
Nov 15 16:51:53 pim udev[16193]: udev_add_device: name = webcam0-81:0-test
Nov 15 16:51:53 pim udev[16193]: create_node: mknod(/udev/webcam0-81:0-test, 020666, 81, 0)
implement printf-like placeholder support for NAME
%n-kernel number, %M-major number, %m-minor number
2003-11-18 15:59:27 +07:00
|
|
|
|
2003-11-19 21:19:06 +07:00
|
|
|
done:
|
2003-12-04 09:33:58 +07:00
|
|
|
perm = find_perm(udev->name);
|
|
|
|
if (perm) {
|
|
|
|
udev->mode = perm->mode;
|
|
|
|
strfieldcpy(udev->owner, perm->owner);
|
|
|
|
strfieldcpy(udev->group, perm->group);
|
|
|
|
} else {
|
|
|
|
/* no matching perms found :( */
|
2003-10-22 12:28:32 +07:00
|
|
|
udev->mode = get_default_mode(class_dev);
|
|
|
|
udev->owner[0] = 0x00;
|
|
|
|
udev->group[0] = 0x00;
|
2003-07-25 18:01:48 +07:00
|
|
|
}
|
2003-12-04 09:33:58 +07:00
|
|
|
dbg("name, '%s' is going to have owner='%s', group='%s', mode = %#o",
|
|
|
|
udev->name, udev->owner, udev->group, udev->mode);
|
2003-11-13 08:38:14 +07:00
|
|
|
|
2003-11-12 23:26:08 +07:00
|
|
|
return 0;
|
2003-07-19 12:48:28 +07:00
|
|
|
}
|
|
|
|
|
2003-07-17 15:24:51 +07:00
|
|
|
int namedev_init(void)
|
|
|
|
{
|
|
|
|
int retval;
|
2003-12-05 10:21:27 +07:00
|
|
|
|
2003-12-03 16:08:46 +07:00
|
|
|
retval = namedev_init_rules();
|
2003-07-17 15:24:51 +07:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
retval = namedev_init_permissions();
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
2003-12-03 09:38:30 +07:00
|
|
|
dump_config_dev_list();
|
2003-12-04 09:33:58 +07:00
|
|
|
dump_perm_dev_list();
|
2003-07-17 15:24:51 +07:00
|
|
|
return retval;
|
|
|
|
}
|