This prevents the need to excessively provide a <i>GROUP="audio"</i> key on every following rule which names sound devices.<br /><br />
-udev defaults to creating nodes with unix permissions of 0660 (read/write to owner and group), which is configured by the <b>default_mode</b> setting inside <i>/etc/udev/udev.conf</i>. There may be some situations where you do not want to use the default permissions on your device node. Fortunately, you can easily override the permissions in your rules using the <i>MODE</i> assignment key. As an example, the following rule defines that the inotify node shall be readable and writable to everyone:
+udev defaults to creating nodes with unix permissions of 0660 (read/write to owner and group). There may be some situations where you do not want to use the default permissions on your device node. Fortunately, you can easily override the permissions in your rules using the <i>MODE</i> assignment key. As an example, the following rule defines that the inotify node shall be readable and writable to everyone:
<blockquote><pre>KERNEL="inotify", NAME="misc/%k", SYMLINK="%k", MODE="0666"</pre></blockquote>
# There are a number of modifiers that are allowed to be used in some of the
# fields. See the udev man page for a full description of them.
#
-# default is OWNER="root" GROUP="root", MODE="0600"
+# default is OWNER="root" GROUP="root", MODE="0660"
#
# all block devices
int fd;
int rc = 0;
+ logging_init("ata_id");
+
for (i = 1 ; i < argc; i++) {
char *arg = argv[i];
printf("ID_MODEL=%s\n", model);
printf("ID_SERIAL=%s\n", serial);
printf("ID_REVISION=%s\n", revision);
- } else
- printf("%s_%s\n", model, serial);
+ } else {
+ if (serial[0] != '\0')
+ printf("%s_%s\n", model, serial);
+ else
+ printf("%s\n", model);
+ }
close:
close(fd);
--- /dev/null
+# Makefile for dasd_id
+#
+# Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
+#
+# 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.
+#
+
+PROG = dasd_id
+
+all: $(PROG)
+
+prefix =
+exec_prefix = ${prefix}
+etcdir = ${prefix}/etc
+sbindir = ${exec_prefix}/sbin
+usrbindir = ${exec_prefix}/usr/bin
+usrsbindir = ${exec_prefix}/usr/sbin
+mandir = ${prefix}/usr/share/man
+devddir = ${etcdir}/dev.d/default
+configdir = ${etcdir}/udev/
+initdir = ${etcdir}/init.d/
+srcdir = .
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+
+CFLAGS+=-D_FILE_OFFSET_BITS=64
+
+OBJS = dasd_id.o ../../udev.a
+
+$(OBJS): $(HEADERS)
+
+.c.o:
+ $(QUIET) $(CC) $(CFLAGS) -c -o $@ $<
+
+$(PROG): $(OBJS) $(HEADERS)
+ $(QUIET) $(LD) $(LDFLAGS) -o $(PROG) $(OBJS) $(LIB_OBJS)
+
+clean:
+ rm -f $(PROG) $(OBJS)
+
+spotless: clean
+
+install: all
+ $(INSTALL_PROGRAM) $(PROG) $(DESTDIR)$(sbindir)/$(PROG)
+
+uninstall:
+ - rm $(DESTDIR)$(sbindir)/$(PROG)
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
+#include <errno.h>
#include <sys/ioctl.h>
#include <asm/types.h>
-#include "volume_id.h"
-#include "logging.h"
-#include "util.h"
-#include "dasd.h"
+#include "../../logging.h"
+#include "../../udev_utils.h"
+
+#ifdef USE_LOG
+void log_message(int priority, const char *format, ...)
+{
+ va_list args;
+ static int udev_log = -1;
+
+ if (udev_log == -1) {
+ const char *value;
+
+ value = getenv("UDEV_LOG");
+ if (value)
+ udev_log = log_priority(value);
+ else
+ udev_log = LOG_ERR;
+ }
+
+ if (priority > udev_log)
+ return;
+
+ va_start(args, format);
+ vsyslog(priority, format, args);
+ va_end(args);
+}
+#endif
+
+/*
+ * Only compile this on S/390. Doesn't make any sense
+ * for other architectures.
+ */
static unsigned char EBCtoASC[256] =
{
-INP */
0x07, 0x07, 0x1C, 0x07, 0x07, 0x0A, 0x17, 0x1B,
/* 0x28 -SA -SFE -SM -CSP -MFA ENQ ACK BEL
- -SW */
+ -SW */
0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x06, 0x07,
/* 0x30 ---- ---- SYN -IR -PP -TRN -NBS EOT */
0x07, 0x07, 0x16, 0x07, 0x07, 0x07, 0x07, 0x04,
0x8D, 0xE1, 0x21, 0x24, 0x2A, 0x29, 0x3B, 0xAA,
/* 0x60 - / ---- Ä ---- ---- ---- */
0x2D, 0x2F, 0x07, 0x8E, 0x07, 0x07, 0x07, 0x8F,
-/* 0x68 ---- , % _ > ? */
+/* 0x68 ---- , % _ > ? */
0x80, 0xA5, 0x07, 0x2C, 0x25, 0x5F, 0x3E, 0x3F,
/* 0x70 --- ---- ---- ---- ---- ---- ---- */
0x07, 0x90, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
};
-static void vtoc_ebcdic_dec (const unsigned char *source, unsigned char *target, int l)
+static void vtoc_ebcdic_dec (const unsigned char *source, char *target, int l)
{
int i;
for (i = 0; i < l; i++)
- target[i]=EBCtoASC[(unsigned char)(source[i])];
+ target[i]=(char)EBCtoASC[(unsigned char)(source[i])];
}
-/*
+/*
* struct dasd_information_t
* represents any data about the data, which is visible to userspace
*/
char configuration_data[256]; /* from read_configuration_data */
} dasd_information_t;
-#define _IOC_NRBITS 8
-#define _IOC_TYPEBITS 8
-#define _IOC_SIZEBITS 14
-#define _IOC_DIRBITS 2
-#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
-#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
-#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
-#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
-#define _IOC_NRSHIFT 0
-#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
-#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
-#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
#define DASD_IOCTL_LETTER 'D'
-
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
#define BLKSSZGET _IO(0x12,104)
-int volume_id_probe_dasd(struct volume_id *id)
+unsigned char serial[8];
+
+static int dasd_id(int fd)
{
int blocksize;
dasd_information_t info;
__u8 *data;
__u8 *label_raw;
- unsigned char name[7];
-
- dbg("probing");
- if (ioctl(id->fd, BIODASDINFO, &info) != 0)
+ if (ioctl(fd, BIODASDINFO, &info) != 0) {
+ dbg("not a dasd");
return -1;
+ }
- if (ioctl(id->fd, BLKSSZGET, &blocksize) != 0)
- return -1;
+ if (ioctl(fd, BLKSSZGET, &blocksize) != 0) {
+ err("failed to get blocksize");
+ return -1;
+ }
- data = volume_id_get_buffer(id, info.label_block * blocksize, 16);
- if (data == NULL)
- return -1;
+ if (lseek(fd,info.label_block * blocksize, SEEK_SET) == -1) {
+ err("seek failed on dasd");
+ return -1;
+ }
+
+ data = malloc(blocksize);
+ if (data == NULL)
+ return -1;
+
+ if (read(fd, data, blocksize) == -1) {
+ err("read disklabel failed");
+ free(data);
+ return -1;
+ }
- if ((!info.FBA_layout) && (!strcmp(info.type, "ECKD")))
- label_raw = &data[8];
- else
- label_raw = &data[4];
+ if ((!info.FBA_layout) && (!strcmp(info.type, "ECKD")))
+ label_raw = &data[8];
+ else
+ label_raw = &data[4];
+ serial[6] = '\0';
- name[6] = '\0';
- volume_id_set_usage(id, VOLUME_ID_DISKLABEL);
- id->type = "dasd";
- volume_id_set_label_raw(id, label_raw, 6);
- vtoc_ebcdic_dec(label_raw, name, 6);
- volume_id_set_label_string(id, name, 6);
+ vtoc_ebcdic_dec(label_raw, serial, 6);
+ free(data);
+
+ return 0;
+ }
+
+int main(int argc, char *argv[])
+{
+ const char *node = NULL;
+ int i;
+ int export = 0;
+ int fd;
+ int rc = 0;
- return 0;
+ logging_init("dasd_id");
+
+ for (i = 1; i < argc; i++) {
+ char *arg = argv[i];
+
+ if (strcmp(arg, "--export") == 0) {
+ export = 1;
+ } else
+ node = arg;
+ }
+ if (!node) {
+ err("no node specified");
+ rc = 1;
+ goto exit;
+ }
+
+ fd = open(node, O_RDONLY);
+ if (fd < 0) {
+ err("unable to open '%s'", node);
+ rc = 1;
+ goto exit;
+ }
+
+ if (dasd_id(fd) < 0) {
+ err("dasd_id failed: %s", strerror(errno));
+ rc = 1;
+ }
+
+ if (export) {
+ printf("ID_TYPE=disk\n");
+ printf("ID_SERIAL=%s\n",serial);
+ } else
+ printf("%s\n", serial);
+
+ close(fd);
+exit:
+ logging_close();
+ return rc;
}
+
* options are not supported, but other code is still left in place for
* now.
*/
-static const char short_options[] = "bd:f:gip:s:uvVx";
+static const char short_options[] = "abd:f:gip:s:uvVx";
/*
* Just duplicate per dev options.
*/
char sysfs_mnt_path[SYSFS_PATH_MAX];
static int all_good;
+static int always_info;
static char *default_callout;
static int dev_specified;
static int sys_specified;
dprintf("option '%c'\n", option);
switch (option) {
+ case 'a':
+ always_info = 1;
+ break;
case 'b':
all_good = 0;
break;
retval = 1;
} else if (scsi_get_serial(scsi_dev, maj_min_dev, page_code,
serial, MAX_SERIAL_LEN)) {
- retval = 1;
+ retval = always_info?0:1;
} else {
retval = 0;
}
#define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */
#define SG_ERR_CAT_TIMEOUT 3
#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */
+#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */
#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */
#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */
return SG_ERR_CAT_MEDIA_CHANGED;
if (0x29 == asc)
return SG_ERR_CAT_RESET;
+ } else if (sense_key == ILLEGAL_REQUEST) {
+ return SG_ERR_CAT_NOTSUPPORTED;
}
}
return SG_ERR_CAT_SENSE;
retval = sg_err_category3(&io_hdr);
switch (retval) {
+ case SG_ERR_CAT_NOTSUPPORTED:
+ buf[1] = 0;
+ /* Fallthrough */
case SG_ERR_CAT_CLEAN:
case SG_ERR_CAT_RECOVERED:
retval = 0;
static char type_str[16];
static int use_usb_info;
+static int use_num_info;
static int export;
+static int debug;
static void set_str(char *to, const unsigned char *from, int count)
{
struct sysfs_device *target_dev;
struct sysfs_device *host_dev, *interface_dev, *usb_dev;
struct sysfs_attribute *scsi_model, *scsi_vendor, *scsi_type, *scsi_rev;
- struct sysfs_attribute *usb_model, *usb_vendor, *usb_rev, *usb_serial;
+ struct sysfs_attribute *usb_model = NULL, *usb_vendor = NULL, *usb_rev, *usb_serial;
struct sysfs_attribute *if_class, *if_subclass;
int if_class_num;
int protocol = 0;
if_class = sysfs_get_device_attr(interface_dev, "bInterfaceClass");
if (!if_class) {
info("%s: cannot get bInterfaceClass attribute", interface_dev->name);
- return -1;
+ return 1;
}
if_class_num = strtoul(if_class->value, NULL, 16);
if (if_class_num != 8) {
set_usb_iftype(type_str, if_class->value, sizeof(type_str) - 1);
+ protocol = 0;
} else {
if_subclass = sysfs_get_device_attr(interface_dev,
"bInterfaceSubClass");
/* Generic SPC-2 device */
scsi_vendor = sysfs_get_device_attr(scsi_dev, "vendor");
if (!scsi_vendor) {
- info("%s: cannot get vendor attribute", scsi_dev->name);
- return -1;
+ info("%s: cannot get SCSI vendor attribute", scsi_dev->name);
+ return 1;
}
set_str(vendor_str, scsi_vendor->value, sizeof(vendor_str)-1);
scsi_model = sysfs_get_device_attr(scsi_dev, "model");
if (!scsi_model) {
- info("%s: cannot get model attribute", scsi_dev->name);
- return -1;
+ info("%s: cannot get SCSI model attribute", scsi_dev->name);
+ return 1;
}
set_str(model_str, scsi_model->value, sizeof(model_str)-1);
scsi_type = sysfs_get_device_attr(scsi_dev, "type");
if (!scsi_type) {
- info("%s: cannot get type attribute", scsi_dev->name);
- return -1;
+ info("%s: cannot get SCSI type attribute", scsi_dev->name);
+ return 1;
}
set_scsi_type(type_str, scsi_type->value, sizeof(type_str)-1);
scsi_rev = sysfs_get_device_attr(scsi_dev, "rev");
if (!scsi_rev) {
- info("%s: cannot get type attribute", scsi_dev->name);
- return -1;
+ info("%s: cannot get SCSI revision attribute", scsi_dev->name);
+ return 1;
}
set_str(revision_str, scsi_rev->value, sizeof(revision_str)-1);
/* Fallback to USB vendor & device */
if (vendor_str[0] == '\0') {
- usb_vendor = sysfs_get_device_attr(usb_dev, "manufacturer");
+ if (!use_num_info)
+ if (!(usb_vendor = sysfs_get_device_attr(usb_dev, "manufacturer")))
+ dbg("No USB vendor string found, using idVendor");
+
if (!usb_vendor) {
- dbg("No USB vendor string found, using idVendor");
- usb_vendor = sysfs_get_device_attr(usb_dev, "idVendor");
+ if (!(usb_vendor = sysfs_get_device_attr(usb_dev, "idVendor"))) {
+ dbg("No USB vendor information available\n");
+ sprintf(vendor_str,"0000");
+ }
}
set_str(vendor_str,usb_vendor->value, sizeof(vendor_str) - 1);
}
if (model_str[0] == '\0') {
- usb_model = sysfs_get_device_attr(usb_dev, "product");
+ if (!use_num_info)
+ if (!(usb_model = sysfs_get_device_attr(usb_dev, "product")))
+ dbg("No USB model string found, using idProduct");
+
if (!usb_model) {
- dbg("No USB model string found, using idProduct");
- usb_model = sysfs_get_device_attr(usb_dev, "idProduct");
+ if (!(usb_model = sysfs_get_device_attr(usb_dev, "idProduct"))) {
+ dbg("No USB model information available\n");
+ sprintf(model_str,"0000");
+ }
}
set_str(model_str, usb_model->value, sizeof(model_str) - 1);
}
exit(1);
}
- while ((option = getopt(argc, argv, "ux")) != -1 ) {
+ while ((option = getopt(argc, argv, "dnux")) != -1 ) {
if (optarg)
dbg("option '%c' arg '%s'", option, optarg);
else
dbg("option '%c'", option);
switch (option) {
+ case 'd':
+ debug = 1;
+ break;
+ case 'n':
+ use_num_info=1;
+ use_usb_info=1;
+ break;
case 'u':
use_usb_info=1;
break;
break;
default:
info("Unknown or bad option '%c' (0x%x)", option, option);
- retval = -1;
+ retval = 1;
break;
}
}
retval = usb_id(target_path);
- if (export) {
- printf("ID_VENDOR=%s\n", vendor_str);
- printf("ID_MODEL=%s\n", model_str);
- printf("ID_REVISION=%s\n", revision_str);
- if (serial_str[0] == '\0') {
- printf("ID_SERIAL=%s_%s\n",
- vendor_str, model_str);
- } else {
- printf("ID_SERIAL=%s_%s_%s\n",
- vendor_str, model_str, serial_str);
- }
- printf("ID_TYPE=%s\n", type_str);
- } else {
- if (serial_str[0] == '\0') {
- printf("%s_%s\n",
- vendor_str, model_str);
+ if (retval == 0) {
+ if (export) {
+ printf("ID_VENDOR=%s\n", vendor_str);
+ printf("ID_MODEL=%s\n", model_str);
+ printf("ID_REVISION=%s\n", revision_str);
+ if (serial_str[0] == '\0') {
+ printf("ID_SERIAL=%s_%s\n",
+ vendor_str, model_str);
+ } else {
+ printf("ID_SERIAL=%s_%s_%s\n",
+ vendor_str, model_str, serial_str);
+ }
+ printf("ID_TYPE=%s\n", type_str);
} else {
- printf("%s_%s_%s\n",
- vendor_str, model_str, serial_str);
+ if (serial_str[0] == '\0') {
+ printf("%s_%s\n",
+ vendor_str, model_str);
+ } else {
+ printf("%s_%s_%s\n",
+ vendor_str, model_str, serial_str);
+ }
}
}
exit(retval);
hpfs * - - -
romfs *
minix *
-dasd *
highpoint *
isw_raid *
lsi_raid *
#include "../../udev_utils.h"
#include "../../logging.h"
#include "volume_id/volume_id.h"
-#include "volume_id/dasd.h"
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
vid = volume_id_open_node(node);
if (vid == NULL) {
- fprintf(stderr, "error open volume\n");
+ fprintf(stderr, "%s: error open volume\n", node);
rc = 2;
goto exit;
}
if (volume_id_probe_all(vid, 0, size) == 0)
goto print;
- if (volume_id_probe_dasd(vid) == 0)
- goto print;
-
- fprintf(stderr, "unknown volume type\n");
+ if (print != PRINT_EXPORT)
+ fprintf(stderr, "%s: unknown volume type\n", node);
rc = 3;
goto exit;
$(VOLUME_ID_BASE)/romfs.o \
$(VOLUME_ID_BASE)/sysv.o \
$(VOLUME_ID_BASE)/minix.o \
- $(VOLUME_ID_BASE)/dasd.o \
$(VOLUME_ID_BASE)/luks.o \
$(VOLUME_ID_BASE)/volume_id.o \
$(VOLUME_ID_BASE)/util.o
$(VOLUME_ID_BASE)/romfs.h \
$(VOLUME_ID_BASE)/sysv.h \
$(VOLUME_ID_BASE)/minix.h \
- $(VOLUME_ID_BASE)/dasd.h \
$(VOLUME_ID_BASE)/luks.h \
$(VOLUME_ID_BASE)/volume_id.h \
$(VOLUME_ID_BASE)/util.h
+++ /dev/null
-/*
- * dasdlabel - read label from s390 block device
- *
- * Copyright (C) 2004 Arnd Bergmann <arnd@arndb.de>
- *
- * 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.
- *
- */
-
-#ifndef _VOLUME_ID_DASDLABEL_
-#define _VOLUME_ID_DASDLABEL_
-
-extern int volume_id_probe_dasd(struct volume_id *id);
-
-#endif
#ifndef _VOLUME_ID_H_
#define _VOLUME_ID_H_
-#define VOLUME_ID_VERSION 44
+#define VOLUME_ID_VERSION 45
#define VOLUME_ID_LABEL_SIZE 64
#define VOLUME_ID_UUID_SIZE 36
extras/ata_id \
extras/volume_id \
extras/usb_id \
+ extras/dasd_id \
extras/run_directory"
[ -z "$KERNEL_DIR" ] && KERNEL_DIR=/lib/modules/`uname -r`/build
KERNEL=="ttyUSB[0-9]*", NAME="right"
KERNEL=="ttyUSB[0-9]*", NAME=""
KERNEL=="ttyUSB[0-9]*", NAME="wrong"
+EOF
+ },
+ {
+ desc => "test multi matches",
+ subsys => "tty",
+ devpath => "/class/tty/ttyUSB0",
+ exp_name => "right",
+ rules => <<EOF
+KERNEL=="ttyUSB*|nothing", NAME="right"
+KERNEL=="ttyUSB*", NAME="wrong"
+EOF
+ },
+ {
+ desc => "test multi matches 2",
+ subsys => "tty",
+ devpath => "/class/tty/ttyUSB0",
+ exp_name => "right",
+ rules => <<EOF
+KERNEL=="dontknow*|*nothing", NAME="nomatch"
+KERNEL=="dontknow*|ttyUSB*|nothing*", NAME="right"
+KERNEL=="ttyUSB*", NAME="wrong"
+EOF
+ },
+ {
+ desc => "IMPORT parent test sequence 1/2 (keep)",
+ subsys => "block",
+ devpath => "/block/sda",
+ exp_name => "parent",
+ option => "keep",
+ rules => <<EOF
+KERNEL=="sda", IMPORT="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
+KERNEL=="sda", NAME="parent"
+EOF
+ },
+ {
+ desc => "IMPORT parent test sequence 2/2 (keep)",
+ subsys => "block",
+ devpath => "/block/sda/sda1",
+ exp_name => "parentenv-parent_right",
+ option => "clean",
+ rules => <<EOF
+KERNEL=="sda1", IMPORT{parent}="PARENT*", NAME="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
EOF
},
);
return import_keys_into_env(udev, result, reslen);
}
+static int import_parent_into_env(struct udevice *udev, struct sysfs_class_device *class_dev, const char *filter)
+{
+ struct sysfs_class_device *parent = sysfs_get_classdev_parent(class_dev);
+ int rc = -1;
+
+ if (parent != NULL) {
+ struct udevice udev_parent;
+ struct name_entry *name_loop;
+
+ dbg("found parent '%s', get the node name", parent->path);
+ udev_init_device(&udev_parent, NULL, NULL, NULL);
+ /* import the udev_db of the parent */
+ if (udev_db_get_device(&udev_parent, &parent->path[strlen(sysfs_path)]) == 0) {
+ dbg("import stored parent env '%s'", udev_parent.name);
+ list_for_each_entry(name_loop, &udev_parent.env_list, node) {
+ char name[NAME_SIZE];
+ char *pos;
+
+ strlcpy(name, name_loop->name, sizeof(name));
+ pos = strchr(name, '=');
+ if (pos) {
+ pos[0] = '\0';
+ pos++;
+ if (strcmp_pattern(filter, name) == 0) {
+ dbg("import key '%s'", name_loop->name);
+ name_list_add(&udev->env_list, name_loop->name, 0);
+ setenv(name, pos, 1);
+ } else
+ dbg("skip key '%s'", name_loop->name);
+ }
+ }
+ rc = 0;
+ } else
+ dbg("parent not found in database");
+ udev_cleanup_device(&udev_parent);
+ }
+
+ return rc;
+}
+
/* finds the lowest positive N such that <name>N isn't present in the udevdb
* if <name> doesn't exist, 0 is returned, N otherwise
*/
break;
}
pos = getenv(attr);
- if (pos == NULL)
+ if (pos == NULL) {
+ dbg("env '%s' not avialable", attr);
break;
- strlcat(string, pos, maxsize);
+ }
dbg("substitute env '%s=%s'", attr, pos);
+ strlcat(string, pos, maxsize);
break;
default:
err("unknown substitution type=%i", type);
static int match_key(const char *key_name, struct udev_rule *rule, struct key *key, const char *val)
{
int match;
+ char value[PATH_SIZE];
char *key_value;
+ char *pos;
if (key->operation == KEY_OP_UNSET)
return 0;
- key_value = rule->buf + key->val_off;
+ strlcpy(value, rule->buf + key->val_off, sizeof(value));
+ key_value = value;
- dbg("check for %s '%s' <-> '%s'", key_name, key_value, val);
- match = (strcmp_pattern(key_value, val) == 0);
- if (match && (key->operation != KEY_OP_NOMATCH)) {
- dbg("%s is matching (matching value)", key_name);
- return 0;
- }
- if (!match && (key->operation == KEY_OP_NOMATCH)) {
- dbg("%s is matching, (non matching value)", key_name);
- return 0;
+ dbg("key %s value='%s'", key_name, key_value);
+ while (key_value) {
+ pos = strchr(key_value, '|');
+ if (pos) {
+ pos[0] = '\0';
+ pos++;
+ }
+ dbg("match %s '%s' <-> '%s'", key_name, key_value, val);
+ match = (strcmp_pattern(key_value, val) == 0);
+ if (match && (key->operation != KEY_OP_NOMATCH)) {
+ dbg("%s is true (matching value)", key_name);
+ return 0;
+ }
+ if (!match && (key->operation == KEY_OP_NOMATCH)) {
+ dbg("%s is true (non-matching value)", key_name);
+ return 0;
+ }
+ key_value = pos;
}
-
- dbg("%s is not matching", key_name);
+ dbg("%s is false", key_name);
return -1;
}
match = (wait_for_sysfs(udev, key_val(rule, &rule->wait_for_sysfs), 3) == 0);
if (match && (rule->wait_for_sysfs.operation != KEY_OP_NOMATCH)) {
- dbg("WAIT_FOR_SYSFS is matching (matching value)");
+ dbg("WAIT_FOR_SYSFS is true (matching value)");
return 0;
}
if (!match && (rule->wait_for_sysfs.operation == KEY_OP_NOMATCH)) {
- dbg("WAIT_FOR_SYSFS is matching, (non matching value)");
+ dbg("WAIT_FOR_SYSFS is true, (non matching value)");
return 0;
}
- dbg("WAIT_FOR_SYSFS is not matching");
+ dbg("WAIT_FOR_SYSFS is false");
return -1;
}
strlcpy(import, key_val(rule, &rule->import), sizeof(import));
apply_format(udev, import, sizeof(import), class_dev, sysfs_device);
dbg("check for IMPORT import='%s'", import);
- if (rule->import_exec) {
+ if (rule->import_type == IMPORT_PROGRAM) {
dbg("run executable file import='%s'", import);
rc = import_program_into_env(udev, import);
- } else {
+ } else if (rule->import_type == IMPORT_FILE) {
dbg("import file import='%s'", import);
rc = import_file_into_env(udev, import);
+ } else if (rule->import_type == IMPORT_PARENT && class_dev) {
+ dbg("import parent import='%s'", import);
+ rc = import_parent_into_env(udev, class_dev, import);
}
if (rc) {
dbg("IMPORT failed");
apply_format(udev, program, sizeof(program), class_dev, sysfs_device);
dbg("check for PROGRAM program='%s", program);
if (execute_program(program, udev->subsystem, result, sizeof(result), NULL) != 0) {
- dbg("PROGRAM is not matching");
+ dbg("PROGRAM is false");
if (rule->program.operation != KEY_OP_NOMATCH)
goto exit;
} else {
if (rule->group.operation == KEY_OP_ASSIGN_FINAL)
udev->group_final = 1;
strlcpy(udev->group, key_val(rule, &rule->group), sizeof(udev->group));
- apply_format(udev, key_val(rule, &rule->group), sizeof(udev->group), class_dev, sysfs_device);
+ apply_format(udev, udev->group, sizeof(udev->group), class_dev, sysfs_device);
dbg("applied group='%s' to '%s'", udev->group, udev->kernel_name);
}
struct key_pair keys[PAIRS_MAX];
};
+enum import_type {
+ IMPORT_UNSET,
+ IMPORT_PROGRAM,
+ IMPORT_FILE,
+ IMPORT_PARENT,
+};
+
struct udev_rule {
struct key kernel_name;
struct key subsystem;
struct key result;
struct key modalias;
struct key import;
+ enum import_type import_type;
struct key wait_for_sysfs;
struct key_pairs sysfs;
struct key_pairs env;
unsigned int partitions;
unsigned int last_rule:1,
ignore_device:1,
- ignore_remove:1,
- import_exec:1;
+ ignore_remove:1;
size_t bufsize;
char buf[];
attr = get_key_attribute(key + sizeof("IMPORT")-1);
if (attr && strstr(attr, "program")) {
dbg("IMPORT will be executed");
- rule->import_exec = 1;
+ rule->import_type = IMPORT_PROGRAM;
} else if (attr && strstr(attr, "file")) {
dbg("IMPORT will be included as file");
+ rule->import_type = IMPORT_FILE;
+ } else if (attr && strstr(attr, "parent")) {
+ dbg("IMPORT will include the parent values");
+ rule->import_type = IMPORT_PARENT;
} else {
/* figure it out if it is executable */
char file[PATH_SIZE];
pos[0] = '\0';
dbg("IMPORT auto mode for '%s'", file);
if (!lstat(file, &stats) && (stats.st_mode & S_IXUSR)) {
- dbg("IMPORT is executable, will be executed");
- rule->import_exec = 1;
+ dbg("IMPORT is executable, will be executed (autotype)");
+ rule->import_type = IMPORT_PROGRAM;
+ } else {
+ dbg("IMPORT is not executable, will be included as file (autotype)");
+ rule->import_type = IMPORT_FILE;
}
}
add_rule_key(rule, &rule->import, operation, value);
rules->buf = NULL;
return -1;
}
+ rules->mapped = 1;
return 0;
}
}
/* forks event and removes event from run queue when finished */
-static void execute_udev(struct uevent_msg *msg)
+static void udev_event_fork(struct uevent_msg *msg)
{
char *const argv[] = { "udev", msg->subsystem, NULL };
pid_t pid;
close(uevent_netlink_sock);
close(udevd_sock);
logging_close();
-
setpriority(PRIO_PROCESS, 0, UDEV_PRIORITY);
execve(udev_bin, argv, msg->envp);
err("exec of child failed");
_exit(1);
- break;
case -1:
err("fork of child failed");
msg_queue_delete(msg);
if (running_with_devpath(loop_msg, max_childs) == 0) {
/* move event to run list */
list_move_tail(&loop_msg->node, &running_list);
- execute_udev(loop_msg);
+ udev_event_fork(loop_msg);
running++;
dbg("moved seq %llu to running list", loop_msg->seqnum);
} else
static int init_udevd_socket(void)
{
struct sockaddr_un saddr;
+ const int buffersize = 1024 * 1024;
socklen_t addrlen;
const int feature_on = 1;
int retval;
return -1;
}
+ /* set receive buffersize */
+ setsockopt(udevd_sock, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
+
/* the bind takes care of ensuring only one copy running */
retval = bind(udevd_sock, (struct sockaddr *) &saddr, addrlen);
if (retval < 0) {
static int init_uevent_netlink_sock(void)
{
struct sockaddr_nl snl;
+ const int buffersize = 1024 * 1024;
int retval;
memset(&snl, 0x00, sizeof(struct sockaddr_nl));
return -1;
}
+ /* set receive buffersize */
+ setsockopt(uevent_netlink_sock, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));
+
retval = bind(uevent_netlink_sock, (struct sockaddr *) &snl,
sizeof(struct sockaddr_nl));
if (retval < 0) {