linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Kay Sievers <kay.sievers@vrfy.org>
To: linux-hotplug@vger.kernel.org
Subject: Re: The Next Generation
Date: Mon, 28 Feb 2005 18:41:41 +0000	[thread overview]
Message-ID: <20050228184141.GA24961@vrfy.org> (raw)
In-Reply-To: <20050217190941.GA1561@vrfy.org>

On Fri, Feb 25, 2005 at 03:17:14PM -0800, Greg KH wrote:
> On Thu, Feb 17, 2005 at 08:09:41PM +0100, Kay Sievers wrote:
> > For that reason, we should get rid of all the just too simple
> > brute-force logic in /etc/hotplug/*, /etc/hotplug.d/ and /etc/dev.d/, which
> > requires scripts to check if they are called for the right device.
> 
> No, we can't break backward compatiblity like that.  We need to always
> support the /etc/hotplug.d/ way, as we've already told too many people
> they can rely on that always working.

...

> And /etc/dev.d/ is also a good thing to have.

Ok, ok, here is a more intelligent replacement. :)

I've changes the HOTPLUG key to be able to read a whole subdirectory
with a wildcard instead of only one file. The following three rules will
emulate the dev.d/ directory handling we currently have compiled in:

  HOTPLUG="/etc/dev.d/%D/*.dev"
  HOTPLUG="/etc/dev.d/%S/*.dev"
  HOTPLUG="/etc/dev.d/default/*.dev"

The nice thing with this approach is that a program called specified twice
will only added once to the list of programs to be executed.

We can ship these rules by default which remains the needed backwards
compatibility, but the user can remove these rules and udev does not need
to search for anything outside the specified rules.

How does that sound now?

Thanks,
Kay

=== namedev.c 1.189 vs edited ==--- 1.189/namedev.c	2005-02-24 12:13:24 +01:00
+++ edited/namedev.c	2005-02-28 17:54:21 +01:00
@@ -168,8 +168,7 @@ static int find_free_number(struct udevi
 }
 
 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
-			 struct sysfs_class_device *class_dev,
-			 struct sysfs_device *sysfs_device)
+			 struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device)
 {
 	char temp[NAME_SIZE];
 	char temp2[NAME_SIZE];
@@ -203,26 +202,18 @@ static void apply_format(struct udevice 
 
 		switch (c) {
 		case 'p':
-			if (strlen(udev->devpath) = 0)
-				break;
 			strfieldcatmax(string, udev->devpath, maxsize);
 			dbg("substitute kernel name '%s'", udev->kernel_name);
 			break;
 		case 'b':
-			if (strlen(udev->bus_id) = 0)
-				break;
 			strfieldcatmax(string, udev->bus_id, maxsize);
 			dbg("substitute bus_id '%s'", udev->bus_id);
 			break;
 		case 'k':
-			if (strlen(udev->kernel_name) = 0)
-				break;
 			strfieldcatmax(string, udev->kernel_name, maxsize);
 			dbg("substitute kernel name '%s'", udev->kernel_name);
 			break;
 		case 'n':
-			if (strlen(udev->kernel_number) = 0)
-				break;
 			strfieldcatmax(string, udev->kernel_number, maxsize);
 			dbg("substitute kernel number '%s'", udev->kernel_number);
 				break;
@@ -235,7 +226,7 @@ static void apply_format(struct udevice 
 			dbg("substitute major number '%u'", major(udev->devt));
 			break;
 		case 'c':
-			if (strlen(udev->program_result) = 0)
+			if (udev->program_result[0] = '\0')
 				break;
 			/* get part part of the result string */
 			i = 0;
@@ -326,6 +317,14 @@ static void apply_format(struct udevice 
 			strfieldcatmax(string, udev->tmp_node, maxsize);
 			dbg("substitute temporary device node name '%s'", udev->tmp_node);
 			break;
+		case 'S':
+			strfieldcatmax(string, udev->subsystem, maxsize);
+			dbg("substitute subsystem '%s'", udev->subsystem);
+			break;
+		case 'D':
+			strfieldcatmax(string, udev->name, maxsize);
+			dbg("substitute node name '%s'", udev->name);
+			break;
 		case 'r':
 			strfieldcatmax(string, udev_root, maxsize);
 			dbg("substitute udev_root '%s'", udev_root);
@@ -571,7 +570,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 +587,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 +698,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,6 +731,10 @@ 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) {
+			if (dev->name[0] != '\0' && udev->name[0] != '\0') {
+				dbg("node name already set, rule ignored");
+				continue;
+			}
 
 			/* apply options */
 			if (dev->ignore_device) {
@@ -730,7 +743,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 +751,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,7 +785,14 @@ int namedev_name_device(struct udevice *
 				strfieldcat(udev->symlink, temp);
 			}
 
-			/* rule matches */
+			/* collect hotplug programs */
+			if (dev->hotplug[0] != '\0') {
+				dbg("configured rule in '%s[%i]' added hotplug program '%s'",
+				     dev->config_file, dev->config_line, dev->hotplug);
+				name_list_add(&udev->hotplug_list, dev->hotplug, 0);
+			}
+
+			/* set the name of the node */
 			if (dev->name[0] != '\0') {
 				info("configured rule in '%s[%i]' applied, '%s' becomes '%s'",
 				     dev->config_file, dev->config_line, udev->kernel_name, dev->name);
@@ -781,21 +805,136 @@ int namedev_name_device(struct udevice *
 				if (udev->type != NET)
 					dbg("name, '%s' is going to have owner='%s', group='%s', mode=%#o partitions=%i",
 					    udev->name, udev->owner, udev->group, udev->mode, udev->partitions);
+			}
 
-				goto exit;
+			if (dev->last_rule) {
+				dbg("last rule key found, processing will stop at this rule");
+				break;
 			}
 		}
 	}
 
 	/* no rule matched, so we use the kernel name */
-	strfieldcpy(udev->name, udev->kernel_name);
-	dbg("no rule found, use kernel name '%s'", udev->name);
+	if (udev->name[0] = '\0') {
+		strfieldcpy(udev->name, udev->kernel_name);
+		dbg("no rule found, use kernel name '%s'", udev->name);
+	}
 
-exit:
 	if (udev->tmp_node[0] != '\0') {
 		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;
+
+	/* look for a matching rule to apply */
+	list_for_each_entry(dev, &config_device_list, node) {
+		dbg("process rule");
+
+		if (dev->hotplug[0] = '\0')
+			continue;
+
+		/* 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;
+		}
+
+		name_list_add(&udev->hotplug_list, dev->hotplug, 0);
+	}
+
+	return 0;
+}
+
+static int hotplug_list_insert(struct udevice *udev, const char *name)
+{
+	char temp[NAME_SIZE];
+
+	strfieldcpy(temp, name);
+	apply_format(udev, temp, NAME_SIZE, NULL, NULL);
+	dbg("applied format '%s'",  temp);
+	name_list_add(&udev->hotplug_list, temp, 0);
+
+	return 0;
+}
+
+int rules_expand_hotplug_list(struct udevice *udev)
+{
+	struct name_entry *name_loop;
+	struct name_entry *name_tmp;
+
+	list_for_each_entry_safe(name_loop, name_tmp, &udev->hotplug_list, node) {
+		apply_format(udev, name_loop->name, NAME_SIZE, NULL, NULL);
+		dbg("applied format '%s'",  name_loop->name);
+
+		/* allow wildcard to add all files with a specific suffix */
+		if (strchr(name_loop->name, '*')) {
+			char directory[NAME_SIZE];
+			char *pos;
+
+			strfieldcpy(directory, name_loop->name);
+			pos = strrchr(directory, '/');
+			if (pos = NULL)
+				return -1;
+			pos[0] = '\0';
+			pos++;
+
+			if (strchr(pos, '*') = NULL)
+				continue;
+
+			pos = strrchr(pos, '.');
+			if (pos = NULL)
+				continue;
+
+			dbg("remove '%s' as command, instead search for '%s'-suffix in '%s'",
+			    name_loop->name, pos, directory);
+			list_del(&name_loop->node);
+			call_foreach_file(hotplug_list_insert, udev, directory, pos);
+		}
 	}
 
 	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-28 17:32:04 +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,10 +51,13 @@ 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_PARTITIONS		"all_partitions"
+#define OPTION_LAST_RULE	"last_rule"
+#define OPTION_IGNORE_DEVICE	"ignore_device"
+#define OPTION_IGNORE_REMOVE	"ignore_remove"
+#define OPTION_NO_HOTPLUG	"no_hotplug"
+#define OPTION_ALL_PARTITIONS	"all_partitions"
 
 #define MAX_SYSFS_PAIRS		5
 
@@ -70,6 +73,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 +91,10 @@ struct config_device {
 	int partitions;
 	int ignore_device;
 	int ignore_remove;
+	int no_hotplug;
+	int last_rule;
+
+	char hotplug[PROGRAM_SIZE];
 
 	char config_file[NAME_SIZE];
 	int config_line;
@@ -94,9 +102,12 @@ 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 int rules_expand_hotplug_list(struct udevice *udev);
 
 extern void dump_config_dev(struct config_device *dev);
 extern void dump_config_dev_list(void);
=== namedev_parse.c 1.52 vs edited ==--- 1.52/namedev_parse.c	2005-02-25 18:52:03 +01:00
+++ edited/namedev_parse.c	2005-02-28 12:39:46 +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(struct udevice *udev, const char *filename)
 {
 	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;
@@ -250,11 +256,11 @@ static int namedev_parse(const char *fil
 				attr = get_key_attribute(temp2 + sizeof(FIELD_NAME)-1);
 				/* FIXME: remove old style options and make OPTIONS= mandatory */
 				if (attr != NULL) {
-					if (strstr(attr, ATTR_PARTITIONS) != NULL) {
+					if (strstr(attr, OPTION_ALL_PARTITIONS) != NULL) {
 						dbg_parse("creation of partition nodes requested");
 						dev.partitions = DEFAULT_PARTITIONS_COUNT;
 					}
-					if (strstr(attr, ATTR_IGNORE_REMOVE) != NULL) {
+					if (strstr(attr, OPTION_IGNORE_REMOVE) != NULL) {
 						dbg_parse("remove event should be ignored");
 						dev.ignore_remove = 1;
 					}
@@ -292,18 +298,32 @@ static int namedev_parse(const char *fil
 			}
 
 			if (strcasecmp(temp2, FIELD_OPTIONS) = 0) {
-				if (strstr(temp3, ATTR_IGNORE_DEVICE) != NULL) {
+				if (strstr(temp3, OPTION_LAST_RULE) != NULL) {
+					dbg_parse("last rule to be applied for that device");
+					dev.last_rule = 1;
+				}
+				if (strstr(temp3, OPTION_IGNORE_DEVICE) != NULL) {
 					dbg_parse("device should be ignored");
 					dev.ignore_device = 1;
 				}
-				if (strstr(temp3, ATTR_IGNORE_REMOVE) != NULL) {
+				if (strstr(temp3, OPTION_IGNORE_REMOVE) != NULL) {
 					dbg_parse("remove event should be ignored");
 					dev.ignore_remove = 1;
 				}
-				if (strstr(temp3, ATTR_PARTITIONS) != NULL) {
+				if (strstr(temp3, OPTION_ALL_PARTITIONS) != NULL) {
 					dbg_parse("creation of partition nodes requested");
 					dev.partitions = DEFAULT_PARTITIONS_COUNT;
 				}
+				if (strstr(temp3, OPTION_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 +365,7 @@ error:
 	return retval;
 }
 
-int namedev_init(void)
+int rules_init(void)
 {
 	struct stat stats;
 	int retval;
@@ -354,14 +374,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(NULL, udev_rules_filename);
 	else
-		retval = call_foreach_file(namedev_parse, udev_rules_filename, RULEFILE_SUFFIX, NULL);
+		retval = call_foreach_file(rules_parse, NULL, udev_rules_filename, RULEFILE_SUFFIX);
 
 	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-28 05:38:24 +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:
@@ -219,8 +229,14 @@ all remaining parts of the result string
 The name of a created temporary device node to provide access to the
 device from a external program.
 .TP
+.B %S
+The name of the subsystem.
+.TP
+.B %D
+The name of the device node.
+.TP
 .B %P
-The node name of the parent device.
+The name of the parent device node.
 .TP
 .BI %s{ filename }
 The content of a sysfs attribute.
@@ -301,15 +317,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 +338,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-28 17:40:45 +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,74 @@ 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);
+			rules_expand_hotplug_list(&udev);
+
+			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 +252,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-28 12:38:48 +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,28 @@ 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;
+	int last_rule;
+
+	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 +104,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-28 04:17:44 +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-28 04:17:44 +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_multiplex.c 1.25 vs edited ==--- 1.25/udev_multiplex.c	2004-11-25 01:55:54 +01:00
+++ edited/udev_multiplex.c	2005-02-28 04:27:29 +01:00
@@ -31,11 +31,10 @@
 #include "udev_utils.h"
 #include "logging.h"
 
-static int run_program(const char *filename, void *data)
+static int run_program(struct udevice *udev, const char *filename)
 {
 	pid_t pid;
 	int fd;
-	struct udevice *udev = data;
 
 	dbg("running %s", filename);
 
@@ -89,7 +88,7 @@ void udev_multiplex_directory(struct ude
 			if (strcmp(devname, udev->subsystem) != 0) {
 				snprintf(dirname, PATH_MAX, "%s/%s", basedir, devname);
 				dirname[PATH_MAX-1] = '\0';
-				call_foreach_file(run_program, dirname, suffix, udev);
+				call_foreach_file(run_program, udev, dirname, suffix);
 			}
 
 			temp[0] = '/';
@@ -101,16 +100,16 @@ void udev_multiplex_directory(struct ude
 	if (udev->name[0] != '\0') {
 		snprintf(dirname, PATH_MAX, "%s/%s", basedir, udev->name);
 		dirname[PATH_MAX-1] = '\0';
-		call_foreach_file(run_program, dirname, suffix, udev);
+		call_foreach_file(run_program, udev, dirname, suffix);
 	}
 
 	if (udev->subsystem[0] != '\0') {
 		snprintf(dirname, PATH_MAX, "%s/%s", basedir, udev->subsystem);
 		dirname[PATH_MAX-1] = '\0';
-		call_foreach_file(run_program, dirname, suffix, udev);
+		call_foreach_file(run_program, udev, dirname, suffix);
 	}
 
 	snprintf(dirname, PATH_MAX, "%s/default", basedir);
 	dirname[PATH_MAX-1] = '\0';
-	call_foreach_file(run_program, dirname, suffix, udev);
+	call_foreach_file(run_program, udev, dirname, suffix);
 }
=== 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-28 04:17:44 +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-28 04:40:45 +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,11 +289,75 @@ 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;
 }
 
 /* calls function for every file found in specified directory */
-int call_foreach_file(file_fnct_t fnct, const char *dirname, const char *suffix, void *data)
+int call_foreach_file(int (*handler_function)(struct udevice *udev, const char *string),
+		      struct udevice *udev, const char *dirname, const char *suffix)
 {
 	struct dirent *ent;
 	DIR *dir;
@@ -338,7 +400,7 @@ int call_foreach_file(file_fnct_t fnct, 
 		snprintf(filename, NAME_SIZE, "%s/%s", dirname, loop_file->name);
 		filename[NAME_SIZE-1] = '\0';
 
-		fnct(filename, data);
+		handler_function(udev, filename);
 
 		list_del(&loop_file->node);
 		free(loop_file);
=== 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-28 04:37:18 +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);
@@ -85,8 +85,10 @@ extern int file_map(const char *filename
 extern void file_unmap(char *buf, size_t bufsize);
 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  call_foreach_file(file_fnct_t fnct, const char *dirname,
-			      const char *suffix, void *data);
+extern int name_list_add(struct list_head *name_list, const char *name, int sort);
+
+extern int execute_command(struct udevice *udev, const char *command);
+extern int call_foreach_file(int (*handler_function)(struct udevice *udev, const char *string),
+			     struct udevice *udev, const char *dirname, const char *suffix);
 
 #endif
=== udevtest.c 1.24 vs edited ==--- 1.24/udevtest.c	2005-02-21 05:45:04 +01:00
+++ edited/udevtest.c	2005-02-28 04:17:44 +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

  parent reply	other threads:[~2005-02-28 18:41 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-02-17 19:09 The Next Generation Kay Sievers
2005-02-17 20:21 ` Marco d'Itri
2005-02-17 20:35 ` Kay Sievers
2005-02-18  5:26 ` Alexander E. Patrakov
2005-02-24 11:29 ` Roman Kagan
2005-02-24 12:26 ` Kay Sievers
2005-02-24 17:51 ` Roman Kagan
2005-02-24 19:37 ` Kay Sievers
2005-02-24 20:39 ` Roman Kagan
2005-02-25 12:54 ` Kevin P. Fleming
2005-02-25 23:17 ` Greg KH
2005-02-25 23:59 ` Marco d'Itri
2005-02-26  0:07 ` Greg KH
2005-02-26  0:18 ` Kay Sievers
2005-02-27 20:13 ` David Brownell
2005-02-27 23:34 ` Kay Sievers
2005-02-28 17:02 ` Roman Kagan
2005-02-28 17:38 ` Kay Sievers
2005-02-28 18:41 ` Kay Sievers [this message]
2005-02-28 19:11 ` Roman Kagan
2005-02-28 19:49 ` Marco d'Itri
2005-02-28 20:37 ` Kay Sievers
2005-02-28 20:42 ` Chris Larson
2005-02-28 20:46 ` Kay Sievers
2005-02-28 20:50 ` Marco d'Itri
2005-02-28 21:01 ` Kay Sievers
2005-02-28 21:14 ` Erik van Konijnenburg
2005-02-28 21:25 ` Roman Kagan
2005-03-01 20:17 ` Tobias Klauser
2005-03-02  7:13 ` David Brownell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20050228184141.GA24961@vrfy.org \
    --to=kay.sievers@vrfy.org \
    --cc=linux-hotplug@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).