linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* replace dev.d/ with a rule based program execution
@ 2005-02-21 18:12 Kay Sievers
  2005-02-22  8:08 ` Hannes Reinecke
                   ` (14 more replies)
  0 siblings, 15 replies; 16+ messages in thread
From: Kay Sievers @ 2005-02-21 18:12 UTC (permalink / raw)
  To: linux-hotplug

Here is an experimental patch to replace the brute-force dev.d/ script
execution by a rule based model, with the same logic we currently use to
name a device. While searching for a rule to apply, we collect programs
to execute after node creation/removal.

This makes it possible to gain complete control of the execution of programs
for a specific device instead of letting the programs exit if they don't
want to handle the device.

We apply the rule on device remove events too. A ACTION="<value>" match can
be used to write rules that are only applied on a specific action.

I've replaced the following:
  [kay@pim ~]$ tree /etc/dev.d/
  /etc/dev.d/
  |-- default
  |   |-- 00-log.dev
  |   |-- 05-pam_console.dev -> ../../udev/scripts/pam_console.dev
  |   `-- 10-hal.dev -> /usr/libexec/hal.dev
  |-- fd0
  |   `-- 10-MAKEDEV.dev -> ../../udev/scripts/MAKEDEV.dev
  |-- fd1
  |   `-- 10-MAKEDEV.dev -> ../../udev/scripts/MAKEDEV.dev
  |-- fd2
  |   `-- 10-MAKEDEV.dev -> ../../udev/scripts/MAKEDEV.dev
  |-- fd3
  |   `-- 10-MAKEDEV.dev -> ../../udev/scripts/MAKEDEV.dev
  `-- sound
      `-- alsa.dev

With these rules:
  KERNEL="ttyUSB*", HOTPLUG="<usb-serial-device program>"
  SUBSYSTEM="tty", OPTIONS="no_hotplug"
  SUBSYSTEM="vc", OPTIONS="no_hotplug"

  ACTION="add", SUBSYSTEM="sound", HOTPLUG="/etc/dev.d/sound/alsa.dev"
  ACTION="add", KERNEL="fd*", HOTPLUG="/etc/udev/scripts/MAKEDEV.dev"
  ACTION="add", HOTPLUG="/etc/udev/scripts/pam_console.dev"

  HOTPLUG="/usr/libexec/hal.dev"
  HOTPLUG="/etc/dev.d/default/00-log.dev"

On my box, udevstart takes 2.1 seconds instead of 8.6 seconds to run with
my default setup. Mainly because it will not run anything for all the virtual
tty devices. Any tty device which should be catched, needs a rule before the
"no_hotplug" option.

It is also possible to pass arguments to the scripts, which sometimes
makes it no longer necessary to wrap a program with a shell script.

We could also remove all the hardcoded knowledge about sysfs in the
wait_for_sysfs logic and replace it by a few simple ignore_device rules.

The same model could easily replace the whole hotplug.d/ multiplexing and
give use an efficient rule based event management with a single source of
policy.

What do you think?

Thanks,
Kay


=== namedev.c 1.188 vs edited ==--- 1.188/namedev.c	2005-02-21 07:01:52 +01:00
+++ edited/namedev.c	2005-02-21 17:29:11 +01:00
@@ -571,7 +571,7 @@ static int match_rule(struct udevice *ud
 	if (dev->kernel[0] != '\0') {
 		dbg("check for " FIELD_KERNEL " dev->kernel='%s' class_dev->name='%s'",
 		    dev->kernel, class_dev->name);
-		if (strcmp_pattern(dev->kernel, class_dev->name) != 0) {
+		if (strcmp_pattern(dev->kernel, udev->kernel_name) != 0) {
 			dbg(FIELD_KERNEL " is not matching");
 			goto exit;
 		}
@@ -588,6 +588,16 @@ static int match_rule(struct udevice *ud
 		dbg(FIELD_SUBSYSTEM " matches");
 	}
 
+	if (dev->action[0] != '\0') {
+		dbg("check for " FIELD_ACTION " dev->action='%s' class_dev->name='%s'",
+		    dev->action, class_dev->name);
+		if (strcmp_pattern(dev->action, udev->action) != 0) {
+			dbg(FIELD_ACTION " is not matching");
+			goto exit;
+		}
+		dbg(FIELD_ACTION " matches");
+	}
+
 	/* walk up the chain of physical devices and find a match */
 	while (1) {
 		/* check for matching driver */
@@ -689,13 +699,13 @@ exit:
 	return -1;
 }
 
-int namedev_name_device(struct udevice *udev, struct sysfs_class_device *class_dev)
+int rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev)
 {
 	struct sysfs_class_device *class_dev_parent;
 	struct sysfs_device *sysfs_device = NULL;
 	struct config_device *dev;
 
-	dbg("class_dev->name='%s'", class_dev->name);
+	dbg("udev->devpath='%s'", udev->devpath);
 
 	/* Figure out where the "device"-symlink is at.  For char devices this will
 	 * always be in the class_dev->path.  On block devices, only the main block
@@ -722,7 +732,6 @@ int namedev_name_device(struct udevice *
 	list_for_each_entry(dev, &config_device_list, node) {
 		dbg("process rule");
 		if (match_rule(udev, dev, class_dev, sysfs_device) = 0) {
-
 			/* apply options */
 			if (dev->ignore_device) {
 				info("configured rule in '%s[%i]' applied, '%s' is ignored",
@@ -730,7 +739,7 @@ int namedev_name_device(struct udevice *
 				return -1;
 			}
 			if (dev->ignore_remove) {
-				udev->ignore_remove = dev->ignore_remove;
+				udev->ignore_remove = 1;
 				dbg_parse("remove event should be ignored");
 			}
 			/* apply all_partitions option only at a main block device */
@@ -738,6 +747,10 @@ int namedev_name_device(struct udevice *
 				udev->partitions = dev->partitions;
 				dbg("creation of partition nodes requested");
 			}
+			if (dev->no_hotplug) {
+				udev->no_hotplug = 1;
+				dbg_parse("supress hotplug program execution");
+			}
 
 			/* apply permissions */
 			if (dev->mode != 0000) {
@@ -768,6 +781,17 @@ int namedev_name_device(struct udevice *
 				strfieldcat(udev->symlink, temp);
 			}
 
+			/* collect hotplug programs */
+			if (dev->hotplug[0] != '\0') {
+				char temp[NAME_SIZE];
+
+				dbg("configured rule in '%s[%i]' added hotplug program '%s'",
+				     dev->config_file, dev->config_line, dev->hotplug);
+				strfieldcpy(temp, dev->hotplug);
+				apply_format(udev, temp, sizeof(temp), class_dev, sysfs_device);
+				name_list_add(&udev->hotplug_list, temp, 0);
+			}
+
 			/* rule matches */
 			if (dev->name[0] != '\0') {
 				info("configured rule in '%s[%i]' applied, '%s' becomes '%s'",
@@ -796,6 +820,70 @@ exit:
 		dbg("removing temporary device node");
 		unlink_secure(udev->tmp_node);
 		udev->tmp_node[0] = '\0';
+	}
+
+	return 0;
+}
+
+int rules_get_hotplug(struct udevice *udev)
+{
+	struct config_device *dev;
+	char temp[NAME_SIZE];
+
+	/* look for a matching rule to apply */
+	list_for_each_entry(dev, &config_device_list, node) {
+		dbg("process rule");
+
+		/* skip rules that can't match */
+		if (dev->bus[0] != '\0' || dev->id[0] != '\0' ||
+		    dev->place[0] != '\0' || dev->sysfs_pair[0].file[0] != '\0' ||
+		    dev->program[0] != '\0' || dev->result[0] != '\0' ||
+		    dev->driver[0] != '\0')
+			continue;
+
+		if (dev->action[0] != '\0') {
+			dbg("check for " FIELD_ACTION " dev->action='%s' udev->action='%s'",
+			    dev->action, udev->action);
+			if (strcmp(dev->action, udev->action) != 0) {
+				dbg(FIELD_ACTION " is not matching");
+				continue;
+			}
+			dbg(FIELD_ACTION " matches");
+		}
+
+		if (dev->subsystem[0] != '\0') {
+			dbg("check for " FIELD_SUBSYSTEM " dev->subsystem='%s' udev->subsystem='%s'",
+			    dev->subsystem, udev->subsystem);
+			if (strcmp_pattern(dev->subsystem, udev->subsystem) != 0) {
+				dbg(FIELD_SUBSYSTEM " is not matching");
+				continue;
+			}
+			dbg(FIELD_SUBSYSTEM " matches");
+		}
+
+		if (dev->kernel[0] != '\0') {
+			dbg("check for " FIELD_KERNEL " dev->kernel='%s' class_dev->name='%s'",
+			    dev->kernel, udev->kernel_name);
+			if (strcmp_pattern(dev->kernel, udev->kernel_name) != 0) {
+				dbg(FIELD_KERNEL " is not matching");
+				continue;
+			}
+			dbg(FIELD_KERNEL " matches");
+		}
+
+		/* rule matches, see if hotplug programs should run*/
+		if (dev->no_hotplug) {
+			udev->no_hotplug = 1;
+			dbg_parse("supress hotplug program execution");
+			return -1;
+		}
+
+		if (dev->hotplug[0] = '\0')
+			continue;
+
+		strfieldcpy(temp, dev->hotplug);
+		apply_format(udev, temp, sizeof(temp), NULL, NULL);
+		name_list_add(&udev->hotplug_list, temp, 0);
 	}
 
 	return 0;
=== namedev.h 1.40 vs edited ==--- 1.40/namedev.h	2005-02-21 06:48:12 +01:00
+++ edited/namedev.h	2005-02-21 17:29:11 +01:00
@@ -34,10 +34,10 @@ struct sysfs_class_device;
 #define ID_SIZE			64
 #define PLACE_SIZE		64
 #define DRIVER_SIZE		64
-#define PROGRAM_SIZE		128
 
 #define FIELD_KERNEL		"KERNEL"
 #define FIELD_SUBSYSTEM		"SUBSYSTEM"
+#define FIELD_ACTION		"ACTION"
 #define FIELD_BUS		"BUS"
 #define FIELD_SYSFS		"SYSFS"
 #define FIELD_ID		"ID"
@@ -51,9 +51,11 @@ struct sysfs_class_device;
 #define FIELD_GROUP		"GROUP"
 #define FIELD_MODE		"MODE"
 #define FIELD_OPTIONS		"OPTIONS"
+#define FIELD_HOTPLUG		"HOTPLUG"
 
 #define ATTR_IGNORE_DEVICE	"ignore_device"
 #define ATTR_IGNORE_REMOVE	"ignore_remove"
+#define ATTR_NO_HOTPLUG		"no_hotplug"
 #define ATTR_PARTITIONS		"all_partitions"
 
 #define MAX_SYSFS_PAIRS		5
@@ -70,6 +72,7 @@ struct config_device {
 
 	char kernel[NAME_SIZE];
 	char subsystem[SUBSYSTEM_SIZE];
+	char action[ACTION_SIZE];
 	char bus[BUS_SIZE];
 	char id[ID_SIZE];
 	char place[PLACE_SIZE];
@@ -87,6 +90,9 @@ struct config_device {
 	int partitions;
 	int ignore_device;
 	int ignore_remove;
+	int no_hotplug;
+
+	char hotplug[PROGRAM_SIZE];
 
 	char config_file[NAME_SIZE];
 	int config_line;
@@ -94,9 +100,11 @@ struct config_device {
 
 extern struct list_head config_device_list;
 
-extern int namedev_init(void);
-extern int namedev_name_device(struct udevice *udev, struct sysfs_class_device *class_dev);
-extern void namedev_close(void);
+extern int rules_init(void);
+extern void rules_close(void);
+
+extern int rules_get_name(struct udevice *udev, struct sysfs_class_device *class_dev);
+extern int rules_get_hotplug(struct udevice *udev);
 
 extern void dump_config_dev(struct config_device *dev);
 extern void dump_config_dev_list(void);
=== namedev_parse.c 1.51 vs edited ==--- 1.51/namedev_parse.c	2005-02-21 06:05:51 +01:00
+++ edited/namedev_parse.c	2005-02-21 17:29:12 +01:00
@@ -98,7 +98,7 @@ static char *get_key_attribute(char *str
 	return NULL;
 }
 
-static int namedev_parse(const char *filename, void *data)
+static int rules_parse(const char *filename, void *data)
 {
 	char line[LINE_SIZE];
 	char *bufline;
@@ -183,6 +183,12 @@ static int namedev_parse(const char *fil
 				continue;
 			}
 
+			if (strcasecmp(temp2, FIELD_ACTION) = 0) {
+				strfieldcpy(dev.action, temp3);
+				valid = 1;
+				continue;
+			}
+
 			if (strcasecmp(temp2, FIELD_BUS) = 0) {
 				strfieldcpy(dev.bus, temp3);
 				valid = 1;
@@ -304,6 +310,16 @@ static int namedev_parse(const char *fil
 					dbg_parse("creation of partition nodes requested");
 					dev.partitions = DEFAULT_PARTITIONS_COUNT;
 				}
+				if (strstr(temp3, ATTR_NO_HOTPLUG) != NULL) {
+					dbg_parse("execution of hotplug programs supressed");
+					dev.no_hotplug = 1;
+				}
+				valid = 1;
+				continue;
+			}
+
+			if (strcasecmp(temp2, FIELD_HOTPLUG) = 0) {
+				strfieldcpy(dev.hotplug, temp3);
 				valid = 1;
 				continue;
 			}
@@ -345,7 +361,7 @@ error:
 	return retval;
 }
 
-int namedev_init(void)
+int rules_init(void)
 {
 	struct stat stats;
 	int retval;
@@ -354,14 +370,14 @@ int namedev_init(void)
 		return -1;
 
 	if ((stats.st_mode & S_IFMT) != S_IFDIR)
-		retval = namedev_parse(udev_rules_filename, NULL);
+		retval = rules_parse(udev_rules_filename, NULL);
 	else
-		retval = call_foreach_file(namedev_parse, udev_rules_filename, RULEFILE_SUFFIX, NULL);
+		retval = call_foreach_file(rules_parse, udev_rules_filename, RULEFILE_SUFFIX, NULL);
 
 	return retval;
 }
 
-void namedev_close(void)
+void rules_close(void)
 {
 	struct config_device *dev;
 
=== udev.8.in 1.78 vs edited ==--- 1.78/udev.8.in	2005-02-13 22:03:06 +01:00
+++ edited/udev.8.in	2005-02-21 17:29:12 +01:00
@@ -98,9 +98,8 @@ Every rule consists of a list of comma s
 .sp
 where fields are:
 .TP
-.B BUS
-Match the bus type of the device.
-(The sysfs device bus must be able to be determined by a "device" symlink.)
+.B ACTION
+Match the event type.
 .TP
 .B KERNEL
 Match the kernel device name.
@@ -108,9 +107,16 @@ Match the kernel device name.
 .B SUBSYSTEM
 Match the kernel subsystem name.
 .TP
+.B ACTION
+Match the event action string.
+.TP
 .B DRIVER
 Match the kernel driver name.
 .TP
+.B BUS
+Match the bus type of the device.
+(The sysfs device bus must be able to be determined by a "device" symlink.)
+.TP
 .B ID
 Match the device number on the bus, like PCI bus id.
 .TP
@@ -178,6 +184,10 @@ This may be useful for removable media d
 change.
 .sp
 Multiple attributes may be separated by comma.
+.TP
+.B HOTPLUG
+programs to be added to a list to be excuted after node creation or removal.
+Identical keys will only be added once.
 .P
 .RB "The " NAME ", " SYMLINK ", " PROGRAM ", " OWNER " and " GROUP
 fields support simple printf-like string substitutions:
@@ -301,15 +311,7 @@ is set if udev is configured to use the 
 want to follow that setting.
 .B DEVNAME
 is exported to make the name of the created node, or the name the network
-device is renamed to, available to the executed program. The programs in every
-directory are sorted in lexical order, while the directories are searched in
-the following order:
-.sp
-.nf
-/etc/dev.d/$(DEVNAME)/*.dev
-/etc/dev.d/$(SUBSYSTEM)/*.dev
-/etc/dev.d/default/*.dev
-.fi
+device is renamed to, available to the executed program.
 .SH "ENVIRONMENT"
 .P
 The following variables are read from the environment:
@@ -330,20 +332,11 @@ Overrides the default location of the
 .B udev
 config file.
 .TP
-.B UDEV_NO_DEVD
-The default behavior of
-.B udev
-is to execute programs in the
-.I /etc/dev.d/
-directory after device handling. If set,
-.B udev
-will skip this step.
 .SH "FILES"
 .nf
 /sbin/udev                           udev program
 /etc/udev/*                          udev config files
 /etc/hotplug.d/default/udev.hotplug  hotplug symlink to udev program
-/etc/dev.d/*                         programs invoked by udev
 .fi
 .SH "SEE ALSO"
 .BR udevinfo (8),
=== udev.c 1.104 vs edited ==--- 1.104/udev.c	2005-02-21 07:01:52 +01:00
+++ edited/udev.c	2005-02-21 18:19:33 +01:00
@@ -136,7 +136,7 @@ int main(int argc, char *argv[], char *e
 		/* disable all logging, as it's much too slow on some facilities */
 		udev_log = 0;
 
-		namedev_init();
+		rules_init();
 		retval = udev_start();
 		goto exit;
 	}
@@ -170,58 +170,72 @@ int main(int argc, char *argv[], char *e
 	if (udev_log)
 		setenv("UDEV_LOG", "1", 1);
 
-	udev_init_device(&udev, devpath, subsystem);
+	udev_init_device(&udev, devpath, subsystem, action);
 
 	if (udev.type = BLOCK || udev.type = CLASS || udev.type = NET) {
-		if (strcmp(action, "add") = 0) {
-			/* wait for sysfs and possibly add node */
-			dbg("udev add");
+		rules_init();
 
-			/* skip subsystems without "dev", but handle net devices */
-			if (udev.type != NET && subsystem_expect_no_dev(udev.subsystem)) {
-				dbg("don't care about '%s' devices", udev.subsystem);
-				goto hotplug;
-			}
+		if (strcmp(udev.action, "add") = 0) {
+			dbg("udev add");
 
+			/* wait for sysfs to populate */
 			snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, udev.devpath);
+			path[SYSFS_PATH_MAX-1] = '\0';
 			class_dev = wait_class_device_open(path);
 			if (class_dev = NULL) {
 				dbg ("open class device failed");
 				goto hotplug;
 			}
 			dbg("opened class_dev->name='%s'", class_dev->name);
-
 			wait_for_class_device(class_dev, &error);
 
-			/* init rules */
-			namedev_init();
+			/* create a node for devices with a "dev" file */
+			if (!subsystem_expect_no_dev(udev.subsystem)) {
+				udev.devt = get_devt(class_dev);
+				if (!udev.devt) {
+					dbg("dev file expected, but not found");
+					sysfs_close_class_device(class_dev);
+					goto hotplug;
+				}
+			}
 
-			/* name, create node, store in db */
-			retval = udev_add_device(&udev, class_dev);
+			/* name device or possibly ignore event */
+			if (rules_get_name(&udev, class_dev) != 0) {
+				sysfs_close_class_device(class_dev);
+				goto hotplug;
+			}
 
+			udev_add_device(&udev, class_dev);
 			sysfs_close_class_device(class_dev);
-		} else if (strcmp(action, "remove") = 0) {
-			/* possibly remove a node */
+
+		} else if (strcmp(udev.action, "remove") = 0) {
 			dbg("udev remove");
 
 			/* skip subsystems without "dev" */
 			if (subsystem_expect_no_dev(udev.subsystem)) {
-				dbg("don't care about '%s' devices", udev.subsystem);
+				dbg("'%s' devices don't have device nodes", udev.subsystem);
 				goto hotplug;
 			}
 
+			/* get hotplug scripts or possibly ignore event */
+			if (rules_get_hotplug(&udev) != 0)
+				goto hotplug;
+
 			/* get node from db, remove db-entry, delete created node */
 			retval = udev_remove_device(&udev);
 		}
 
-		/* run dev.d/ scripts if we created/deleted a node or changed a netif name */
-		if (udev.devname[0] != '\0') {
+		/* execute hotplug scripts */
+		if (udev.devname[0] != '\0' && !udev.no_hotplug) {
+			struct name_entry *name_loop;
+
 			setenv("DEVNAME", udev.devname, 1);
-			if (udev_dev_d)
-				udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX);
+			list_for_each_entry(name_loop, &udev.hotplug_list, node)
+				execute_command(&udev, name_loop->name);
 		}
+
 	} else if (udev.type = PHYSDEV) {
-		if (strcmp(action, "add") = 0) {
+		if (strcmp(udev.action, "add") = 0) {
 			/* wait for sysfs */
 			dbg("devices add");
 
@@ -236,12 +250,11 @@ int main(int argc, char *argv[], char *e
 			wait_for_devices_device(devices_dev, &error);
 
 			sysfs_close_device(devices_dev);
-		} else if (strcmp(action, "remove") = 0) {
+		} else if (strcmp(action, "remove") = 0)
 			dbg("devices remove");
-		}
-	} else {
-		dbg("unhandled");
-	}
+
+	} else
+		dbg("don't care");
 
 hotplug:
 	if (udev_hotplug_d && managed_event)
=== udev.h 1.87 vs edited ==--- 1.87/udev.h	2005-02-21 06:48:12 +01:00
+++ edited/udev.h	2005-02-21 17:29:12 +01:00
@@ -4,6 +4,7 @@
  * Userspace devfs
  *
  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2003-2005 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
@@ -31,7 +32,9 @@
 #define ALARM_TIMEOUT			120
 #define COMMENT_CHARACTER		'#'
 
+#define LINE_SIZE			512
 #define NAME_SIZE			256
+#define PROGRAM_SIZE			128
 #define USER_SIZE			32
 
 #define ACTION_SIZE			32
@@ -39,16 +42,16 @@
 #define SUBSYSTEM_SIZE			32
 #define SEQNUM_SIZE			32
 
-#define LINE_SIZE			512
-
-#define DEVD_DIR			"/etc/dev.d"
-#define DEVD_SUFFIX			".dev"
-
 #define HOTPLUGD_DIR			"/etc/hotplug.d"
 #define HOTPLUG_SUFFIX			".hotplug"
 
 #define DEFAULT_PARTITIONS_COUNT	15
 
+struct name_entry {
+	struct list_head node;
+	char name[NAME_SIZE];
+};
+
 enum device_type {
 	UNKNOWN,
 	CLASS,
@@ -58,22 +61,27 @@ enum device_type {
 };
 
 struct udevice {
+	char action[ACTION_SIZE];
 	char devpath[DEVPATH_SIZE];
 	char subsystem[SUBSYSTEM_SIZE];
 
 	char name[NAME_SIZE];
+	char devname[NAME_SIZE];
 	char symlink[NAME_SIZE];
 	char owner[USER_SIZE];
 	char group[USER_SIZE];
 	mode_t mode;
-	char type;
+	enum device_type type ;
 	dev_t devt;
 
-	char devname[NAME_SIZE];
 	char tmp_node[NAME_SIZE];
 	int partitions;
 	int ignore_remove;
-	int config_line;
+	int no_hotplug;
+
+	struct list_head hotplug_list;
+
+	unsigned int config_line;
 	char config_file[NAME_SIZE];
 	char bus_id[SYSFS_NAME_LEN];
 	char program_result[NAME_SIZE];
@@ -95,7 +103,6 @@ extern char udev_db_path[PATH_MAX+NAME_M
 extern char udev_config_filename[PATH_MAX+NAME_MAX];
 extern char udev_rules_filename[PATH_MAX+NAME_MAX];
 extern int udev_log;
-extern int udev_dev_d;
 extern int udev_hotplug_d;
 
 #endif
=== udev_add.c 1.95 vs edited ==--- 1.95/udev_add.c	2005-02-21 05:45:03 +01:00
+++ edited/udev_add.c	2005-02-21 17:29:12 +01:00
@@ -39,7 +39,6 @@
 #include "libsysfs/sysfs/libsysfs.h"
 #include "udev.h"
 #include "udev_utils.h"
-#include "udev_sysfs.h"
 #include "udev_version.h"
 #include "logging.h"
 #include "namedev.h"
@@ -272,17 +271,6 @@ int udev_add_device(struct udevice *udev
 {
 	char *pos;
 	int retval = 0;
-
-	if (udev->type = BLOCK || udev->type = CLASS) {
-		udev->devt = get_devt(class_dev);
-		if (!udev->devt) {
-			dbg("no dev-file found, do nothing");
-			return 0;
-		}
-	}
-
-	if (namedev_name_device(udev, class_dev) != 0)
-		return 0;
 
 	dbg("adding name='%s'", udev->name);
 
=== udev_config.c 1.31 vs edited ==--- 1.31/udev_config.c	2005-01-04 21:37:01 +01:00
+++ edited/udev_config.c	2005-02-21 17:29:12 +01:00
@@ -46,7 +46,6 @@ char udev_db_path[PATH_MAX+NAME_MAX];
 char udev_rules_filename[PATH_MAX+NAME_MAX];
 char udev_config_filename[PATH_MAX+NAME_MAX];
 int udev_log;
-int udev_dev_d;
 int udev_hotplug_d;
 
 
@@ -72,11 +71,6 @@ static void init_variables(void)
 	strcpy(udev_rules_filename, UDEV_RULES_FILE);
 
 	udev_log = string_is_true(UDEV_LOG_DEFAULT);
-
-	udev_dev_d = 1;
-	env = getenv("UDEV_NO_DEVD");
-	if (env && string_is_true(env))
-		udev_dev_d = 0;
 
 	udev_hotplug_d = 1;
 	env = getenv("UDEV_NO_HOTPLUGD");
=== udev_start.c 1.29 vs edited ==--- 1.29/udev_start.c	2005-02-10 10:26:09 +01:00
+++ edited/udev_start.c	2005-02-21 18:24:41 +01:00
@@ -35,6 +35,8 @@
 #include <unistd.h>
 
 #include "libsysfs/sysfs/libsysfs.h"
+#include "namedev.h"
+#include "udev_sysfs.h"
 #include "logging.h"
 #include "udev_utils.h"
 #include "list.h"
@@ -96,7 +98,7 @@ static int add_device(const char *path, 
 
 	devpath = &path[strlen(sysfs_path)];
 
-	/* set environment for callouts and dev.d/ */
+	/* set environment for callouts and hotplug programs */
 	setenv("DEVPATH", devpath, 1);
 	setenv("SUBSYSTEM", subsystem, 1);
 
@@ -108,15 +110,32 @@ static int add_device(const char *path, 
 		return -ENODEV;
 	}
 
-	udev_init_device(&udev, devpath, subsystem);
+	udev_init_device(&udev, devpath, subsystem, "add");
+
+	/* create a node for devices with a "dev" file */
+	if (!subsystem_expect_no_dev(udev.subsystem)) {
+		udev.devt = get_devt(class_dev);
+		if (!udev.devt) {
+			dbg("dev file expected, but not found");
+			goto exit;
+		}
+	}
+
+	if (rules_get_name(&udev, class_dev) != 0)
+		goto exit;
+
 	udev_add_device(&udev, class_dev);
 
-	/* run dev.d/ scripts if we created a node or changed a netif name */
-	if (udev_dev_d && udev.devname[0] != '\0') {
+	/* execute hotplug scripts */
+	if (udev.devname[0] != '\0' && !udev.no_hotplug) {
+		struct name_entry *name_loop;
+
 		setenv("DEVNAME", udev.devname, 1);
-		udev_multiplex_directory(&udev, DEVD_DIR, DEVD_SUFFIX);
+		list_for_each_entry(name_loop, &udev.hotplug_list, node)
+			execute_command(&udev, name_loop->name);
 	}
 
+exit:
 	sysfs_close_class_device(class_dev);
 
 	return 0;
@@ -280,7 +299,7 @@ static void udev_scan_class(void)
 
 int udev_start(void)
 {
-	/* set environment for callouts and dev.d/ */
+	/* set environment for callouts and hotplug programs */
 	setenv("ACTION", "add", 1);
 	setenv("UDEV_START", "1", 1);
 
=== udev_utils.c 1.32 vs edited ==--- 1.32/udev_utils.c	2005-02-21 07:01:52 +01:00
+++ edited/udev_utils.c	2005-02-21 17:29:13 +01:00
@@ -29,6 +29,7 @@
 #include <dirent.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
+#include <sys/wait.h>
 #include <sys/utsname.h>
 
 #include "udev.h"
@@ -37,11 +38,12 @@
 #include "list.h"
 
 
-int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem)
+int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem, const char *action)
 {
 	char *pos;
 
 	memset(udev, 0x00, sizeof(struct udevice));
+	INIT_LIST_HEAD(&udev->hotplug_list);
 
 	if (devpath) {
 		strfieldcpy(udev->devpath, devpath);
@@ -49,6 +51,8 @@ int udev_init_device(struct udevice *ude
 	}
 	if (subsystem)
 		strfieldcpy(udev->subsystem, subsystem);
+	if (action)
+		strfieldcpy(udev->action, action);
 
 	if (strcmp(udev->subsystem, "block") = 0)
 		udev->type = BLOCK;
@@ -262,13 +266,7 @@ void no_trailing_slash(char *path)
 		path[--len] = '\0';
 }
 
-struct name_entry {
-	struct list_head node;
-	char name[NAME_SIZE];
-};
-
-/* sort files in lexical order */
-static int name_list_add(struct list_head *name_list, const char *name, int sort)
+int name_list_add(struct list_head *name_list, const char *name, int sort)
 {
 	struct name_entry *loop_name;
 	struct name_entry *new_name;
@@ -291,6 +289,69 @@ static int name_list_add(struct list_hea
 
 	strfieldcpy(new_name->name, name);
 	list_add_tail(&new_name->node, &loop_name->node);
+
+	return 0;
+}
+
+int execute_command(struct udevice *udev, const char *command)
+{
+	int retval;
+	pid_t pid;
+	char arg[PROGRAM_SIZE];
+	char *argv[(PROGRAM_SIZE / 2) + 1];
+	char *pos;
+	int fd;
+	int i;
+
+	strfieldcpy(arg, command);
+	i = 0;
+	if (strchr(command, ' ')) {
+		pos = arg;
+		while (pos != NULL) {
+			if (pos[0] = '\'') {
+				/* don't separate if in apostrophes */
+				pos++;
+				argv[i] = strsep(&pos, "\'");
+				while (pos && pos[0] = ' ')
+					pos++;
+			} else {
+				argv[i] = strsep(&pos, " ");
+			}
+			dbg("arg[%i] '%s'", i, argv[i]);
+			i++;
+		}
+		argv[i] =  NULL;
+		dbg("execute '%s' with parsed arguments", arg);
+	} else {
+		argv[0] = arg;
+		argv[1] = udev->subsystem;
+		argv[2] = NULL;
+		dbg("execute '%s' with subsystem '%s' argument", arg, argv[1]);
+	}
+
+	pid = fork();
+	switch (pid) {
+	case 0:
+		/* child */
+		fd = open("/dev/null", O_RDWR);
+		if ( fd >= 0) {
+			dup2(fd, STDOUT_FILENO);
+			dup2(fd, STDIN_FILENO);
+			dup2(fd, STDERR_FILENO);
+		}
+		close(fd);
+
+		retval = execv(arg, argv);
+		dbg("exec of child failed");
+		_exit(1);
+	case -1:
+		dbg("fork of child failed");
+		break;
+		return -1;
+	default:
+		waitpid(pid, NULL, 0);
+	}
+
 	return 0;
 }
 
=== udev_utils.h 1.23 vs edited ==--- 1.23/udev_utils.h	2005-02-21 06:48:12 +01:00
+++ edited/udev_utils.h	2005-02-21 17:29:13 +01:00
@@ -76,7 +76,7 @@ do { \
 # define asmlinkage	/* nothing */
 #endif
 
-extern int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem);
+extern int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem, const char *action);
 extern int kernel_release_satisfactory(unsigned int version, unsigned int patchlevel, unsigned int sublevel);
 extern int create_path(const char *path);
 extern int parse_get_pair(char **orig_string, char **left, char **right);
@@ -86,6 +86,8 @@ extern void file_unmap(char *buf, size_t
 extern size_t buf_get_line(const char *buf, size_t buflen, size_t cur);
 extern void no_trailing_slash(char *path);
 typedef int (*file_fnct_t)(const char *filename, void *data);
+extern int execute_command(struct udevice *udev, const char *command);
+extern int name_list_add(struct list_head *name_list, const char *name, int sort);
 extern int  call_foreach_file(file_fnct_t fnct, const char *dirname,
 			      const char *suffix, void *data);
 
=== udevtest.c 1.24 vs edited ==--- 1.24/udevtest.c	2005-02-21 05:45:04 +01:00
+++ edited/udevtest.c	2005-02-21 17:29:13 +01:00
@@ -85,13 +85,13 @@ int main(int argc, char *argv[], char *e
 	info("looking at '%s'", devpath);
 
 	/* initialize the naming deamon */
-	namedev_init();
+	rules_init();
 
 	if (argc = 3)
 		subsystem = argv[2];
 
 	/* fill in values and test_run flag*/
-	udev_init_device(&udev, devpath, subsystem);
+	udev_init_device(&udev, devpath, subsystem, "add");
 
 	/* skip subsystems without "dev", but handle net devices */
 	if (udev.type != NET && subsystem_expect_no_dev(udev.subsystem)) {



-------------------------------------------------------
SF email is sponsored by - The IT Product Guide
Read honest & candid reviews on hundreds of IT Products from real users.
Discover which products truly live up to the hype. Start reading now.
http://ads.osdn.com/?ad_ide95&alloc_id\x14396&op=click
_______________________________________________
Linux-hotplug-devel mailing list  http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2005-02-26  2:22 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-21 18:12 replace dev.d/ with a rule based program execution Kay Sievers
2005-02-22  8:08 ` Hannes Reinecke
2005-02-22 17:53 ` Harald Hoyer
2005-02-23  1:08 ` Marco d'Itri
2005-02-24 20:15 ` David Zeuthen
2005-02-24 20:34 ` Kay Sievers
2005-02-24 20:45 ` David Zeuthen
2005-02-24 21:04 ` Kay Sievers
2005-02-24 21:52 ` Kay Sievers
2005-02-24 22:03 ` David Zeuthen
2005-02-25 23:26 ` Greg KH
2005-02-26  0:28 ` Kay Sievers
2005-02-26  0:57 ` Marco d'Itri
2005-02-26  1:04 ` Kay Sievers
2005-02-26  1:06 ` Marco d'Itri
2005-02-26  2:22 ` Kay Sievers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).