linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [udev] experimental (very simple) SYMLINK creation
@ 2003-12-05  4:24 Kay Sievers
  0 siblings, 0 replies; 8+ messages in thread
From: Kay Sievers @ 2003-12-05  4:24 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 581 bytes --]

Hi,
here is a experimental symlink creation patch - for discussion,
in which direction we should go.
It is possible now to define SYMLINK= after the NAME= in udev.rules.
The link is relative to the node, but the path is not optimized now
if the node and the link are in the same nested directory.
Only one link is supported, cause i need to sleep now :)

thanks,
Kay


06-simple-symlink-creation.diff
  simple symlink creation
  reorganized udev-remove to have access to the symlink field
  subdir creation/removal are functions now
  udev-test.pl tests for link creation/removal


[-- Attachment #2: 06-simple-symlink-creation.diff --]
[-- Type: text/plain, Size: 11747 bytes --]

diff -Nru a/namedev.c b/namedev.c
--- a/namedev.c	Fri Dec  5 04:59:53 2003
+++ b/namedev.c	Fri Dec  5 04:59:53 2003
@@ -121,6 +121,7 @@
 		copy_string(dev, new_dev, place);
 		copy_string(dev, new_dev, kernel_name);
 		copy_string(dev, new_dev, exec_program);
+		copy_string(dev, new_dev, symlink);
 		return 0;
 	}
 
@@ -366,6 +367,7 @@
 		if (strcmp_pattern(dev->id, udev->callout_value) != 0)
 			continue;
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("callout returned matching value '%s', '%s' becomes '%s'",
 		    dev->id, class_dev->name, udev->name);
 		return 0;
@@ -416,6 +418,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching attribute '%s', '%s' becomes '%s' ",
 		    dev->sysfs_file, class_dev->name, udev->name);
 
@@ -461,6 +464,7 @@
 		if (!found)
 			continue;
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching id '%s', '%s' becomes '%s'",
 		    dev->id, class_dev->name, udev->name);
 		return 0;
@@ -506,6 +510,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching place '%s', '%s' becomes '%s'",
 		    dev->place, class_dev->name, udev->name);
 		return 0;
@@ -528,6 +533,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found name, '%s' becomes '%s'", dev->kernel_name, udev->name);
 		
 		return 0;
@@ -618,8 +624,9 @@
 	goto done;
 
 found:
-	/* substitute placeholder in NAME  */
+	/* substitute placeholder */
 	apply_format(udev, udev->name);
+	apply_format(udev, udev->symlink);
 
 done:
 	perm = find_perm(udev->name);
diff -Nru a/namedev.h b/namedev.h
--- a/namedev.h	Fri Dec  5 04:59:53 2003
+++ b/namedev.h	Fri Dec  5 04:59:53 2003
@@ -63,6 +63,7 @@
 	char kernel_name[NAME_SIZE];
 	char exec_program[FILE_SIZE];
 	char name[NAME_SIZE];
+	char symlink[NAME_SIZE];
 };
 
 struct perm_device {
diff -Nru a/namedev_parse.c b/namedev_parse.c
--- a/namedev_parse.c	Fri Dec  5 04:59:53 2003
+++ b/namedev_parse.c	Fri Dec  5 04:59:53 2003
@@ -291,9 +291,11 @@
 			if (retval)
 				break;
 			strfieldcpy(dev.name, temp3);
+
 			dbg_parse("REPLACE name='%s', kernel_name='%s'",
 				  dev.name, dev.kernel_name);
 		}
+
 		if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
 			/* number type */
 			dev.type = CALLOUT;
@@ -324,10 +326,17 @@
 			if (retval)
 				break;
 			strfieldcpy(dev.name, temp3);
+
 			dbg_parse("CALLOUT name='%s', program='%s'",
 				  dev.name, dev.exec_program);
 		}
 
+		/* SYMLINK="name" */
+		temp2 = strsep(&temp, ",");
+		retval = get_value("SYMLINK", &temp, &temp3);
+		if (retval == 0)
+			strfieldcpy(dev.symlink, temp3);
+
 		retval = add_config_dev(&dev);
 		if (retval) {
 			dbg("add_config_dev returned with error %d", retval);
@@ -414,7 +423,7 @@
 			  dev.mode);
 		retval = add_perm_dev(&dev);
 		if (retval) {
-			dbg("add_config_dev returned with error %d", retval);
+			dbg("add_perm_dev returned with error %d", retval);
 			goto exit;
 		}
 	}
diff -Nru a/test/udev-test.pl b/test/udev-test.pl
--- a/test/udev-test.pl	Fri Dec  5 04:59:53 2003
+++ b/test/udev-test.pl	Fri Dec  5 04:59:53 2003
@@ -39,7 +39,7 @@
 		expected => "boot_disk" ,
 		conf     => <<EOF
 LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
-REPLACE, KERNEL="ttyUSB0", NAME="visor""
+REPLACE, KERNEL="ttyUSB0", NAME="visor"
 EOF
 	},
 	{
@@ -171,14 +171,30 @@
 EOF
 	},
 	{
-		desc     => "callout bus type",
+		desc     => "symlink creation (node)",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "ttyUSB0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="tts/USB%n"
+EOF
+	},
+	{
+		desc     => "symlink creation (link)",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "tts/USB0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="tts/USB%n"
+EOF
+	},
+	{
+		desc     => "symlink creation (link)",
 		subsys   => "block",
-		devpath  => "block/sda",
-		expected => "scsi-0:0:0:0" ,
+		devpath  => "block/sda/sda2",
+		expected => "my/own/link2" ,
 		conf     => <<EOF
-CALLOUT, BUS="usb", PROGRAM="/bin/echo -n usb-%b", ID="*", NAME="%c"
-CALLOUT, BUS="scsi", PROGRAM="/bin/echo -n scsi-%b", ID="*", NAME="%c"
-CALLOUT, BUS="foo", PROGRAM="/bin/echo -n foo-%b", ID="*", NAME="%c"
+LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="lun0/%D", SYMLINK="my/own/link%n"
 EOF
 	},
 );
@@ -238,7 +254,8 @@
 	}
 
 	udev("remove", $config->{subsys}, $config->{devpath}, \$config->{conf});
-	if (-e "$PWD/$udev_root$config->{expected}") {
+	if ((-e "$PWD/$udev_root$config->{expected}") ||
+	    (-l "$PWD/$udev_root$config->{expected}")) {
 		print "remove: error\n\n";
 		system("tree $udev_root");
 		$error++;
diff -Nru a/udev-add.c b/udev-add.c
--- a/udev-add.c	Fri Dec  5 04:59:53 2003
+++ b/udev-add.c	Fri Dec  5 04:59:53 2003
@@ -72,6 +72,34 @@
 	return retval;
 }
 
+static int create_path(char *file)
+{
+	char p[NAME_SIZE];
+	char *pos;
+	int retval;
+	struct stat stats;
+	
+	strncpy(p, file, sizeof(p));
+	pos = strchr(p+1, '/');
+	while (1) {
+		pos = strchr(pos+1, '/');
+		if (pos == NULL)
+			break;
+		*pos = 0x00;
+		if (stat(p, &stats)) {
+			retval = mkdir(p, 0755);
+			if (retval) {
+				dbg("mkdir(%s) failed with error '%s'",
+				    p, strerror(errno));
+				return retval;
+			}
+			dbg("created '%s'", p);
+		}
+		*pos = '/';
+	}
+	return 0;
+}
+
 /*
  * we possibly want to add some symlinks here
  * only numeric owner/group id's are supported
@@ -79,10 +107,12 @@
 static int create_node(struct udevice *dev)
 {
 	char filename[255];
+	char linkname[255];
 	int retval = 0;
 	uid_t uid = 0;
 	gid_t gid = 0;
 	dev_t res;
+	char *pos;
 
 	strncpy(filename, udev_root, sizeof(filename));
 	strncat(filename, dev->name, sizeof(filename));
@@ -109,31 +139,9 @@
 		return -EINVAL;
 	}
 
-	/* create subdirectories if requested */
-	if (strchr(dev->name, '/')) {
-		char path[255];
-		char *pos;
-		struct stat stats;
-
-		strncpy(path, filename, sizeof(path));
-		pos = strchr(path+1, '/');
-		while (1) {
-			pos = strchr(pos+1, '/');
-			if (pos == NULL)
-				break;
-			*pos = 0x00;
-			if (stat(path, &stats)) {
-				retval = mkdir(path, 0755);
-				if (retval) {
-					dbg("mkdir(%s) failed with error '%s'",
-					    path, strerror(errno));
-					return retval;
-				}
-				dbg("created '%s'", path);
-			}
-			*pos = '/';
-		}
-	}
+	/* create parent directories if needed */
+	if (strrchr(dev->name, '/'))
+		create_path(filename);
 
 	dbg("mknod(%s, %#o, %u, %u)", filename, dev->mode, dev->major, dev->minor);
 	retval = mknod(filename, dev->mode, res);
@@ -179,8 +187,36 @@
 		dbg("chown(%s, %u, %u)", filename, uid, gid);
 		retval = chown(filename, uid, gid);
 		if (retval)
-			dbg("chown(%s, %u, %u) failed with error '%s'", filename,
-			    uid, gid, strerror(errno));
+			dbg("chown(%s, %u, %u) failed with error '%s'",
+			    filename, uid, gid, strerror(errno));
+	}
+
+
+	/* create symlink if requested */
+	if (*dev->symlink) {
+		strncpy(linkname, udev_root, sizeof(linkname));
+		strncat(linkname, dev->symlink, sizeof(linkname));
+		pos = strchr(dev->symlink, '/');
+		if (pos) {
+			create_path(linkname);
+			strcpy(filename, "../");
+			while (1) {
+				pos = strchr(pos+1, '/');
+				if (pos == NULL)
+					break;
+				strcat(filename, "../");
+			}
+		} else {
+			strcpy(filename, "./");
+		}
+		strncat(filename, dev->name, sizeof(filename));
+
+		dbg("symlink(%s, %s)", filename, linkname);
+
+		retval = symlink(filename, linkname);
+		if (retval)
+			dbg("symlink(%s, %s) failed with error '%s'",
+			    filename, linkname, strerror(errno));
 	}
 
 	return retval;
diff -Nru a/udev-remove.c b/udev-remove.c
--- a/udev-remove.c	Fri Dec  5 04:59:53 2003
+++ b/udev-remove.c	Fri Dec  5 04:59:53 2003
@@ -34,47 +34,43 @@
 #include "udevdb.h"
 #include "libsysfs/libsysfs.h"
 
-
-/*
- * Look up the sysfs path in the database to see if we have named this device
- * something different from the kernel name.  If we have, us it.  If not, use
- * the default kernel name for lack of anything else to know to do.
- */
-static char *get_name(char *path, int major, int minor)
+static int delete_path(char *path)
 {
-	static char name[100];
-	struct udevice *dev;
-	char *temp;
+	char *pos;
+	int retval;
 
-	dev = udevdb_get_dev(path);
-	if (dev != NULL) {
-		strcpy(name, dev->name);
-		goto exit;
+	pos = strrchr(path, '/');
+	while (1) {
+		*pos = '\0';
+		pos = strrchr(path, '/');
+
+		/* don't remove the last one */
+		if ((pos == path) || (pos == NULL))
+			break;
+
+		/* remove if empty */
+		retval = rmdir(path);
+		if (retval) {
+			if (errno == ENOTEMPTY)
+				return 0;
+			dbg("rmdir(%s) failed with error '%s'",
+			    path, strerror(errno));
+			break;
+		}
+		dbg("removed '%s'", path);
 	}
-
-	dbg("'%s' not found in database, falling back on default name", path);
-	temp = strrchr(path, '/');
-	if (temp == NULL)
-		return NULL;
-	strncpy(name, &temp[1], sizeof(name));
-
-exit:
-	dbg("name is '%s'", name);
-	return &name[0];
+	return 0;
 }
 
-/*
- * We also want to clean up any symlinks that were created in create_node()
- */
-static int delete_node(char *name)
+static int delete_node(struct udevice *dev)
 {
 	char filename[255];
 	int retval;
 
 	strncpy(filename, udev_root, sizeof(filename));
-	strncat(filename, name, sizeof(filename));
+	strncat(filename, dev->name, sizeof(filename));
 
-	dbg("unlinking '%s'", filename);
+	dbg("unlinking node '%s'", filename);
 	retval = unlink(filename);
 	if (retval) {
 		dbg("unlink(%s) failed with error '%s'",
@@ -83,49 +79,43 @@
 	}
 
 	/* remove subdirectories */
-	if (strchr(name, '/')) {
-		char *pos;
+	if (strchr(dev->name, '/'))
+		delete_path(filename);
 
-		pos = strrchr(filename, '/');
-		while (1) {
-			*pos = 0x00;
-			pos = strrchr(filename, '/');
-
-			/* don't remove the last one */
-			if ((pos == filename) || (pos == NULL))
-				break;
-
-			/* remove if empty */
-			retval = rmdir(filename);
-			if (retval) {
-				if (errno == ENOTEMPTY)
-					return 0;
-				dbg("rmdir(%s) failed with error '%s'",
-				    filename, strerror(errno));
-				break;
-			}
-			dbg("removed '%s'", filename);
+	if (*dev->symlink) {
+		strncpy(filename, udev_root, sizeof(filename));
+		strncat(filename, dev->symlink, sizeof(filename));
+		dbg("unlinking symlink '%s'", filename);
+		retval = unlink(filename);
+		if (retval) {
+			dbg("unlink(%s) failed with error '%s'",
+				filename, strerror(errno));
+			return retval;
+		}
+		if (strchr(dev->symlink, '/')) {
+			delete_path(filename);
 		}
 	}
+
 	return retval;
 }
 
-int udev_remove_device(char *device, char *subsystem)
+int udev_remove_device(char *path, char *subsystem)
 {
-	char *name;
-	int retval = 0;
+	char name[100];
+	struct udevice *dev;
+	char *temp;
 
-	name = get_name(device, 0, 0);
-	if (name == NULL) {
-		dbg ("get_name failed");
-		retval = -ENODEV;
-		goto exit;
+	dev = udevdb_get_dev(path);
+	if (dev == NULL) {
+		dbg("'%s' not found in database, falling back on default name", path);
+		temp = strrchr(path, '/');
+		if (temp == NULL)
+			return -ENODEV;
+		strncpy(name, &temp[1], sizeof(name));
 	}
 
-	udevdb_delete_dev(device);
-
-	return delete_node(name);
-
-exit:
-	return retval;
+	dbg("name is '%s'", dev->name);
+	udevdb_delete_dev(path);
+	return delete_node(dev);
 }
diff -Nru a/udev.h b/udev.h
--- a/udev.h	Fri Dec  5 04:59:53 2003
+++ b/udev.h	Fri Dec  5 04:59:53 2003
@@ -64,6 +64,7 @@
 	int major;
 	int minor;
 	mode_t mode;
+	char symlink[NAME_SIZE];
 
 	/* fields that help us in building strings */
 	unsigned char bus_id[SYSFS_NAME_LEN];

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

* Re: [udev] experimental (very simple) SYMLINK creation
@ 2003-12-05  7:26 Olaf Hering
  2003-12-05 15:45 ` Kay Sievers
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Olaf Hering @ 2003-12-05  7:26 UTC (permalink / raw)
  To: linux-hotplug

 On Fri, Dec 05, Kay Sievers wrote:

> It is possible now to define SYMLINK= after the NAME= in udev.rules.

Nice! Thanks.

-- 
USB is for mice, FireWire is for men!

sUse lINUX ag, n√úRNBERG


-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id\x1278&alloc_id371&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] 8+ messages in thread

* Re: [udev] experimental (very simple) SYMLINK creation
  2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
@ 2003-12-05 15:45 ` Kay Sievers
  2003-12-07  6:02 ` Kay Sievers
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Kay Sievers @ 2003-12-05 15:45 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 773 bytes --]

On Fri, Dec 05, 2003 at 05:24:33AM +0100, Kay Sievers wrote:
> here is a experimental symlink creation patch - for discussion,
> in which direction we should go.
> It is possible now to define SYMLINK= after the NAME= in udev.rules.
> The link is relative to the node, but the path is not optimized now
> if the node and the link are in the same nested directory.
> Only one link is supported, cause i need to sleep now :)
> 
> 06-simple-symlink-creation.diff
>   simple symlink creation
>   reorganized udev-remove to have access to the symlink field
>   subdir creation/removal are functions now
>   udev-test.pl tests for link creation/removal

Eeh, the copy-paste-devil removed one of the tests from udev-test.pl and one comment :)
So here is a new patch.

thanks,
Kay

[-- Attachment #2: 06-simple-symlink-creation.diff --]
[-- Type: text/plain, Size: 11758 bytes --]

diff -Nru a/namedev.c b/namedev.c
--- a/namedev.c	Fri Dec  5 16:38:27 2003
+++ b/namedev.c	Fri Dec  5 16:38:27 2003
@@ -121,6 +121,7 @@
 		copy_string(dev, new_dev, place);
 		copy_string(dev, new_dev, kernel_name);
 		copy_string(dev, new_dev, exec_program);
+		copy_string(dev, new_dev, symlink);
 		return 0;
 	}
 
@@ -366,6 +367,7 @@
 		if (strcmp_pattern(dev->id, udev->callout_value) != 0)
 			continue;
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("callout returned matching value '%s', '%s' becomes '%s'",
 		    dev->id, class_dev->name, udev->name);
 		return 0;
@@ -416,6 +418,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching attribute '%s', '%s' becomes '%s' ",
 		    dev->sysfs_file, class_dev->name, udev->name);
 
@@ -461,6 +464,7 @@
 		if (!found)
 			continue;
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching id '%s', '%s' becomes '%s'",
 		    dev->id, class_dev->name, udev->name);
 		return 0;
@@ -506,6 +510,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching place '%s', '%s' becomes '%s'",
 		    dev->place, class_dev->name, udev->name);
 		return 0;
@@ -528,6 +533,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found name, '%s' becomes '%s'", dev->kernel_name, udev->name);
 		
 		return 0;
@@ -618,8 +624,9 @@
 	goto done;
 
 found:
-	/* substitute placeholder in NAME  */
+	/* substitute placeholder */
 	apply_format(udev, udev->name);
+	apply_format(udev, udev->symlink);
 
 done:
 	perm = find_perm(udev->name);
diff -Nru a/namedev.h b/namedev.h
--- a/namedev.h	Fri Dec  5 16:38:27 2003
+++ b/namedev.h	Fri Dec  5 16:38:27 2003
@@ -63,6 +63,7 @@
 	char kernel_name[NAME_SIZE];
 	char exec_program[FILE_SIZE];
 	char name[NAME_SIZE];
+	char symlink[NAME_SIZE];
 };
 
 struct perm_device {
diff -Nru a/namedev_parse.c b/namedev_parse.c
--- a/namedev_parse.c	Fri Dec  5 16:38:27 2003
+++ b/namedev_parse.c	Fri Dec  5 16:38:27 2003
@@ -291,9 +291,11 @@
 			if (retval)
 				break;
 			strfieldcpy(dev.name, temp3);
+
 			dbg_parse("REPLACE name='%s', kernel_name='%s'",
 				  dev.name, dev.kernel_name);
 		}
+
 		if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
 			/* number type */
 			dev.type = CALLOUT;
@@ -324,10 +326,17 @@
 			if (retval)
 				break;
 			strfieldcpy(dev.name, temp3);
+
 			dbg_parse("CALLOUT name='%s', program='%s'",
 				  dev.name, dev.exec_program);
 		}
 
+		/* SYMLINK="name" */
+		temp2 = strsep(&temp, ",");
+		retval = get_value("SYMLINK", &temp, &temp3);
+		if (retval == 0)
+			strfieldcpy(dev.symlink, temp3);
+
 		retval = add_config_dev(&dev);
 		if (retval) {
 			dbg("add_config_dev returned with error %d", retval);
@@ -414,7 +423,7 @@
 			  dev.mode);
 		retval = add_perm_dev(&dev);
 		if (retval) {
-			dbg("add_config_dev returned with error %d", retval);
+			dbg("add_perm_dev returned with error %d", retval);
 			goto exit;
 		}
 	}
diff -Nru a/test/udev-test.pl b/test/udev-test.pl
--- a/test/udev-test.pl	Fri Dec  5 16:38:27 2003
+++ b/test/udev-test.pl	Fri Dec  5 16:38:27 2003
@@ -39,7 +39,7 @@
 		expected => "boot_disk" ,
 		conf     => <<EOF
 LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
-REPLACE, KERNEL="ttyUSB0", NAME="visor""
+REPLACE, KERNEL="ttyUSB0", NAME="visor"
 EOF
 	},
 	{
@@ -181,6 +181,33 @@
 CALLOUT, BUS="foo", PROGRAM="/bin/echo -n foo-%b", ID="*", NAME="%c"
 EOF
 	},
+	{
+		desc     => "symlink creation (node)",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "ttyUSB0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="tts/USB%n"
+EOF
+	},
+	{
+		desc     => "symlink creation (link)",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "tts/USB0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="tts/USB%n"
+EOF
+	},
+	{
+		desc     => "symlink creation (link)",
+		subsys   => "block",
+		devpath  => "block/sda/sda2",
+		expected => "my/own/link2" ,
+		conf     => <<EOF
+LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="lun0/%D", SYMLINK="my/own/link%n"
+EOF
+	},
 );
 
 # set env
@@ -238,7 +265,8 @@
 	}
 
 	udev("remove", $config->{subsys}, $config->{devpath}, \$config->{conf});
-	if (-e "$PWD/$udev_root$config->{expected}") {
+	if ((-e "$PWD/$udev_root$config->{expected}") ||
+	    (-l "$PWD/$udev_root$config->{expected}")) {
 		print "remove: error\n\n";
 		system("tree $udev_root");
 		$error++;
diff -Nru a/udev-add.c b/udev-add.c
--- a/udev-add.c	Fri Dec  5 16:38:27 2003
+++ b/udev-add.c	Fri Dec  5 16:38:27 2003
@@ -72,6 +72,34 @@
 	return retval;
 }
 
+static int create_path(char *file)
+{
+	char p[NAME_SIZE];
+	char *pos;
+	int retval;
+	struct stat stats;
+	
+	strncpy(p, file, sizeof(p));
+	pos = strchr(p+1, '/');
+	while (1) {
+		pos = strchr(pos+1, '/');
+		if (pos == NULL)
+			break;
+		*pos = 0x00;
+		if (stat(p, &stats)) {
+			retval = mkdir(p, 0755);
+			if (retval) {
+				dbg("mkdir(%s) failed with error '%s'",
+				    p, strerror(errno));
+				return retval;
+			}
+			dbg("created '%s'", p);
+		}
+		*pos = '/';
+	}
+	return 0;
+}
+
 /*
  * we possibly want to add some symlinks here
  * only numeric owner/group id's are supported
@@ -79,10 +107,12 @@
 static int create_node(struct udevice *dev)
 {
 	char filename[255];
+	char linkname[255];
 	int retval = 0;
 	uid_t uid = 0;
 	gid_t gid = 0;
 	dev_t res;
+	char *pos;
 
 	strncpy(filename, udev_root, sizeof(filename));
 	strncat(filename, dev->name, sizeof(filename));
@@ -109,31 +139,9 @@
 		return -EINVAL;
 	}
 
-	/* create subdirectories if requested */
-	if (strchr(dev->name, '/')) {
-		char path[255];
-		char *pos;
-		struct stat stats;
-
-		strncpy(path, filename, sizeof(path));
-		pos = strchr(path+1, '/');
-		while (1) {
-			pos = strchr(pos+1, '/');
-			if (pos == NULL)
-				break;
-			*pos = 0x00;
-			if (stat(path, &stats)) {
-				retval = mkdir(path, 0755);
-				if (retval) {
-					dbg("mkdir(%s) failed with error '%s'",
-					    path, strerror(errno));
-					return retval;
-				}
-				dbg("created '%s'", path);
-			}
-			*pos = '/';
-		}
-	}
+	/* create parent directories if needed */
+	if (strrchr(dev->name, '/'))
+		create_path(filename);
 
 	dbg("mknod(%s, %#o, %u, %u)", filename, dev->mode, dev->major, dev->minor);
 	retval = mknod(filename, dev->mode, res);
@@ -179,8 +187,36 @@
 		dbg("chown(%s, %u, %u)", filename, uid, gid);
 		retval = chown(filename, uid, gid);
 		if (retval)
-			dbg("chown(%s, %u, %u) failed with error '%s'", filename,
-			    uid, gid, strerror(errno));
+			dbg("chown(%s, %u, %u) failed with error '%s'",
+			    filename, uid, gid, strerror(errno));
+	}
+
+
+	/* create symlink if requested */
+	if (*dev->symlink) {
+		strncpy(linkname, udev_root, sizeof(linkname));
+		strncat(linkname, dev->symlink, sizeof(linkname));
+		pos = strchr(dev->symlink, '/');
+		if (pos) {
+			create_path(linkname);
+			strcpy(filename, "../");
+			while (1) {
+				pos = strchr(pos+1, '/');
+				if (pos == NULL)
+					break;
+				strcat(filename, "../");
+			}
+		} else {
+			strcpy(filename, "./");
+		}
+		strncat(filename, dev->name, sizeof(filename));
+
+		dbg("symlink(%s, %s)", filename, linkname);
+
+		retval = symlink(filename, linkname);
+		if (retval)
+			dbg("symlink(%s, %s) failed with error '%s'",
+			    filename, linkname, strerror(errno));
 	}
 
 	return retval;
diff -Nru a/udev-remove.c b/udev-remove.c
--- a/udev-remove.c	Fri Dec  5 16:38:27 2003
+++ b/udev-remove.c	Fri Dec  5 16:38:27 2003
@@ -34,47 +34,43 @@
 #include "udevdb.h"
 #include "libsysfs/libsysfs.h"
 
-
-/*
- * Look up the sysfs path in the database to see if we have named this device
- * something different from the kernel name.  If we have, us it.  If not, use
- * the default kernel name for lack of anything else to know to do.
- */
-static char *get_name(char *path, int major, int minor)
+static int delete_path(char *path)
 {
-	static char name[100];
-	struct udevice *dev;
-	char *temp;
+	char *pos;
+	int retval;
 
-	dev = udevdb_get_dev(path);
-	if (dev != NULL) {
-		strcpy(name, dev->name);
-		goto exit;
+	pos = strrchr(path, '/');
+	while (1) {
+		*pos = '\0';
+		pos = strrchr(path, '/');
+
+		/* don't remove the last one */
+		if ((pos == path) || (pos == NULL))
+			break;
+
+		/* remove if empty */
+		retval = rmdir(path);
+		if (retval) {
+			if (errno == ENOTEMPTY)
+				return 0;
+			dbg("rmdir(%s) failed with error '%s'",
+			    path, strerror(errno));
+			break;
+		}
+		dbg("removed '%s'", path);
 	}
-
-	dbg("'%s' not found in database, falling back on default name", path);
-	temp = strrchr(path, '/');
-	if (temp == NULL)
-		return NULL;
-	strncpy(name, &temp[1], sizeof(name));
-
-exit:
-	dbg("name is '%s'", name);
-	return &name[0];
+	return 0;
 }
 
-/*
- * We also want to clean up any symlinks that were created in create_node()
- */
-static int delete_node(char *name)
+static int delete_node(struct udevice *dev)
 {
 	char filename[255];
 	int retval;
 
 	strncpy(filename, udev_root, sizeof(filename));
-	strncat(filename, name, sizeof(filename));
+	strncat(filename, dev->name, sizeof(filename));
 
-	dbg("unlinking '%s'", filename);
+	dbg("unlinking node '%s'", filename);
 	retval = unlink(filename);
 	if (retval) {
 		dbg("unlink(%s) failed with error '%s'",
@@ -83,49 +79,48 @@
 	}
 
 	/* remove subdirectories */
-	if (strchr(name, '/')) {
-		char *pos;
+	if (strchr(dev->name, '/'))
+		delete_path(filename);
 
-		pos = strrchr(filename, '/');
-		while (1) {
-			*pos = 0x00;
-			pos = strrchr(filename, '/');
-
-			/* don't remove the last one */
-			if ((pos == filename) || (pos == NULL))
-				break;
-
-			/* remove if empty */
-			retval = rmdir(filename);
-			if (retval) {
-				if (errno == ENOTEMPTY)
-					return 0;
-				dbg("rmdir(%s) failed with error '%s'",
-				    filename, strerror(errno));
-				break;
-			}
-			dbg("removed '%s'", filename);
+	if (*dev->symlink) {
+		strncpy(filename, udev_root, sizeof(filename));
+		strncat(filename, dev->symlink, sizeof(filename));
+		dbg("unlinking symlink '%s'", filename);
+		retval = unlink(filename);
+		if (retval) {
+			dbg("unlink(%s) failed with error '%s'",
+				filename, strerror(errno));
+			return retval;
+		}
+		if (strchr(dev->symlink, '/')) {
+			delete_path(filename);
 		}
 	}
+
 	return retval;
 }
 
-int udev_remove_device(char *device, char *subsystem)
+/*
+ * Look up the sysfs path in the database to see if we have named this device
+ * something different from the kernel name.  If we have, us it.  If not, use
+ * the default kernel name for lack of anything else to know to do.
+ */
+int udev_remove_device(char *path, char *subsystem)
 {
-	char *name;
-	int retval = 0;
+	char name[100];
+	struct udevice *dev;
+	char *temp;
 
-	name = get_name(device, 0, 0);
-	if (name == NULL) {
-		dbg ("get_name failed");
-		retval = -ENODEV;
-		goto exit;
+	dev = udevdb_get_dev(path);
+	if (dev == NULL) {
+		dbg("'%s' not found in database, falling back on default name", path);
+		temp = strrchr(path, '/');
+		if (temp == NULL)
+			return -ENODEV;
+		strncpy(name, &temp[1], sizeof(name));
 	}
 
-	udevdb_delete_dev(device);
-
-	return delete_node(name);
-
-exit:
-	return retval;
+	dbg("name is '%s'", dev->name);
+	udevdb_delete_dev(path);
+	return delete_node(dev);
 }
diff -Nru a/udev.h b/udev.h
--- a/udev.h	Fri Dec  5 16:38:27 2003
+++ b/udev.h	Fri Dec  5 16:38:27 2003
@@ -64,6 +64,7 @@
 	int major;
 	int minor;
 	mode_t mode;
+	char symlink[NAME_SIZE];
 
 	/* fields that help us in building strings */
 	unsigned char bus_id[SYSFS_NAME_LEN];

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

* Re: [udev] experimental (very simple) SYMLINK creation
  2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
  2003-12-05 15:45 ` Kay Sievers
@ 2003-12-07  6:02 ` Kay Sievers
  2003-12-07 17:45 ` Kay Sievers
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Kay Sievers @ 2003-12-07  6:02 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 1301 bytes --]

On Fri, Dec 05, 2003 at 04:45:28PM +0100, Kay Sievers wrote:
> On Fri, Dec 05, 2003 at 05:24:33AM +0100, Kay Sievers wrote:
> > here is a experimental symlink creation patch - for discussion,
> > in which direction we should go.
> > It is possible now to define SYMLINK= after the NAME= in udev.rules.
> > The link is relative to the node, but the path is not optimized now
> > if the node and the link are in the same nested directory.
> > Only one link is supported, cause i need to sleep now :)
> > 
> > 06-simple-symlink-creation.diff
> >   simple symlink creation
> >   reorganized udev-remove to have access to the symlink field
> >   subdir creation/removal are functions now
> >   udev-test.pl tests for link creation/removal

Here is a new version with relative link target path optimization
an better tests in udev-test.pl:

LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink"

  Dec  7 06:48:34 pim udev[13789]: create_node: symlink 'udev-root/1/2/c/d/symlink' to node '1/2/a/b/node' requested
  Dec  7 06:48:34 pim udev[13789]: create_path: created 'udev-root/1/2/c'
  Dec  7 06:48:34 pim udev[13789]: create_path: created 'udev-root/1/2/c/d'
  Dec  7 06:48:34 pim udev[13789]: create_node: symlink(../../a/b/node, udev-root/1/2/c/d/symlink)


thanks,
Kay

[-- Attachment #2: 06-simple-symlink-creation.diff --]
[-- Type: text/plain, Size: 14270 bytes --]

diff -Nru a/namedev.c b/namedev.c
--- a/namedev.c	Sun Dec  7 06:58:47 2003
+++ b/namedev.c	Sun Dec  7 06:58:47 2003
@@ -121,6 +121,7 @@
 		copy_string(dev, new_dev, place);
 		copy_string(dev, new_dev, kernel_name);
 		copy_string(dev, new_dev, exec_program);
+		copy_string(dev, new_dev, symlink);
 		return 0;
 	}
 
@@ -366,6 +367,7 @@
 		if (strcmp_pattern(dev->id, udev->callout_value) != 0)
 			continue;
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("callout returned matching value '%s', '%s' becomes '%s'",
 		    dev->id, class_dev->name, udev->name);
 		return 0;
@@ -416,6 +418,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching attribute '%s', '%s' becomes '%s' ",
 		    dev->sysfs_file, class_dev->name, udev->name);
 
@@ -461,6 +464,7 @@
 		if (!found)
 			continue;
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching id '%s', '%s' becomes '%s'",
 		    dev->id, class_dev->name, udev->name);
 		return 0;
@@ -506,6 +510,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found matching place '%s', '%s' becomes '%s'",
 		    dev->place, class_dev->name, udev->name);
 		return 0;
@@ -528,6 +533,7 @@
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
+		strfieldcpy(udev->symlink, dev->symlink);
 		dbg("found name, '%s' becomes '%s'", dev->kernel_name, udev->name);
 		
 		return 0;
@@ -618,8 +624,9 @@
 	goto done;
 
 found:
-	/* substitute placeholder in NAME  */
+	/* substitute placeholder */
 	apply_format(udev, udev->name);
+	apply_format(udev, udev->symlink);
 
 done:
 	perm = find_perm(udev->name);
diff -Nru a/namedev.h b/namedev.h
--- a/namedev.h	Sun Dec  7 06:58:47 2003
+++ b/namedev.h	Sun Dec  7 06:58:47 2003
@@ -63,6 +63,7 @@
 	char kernel_name[NAME_SIZE];
 	char exec_program[FILE_SIZE];
 	char name[NAME_SIZE];
+	char symlink[NAME_SIZE];
 };
 
 struct perm_device {
diff -Nru a/namedev_parse.c b/namedev_parse.c
--- a/namedev_parse.c	Sun Dec  7 06:58:47 2003
+++ b/namedev_parse.c	Sun Dec  7 06:58:47 2003
@@ -213,10 +213,16 @@
 				break;
 			strfieldcpy(dev.name, temp3);
 
+			/* SYMLINK="name" */
+			temp2 = strsep(&temp, ",");
+			retval = get_value("SYMLINK", &temp, &temp3);
+			if (retval == 0)
+				strfieldcpy(dev.symlink, temp3);
+
 			dbg_parse("LABEL name='%s', bus='%s', "
-				  "sysfs_file='%s', sysfs_value='%s'",
+				  "sysfs_file='%s', sysfs_value='%s', symlink='%s'",
 				  dev.name, dev.bus, dev.sysfs_file,
-				  dev.sysfs_value);
+				  dev.sysfs_value, dev.symlink);
 		}
 
 		if (strcasecmp(temp2, TYPE_NUMBER) == 0) {
@@ -243,8 +249,14 @@
 				break;
 			strfieldcpy(dev.name, temp3);
 
-			dbg_parse("NUMBER name='%s', bus='%s', id='%s'",
-				  dev.name, dev.bus, dev.id);
+			/* SYMLINK="name" */
+			temp2 = strsep(&temp, ",");
+			retval = get_value("SYMLINK", &temp, &temp3);
+			if (retval == 0)
+				strfieldcpy(dev.symlink, temp3);
+
+			dbg_parse("NUMBER name='%s', bus='%s', id='%s', symlink='%s'",
+				  dev.name, dev.bus, dev.id, dev.symlink);
 		}
 
 		if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) {
@@ -271,8 +283,15 @@
 				break;
 			strfieldcpy(dev.name, temp3);
 
-			dbg_parse("TOPOLOGY name='%s', bus='%s', place='%s'",
-				  dev.name, dev.bus, dev.place);
+			/* SYMLINK="name" */
+			temp2 = strsep(&temp, ",");
+			retval = get_value("SYMLINK", &temp, &temp3);
+			if (retval == 0)
+				strfieldcpy(dev.symlink, temp3);
+
+			dbg_parse("TOPOLOGY name='%s', bus='%s', "
+				  "place='%s', symlink='%s'",
+				  dev.name, dev.bus, dev.place, dev.symlink);
 		}
 
 		if (strcasecmp(temp2, TYPE_REPLACE) == 0) {
@@ -291,9 +310,17 @@
 			if (retval)
 				break;
 			strfieldcpy(dev.name, temp3);
-			dbg_parse("REPLACE name='%s', kernel_name='%s'",
-				  dev.name, dev.kernel_name);
+
+			/* SYMLINK="name" */
+			temp2 = strsep(&temp, ",");
+			retval = get_value("SYMLINK", &temp, &temp3);
+			if (retval == 0)
+				strfieldcpy(dev.symlink, temp3);
+
+			dbg_parse("REPLACE name='%s', kernel_name='%s', symlink='%s'",
+				  dev.name, dev.kernel_name, dev.symlink);
 		}
+
 		if (strcasecmp(temp2, TYPE_CALLOUT) == 0) {
 			/* number type */
 			dev.type = CALLOUT;
@@ -324,8 +351,17 @@
 			if (retval)
 				break;
 			strfieldcpy(dev.name, temp3);
-			dbg_parse("CALLOUT name='%s', program='%s'",
-				  dev.name, dev.exec_program);
+
+			/* SYMLINK="name" */
+			temp2 = strsep(&temp, ",");
+			retval = get_value("SYMLINK", &temp, &temp3);
+			if (retval == 0)
+				strfieldcpy(dev.symlink, temp3);
+
+			dbg_parse("CALLOUT name='%s', bus='%s', program='%s', "
+				  "id='%s', symlink='%s'",
+				  dev.name, dev.bus, dev.exec_program,
+				  dev.id, dev.symlink);
 		}
 
 		retval = add_config_dev(&dev);
@@ -414,7 +450,7 @@
 			  dev.mode);
 		retval = add_perm_dev(&dev);
 		if (retval) {
-			dbg("add_config_dev returned with error %d", retval);
+			dbg("add_perm_dev returned with error %d", retval);
 			goto exit;
 		}
 	}
diff -Nru a/test/udev-test.pl b/test/udev-test.pl
--- a/test/udev-test.pl	Sun Dec  7 06:58:47 2003
+++ b/test/udev-test.pl	Sun Dec  7 06:58:47 2003
@@ -39,7 +39,7 @@
 		expected => "boot_disk" ,
 		conf     => <<EOF
 LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
-REPLACE, KERNEL="ttyUSB0", NAME="visor""
+REPLACE, KERNEL="ttyUSB0", NAME="visor"
 EOF
 	},
 	{
@@ -181,6 +181,42 @@
 CALLOUT, BUS="foo", PROGRAM="/bin/echo -n foo-%b", ID="*", NAME="%c"
 EOF
 	},
+	{
+		desc     => "symlink creation (same directory)",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "visor0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB[0-9]*", NAME="ttyUSB%n", SYMLINK="visor%n"
+EOF
+	},
+	{
+		desc     => "symlink creation (relative link back)",
+		subsys   => "block",
+		devpath  => "block/sda/sda2",
+		expected => "1/2/a/b/symlink" ,
+		conf     => <<EOF
+LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/node", SYMLINK="1/2/a/b/symlink"
+EOF
+	},
+	{
+		desc     => "symlink creation (relative link forward)",
+		subsys   => "block",
+		devpath  => "block/sda/sda2",
+		expected => "1/2/symlink" ,
+		conf     => <<EOF
+LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/symlink"
+EOF
+	},
+	{
+		desc     => "symlink creation (relative link back and forward)",
+		subsys   => "block",
+		devpath  => "block/sda/sda2",
+		expected => "1/2/c/d/symlink" ,
+		conf     => <<EOF
+LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink"
+EOF
+	},
 );
 
 # set env
@@ -238,7 +274,8 @@
 	}
 
 	udev("remove", $config->{subsys}, $config->{devpath}, \$config->{conf});
-	if (-e "$PWD/$udev_root$config->{expected}") {
+	if ((-e "$PWD/$udev_root$config->{expected}") ||
+	    (-l "$PWD/$udev_root$config->{expected}")) {
 		print "remove: error\n\n";
 		system("tree $udev_root");
 		$error++;
diff -Nru a/udev-add.c b/udev-add.c
--- a/udev-add.c	Sun Dec  7 06:58:47 2003
+++ b/udev-add.c	Sun Dec  7 06:58:47 2003
@@ -72,6 +72,34 @@
 	return retval;
 }
 
+static int create_path(char *file)
+{
+	char p[NAME_SIZE];
+	char *pos;
+	int retval;
+	struct stat stats;
+	
+	strncpy(p, file, sizeof(p));
+	pos = strchr(p+1, '/');
+	while (1) {
+		pos = strchr(pos+1, '/');
+		if (pos == NULL)
+			break;
+		*pos = 0x00;
+		if (stat(p, &stats)) {
+			retval = mkdir(p, 0755);
+			if (retval) {
+				dbg("mkdir(%s) failed with error '%s'",
+				    p, strerror(errno));
+				return retval;
+			}
+			dbg("created '%s'", p);
+		}
+		*pos = '/';
+	}
+	return 0;
+}
+
 /*
  * we possibly want to add some symlinks here
  * only numeric owner/group id's are supported
@@ -79,10 +107,14 @@
 static int create_node(struct udevice *dev)
 {
 	char filename[255];
+	char linktarget[255];
 	int retval = 0;
 	uid_t uid = 0;
 	gid_t gid = 0;
 	dev_t res;
+	int i;
+	int tail;
+
 
 	strncpy(filename, udev_root, sizeof(filename));
 	strncat(filename, dev->name, sizeof(filename));
@@ -109,31 +141,9 @@
 		return -EINVAL;
 	}
 
-	/* create subdirectories if requested */
-	if (strchr(dev->name, '/')) {
-		char path[255];
-		char *pos;
-		struct stat stats;
-
-		strncpy(path, filename, sizeof(path));
-		pos = strchr(path+1, '/');
-		while (1) {
-			pos = strchr(pos+1, '/');
-			if (pos == NULL)
-				break;
-			*pos = 0x00;
-			if (stat(path, &stats)) {
-				retval = mkdir(path, 0755);
-				if (retval) {
-					dbg("mkdir(%s) failed with error '%s'",
-					    path, strerror(errno));
-					return retval;
-				}
-				dbg("created '%s'", path);
-			}
-			*pos = '/';
-		}
-	}
+	/* create parent directories if needed */
+	if (strrchr(dev->name, '/'))
+		create_path(filename);
 
 	dbg("mknod(%s, %#o, %u, %u)", filename, dev->mode, dev->major, dev->minor);
 	retval = mknod(filename, dev->mode, res);
@@ -179,8 +189,43 @@
 		dbg("chown(%s, %u, %u)", filename, uid, gid);
 		retval = chown(filename, uid, gid);
 		if (retval)
-			dbg("chown(%s, %u, %u) failed with error '%s'", filename,
-			    uid, gid, strerror(errno));
+			dbg("chown(%s, %u, %u) failed with error '%s'",
+			    filename, uid, gid, strerror(errno));
+	}
+
+
+	/* create symlink if requested */
+	if (*dev->symlink) {
+		strncpy(filename, udev_root, sizeof(filename));
+		strncat(filename, dev->symlink, sizeof(filename));
+		dbg("symlink '%s' to node '%s' requested", filename, dev->name);
+		if (strrchr(dev->symlink, '/'))
+			create_path(filename);
+
+		/* optimize relative link */
+		linktarget[0] = '\0';
+		i = 0;
+		tail = 0;
+		while ((dev->name[i] == dev->symlink[i]) && dev->name[i]) {
+			if (dev->name[i] == '/')
+				tail = i+1;
+			i++;
+		}
+		while (dev->symlink[i]) {
+			if (dev->symlink[i] == '/')
+				strcat(linktarget, "../");
+			i++;
+		}
+
+		if (*linktarget == '\0')
+			strcpy(linktarget, "./");
+		strcat(linktarget, &dev->name[tail]);
+
+		dbg("symlink(%s, %s)", linktarget, filename);
+		retval = symlink(linktarget, filename);
+		if (retval)
+			dbg("symlink(%s, %s) failed with error '%s'",
+			    linktarget, filename, strerror(errno));
 	}
 
 	return retval;
diff -Nru a/udev-remove.c b/udev-remove.c
--- a/udev-remove.c	Sun Dec  7 06:58:47 2003
+++ b/udev-remove.c	Sun Dec  7 06:58:47 2003
@@ -34,47 +34,43 @@
 #include "udevdb.h"
 #include "libsysfs/libsysfs.h"
 
-
-/*
- * Look up the sysfs path in the database to see if we have named this device
- * something different from the kernel name.  If we have, us it.  If not, use
- * the default kernel name for lack of anything else to know to do.
- */
-static char *get_name(char *path, int major, int minor)
+static int delete_path(char *path)
 {
-	static char name[100];
-	struct udevice *dev;
-	char *temp;
+	char *pos;
+	int retval;
 
-	dev = udevdb_get_dev(path);
-	if (dev != NULL) {
-		strcpy(name, dev->name);
-		goto exit;
+	pos = strrchr(path, '/');
+	while (1) {
+		*pos = '\0';
+		pos = strrchr(path, '/');
+
+		/* don't remove the last one */
+		if ((pos == path) || (pos == NULL))
+			break;
+
+		/* remove if empty */
+		retval = rmdir(path);
+		if (retval) {
+			if (errno == ENOTEMPTY)
+				return 0;
+			dbg("rmdir(%s) failed with error '%s'",
+			    path, strerror(errno));
+			break;
+		}
+		dbg("removed '%s'", path);
 	}
-
-	dbg("'%s' not found in database, falling back on default name", path);
-	temp = strrchr(path, '/');
-	if (temp == NULL)
-		return NULL;
-	strncpy(name, &temp[1], sizeof(name));
-
-exit:
-	dbg("name is '%s'", name);
-	return &name[0];
+	return 0;
 }
 
-/*
- * We also want to clean up any symlinks that were created in create_node()
- */
-static int delete_node(char *name)
+static int delete_node(struct udevice *dev)
 {
 	char filename[255];
 	int retval;
 
 	strncpy(filename, udev_root, sizeof(filename));
-	strncat(filename, name, sizeof(filename));
+	strncat(filename, dev->name, sizeof(filename));
 
-	dbg("unlinking '%s'", filename);
+	dbg("unlinking node '%s'", filename);
 	retval = unlink(filename);
 	if (retval) {
 		dbg("unlink(%s) failed with error '%s'",
@@ -83,49 +79,48 @@
 	}
 
 	/* remove subdirectories */
-	if (strchr(name, '/')) {
-		char *pos;
+	if (strchr(dev->name, '/'))
+		delete_path(filename);
 
-		pos = strrchr(filename, '/');
-		while (1) {
-			*pos = 0x00;
-			pos = strrchr(filename, '/');
-
-			/* don't remove the last one */
-			if ((pos == filename) || (pos == NULL))
-				break;
-
-			/* remove if empty */
-			retval = rmdir(filename);
-			if (retval) {
-				if (errno == ENOTEMPTY)
-					return 0;
-				dbg("rmdir(%s) failed with error '%s'",
-				    filename, strerror(errno));
-				break;
-			}
-			dbg("removed '%s'", filename);
+	if (*dev->symlink) {
+		strncpy(filename, udev_root, sizeof(filename));
+		strncat(filename, dev->symlink, sizeof(filename));
+		dbg("unlinking symlink '%s'", filename);
+		retval = unlink(filename);
+		if (retval) {
+			dbg("unlink(%s) failed with error '%s'",
+				filename, strerror(errno));
+			return retval;
+		}
+		if (strchr(dev->symlink, '/')) {
+			delete_path(filename);
 		}
 	}
+
 	return retval;
 }
 
-int udev_remove_device(char *device, char *subsystem)
+/*
+ * Look up the sysfs path in the database to see if we have named this device
+ * something different from the kernel name.  If we have, us it.  If not, use
+ * the default kernel name for lack of anything else to know to do.
+ */
+int udev_remove_device(char *path, char *subsystem)
 {
-	char *name;
-	int retval = 0;
+	char name[100];
+	struct udevice *dev;
+	char *temp;
 
-	name = get_name(device, 0, 0);
-	if (name == NULL) {
-		dbg ("get_name failed");
-		retval = -ENODEV;
-		goto exit;
+	dev = udevdb_get_dev(path);
+	if (dev == NULL) {
+		dbg("'%s' not found in database, falling back on default name", path);
+		temp = strrchr(path, '/');
+		if (temp == NULL)
+			return -ENODEV;
+		strncpy(name, &temp[1], sizeof(name));
 	}
 
-	udevdb_delete_dev(device);
-
-	return delete_node(name);
-
-exit:
-	return retval;
+	dbg("name is '%s'", dev->name);
+	udevdb_delete_dev(path);
+	return delete_node(dev);
 }
diff -Nru a/udev.h b/udev.h
--- a/udev.h	Sun Dec  7 06:58:47 2003
+++ b/udev.h	Sun Dec  7 06:58:47 2003
@@ -64,6 +64,7 @@
 	int major;
 	int minor;
 	mode_t mode;
+	char symlink[NAME_SIZE];
 
 	/* fields that help us in building strings */
 	unsigned char bus_id[SYSFS_NAME_LEN];

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

* Re: [udev] experimental (very simple) SYMLINK creation
  2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
  2003-12-05 15:45 ` Kay Sievers
  2003-12-07  6:02 ` Kay Sievers
@ 2003-12-07 17:45 ` Kay Sievers
  2003-12-07 17:58 ` Marco d'Itri
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Kay Sievers @ 2003-12-07 17:45 UTC (permalink / raw)
  To: linux-hotplug

[-- Attachment #1: Type: text/plain, Size: 813 bytes --]

On Sun, Dec 07, 2003 at 01:35:08AM -0800, Greg KH wrote:
> > > On Fri, Dec 05, 2003 at 05:24:33AM +0100, Kay Sievers wrote:
> > > > here is a experimental symlink creation patch - for discussion,
> > > > in which direction we should go.
> 
> Very nice, applied.  I should wait a few days all the time before
> applying your patches :)

Oh, so I have the time to discuss it with myself :)

What do you think? Should we allow multiple symlinks? Separated by which character?
So we may simply loop over the field and create more than one:

..., SYMLINK="webcam%n:camera/%n:v4l/video%n"


thanks,
Kay


Attached is a trivial cleanup patch:

01-cleanup_man+remove_symlink_comment.diff
  remove "want symlinks" text from udev-add.c
  mention SYMLINK in man page
  man page format cleanup
  man page example for SYMLINK

[-- Attachment #2: 01-cleanup_man+remove_symlink_comment.diff --]
[-- Type: text/plain, Size: 5644 bytes --]

diff -Nru a/udev-add.c b/udev-add.c
--- a/udev-add.c	Sun Dec  7 16:30:52 2003
+++ b/udev-add.c	Sun Dec  7 16:30:52 2003
@@ -53,18 +53,15 @@
 static int get_major_minor(struct sysfs_class_device *class_dev, struct udevice *udev)
 {
 	int retval = -ENODEV;
-
 	char *dev;
 
 	dev = sysfs_get_value_from_attributes(class_dev->directory->attributes, "dev");
 	if (dev == NULL)
 		goto exit;
-
 	dbg("dev='%s'", dev);
 
 	if (sscanf(dev, "%u:%u", &udev->major, &udev->minor) != 2)
 		goto exit;
-
 	dbg("found major=%d, minor=%d", udev->major, udev->minor);
 
 	retval = 0;
@@ -100,10 +97,6 @@
 	return 0;
 }
 
-/*
- * we possibly want to add some symlinks here
- * only numeric owner/group id's are supported
- */
 static int create_node(struct udevice *dev)
 {
 	char filename[255];
@@ -115,7 +108,6 @@
 	int i;
 	int tail;
 
-
 	strncpy(filename, udev_root, sizeof(filename));
 	strncat(filename, dev->name, sizeof(filename));
 
@@ -238,7 +230,6 @@
 
 	strcpy(dev_path, sysfs_path);
 	strcat(dev_path, device_name);
-
 	dbg("looking at '%s'", dev_path);
 
 	/* open up the sysfs class device for this thing... */
diff -Nru a/udev.8 b/udev.8
--- a/udev.8	Sun Dec  7 16:30:52 2003
+++ b/udev.8	Sun Dec  7 16:30:52 2003
@@ -63,7 +63,7 @@
 .I 0666
 .br
 .P
-A sample \fIudev.conf\fP might look like this:
+.RI "A sample " udev.conf " might look like this:
 .sp
 .nf
 # udev_root - where in the filesystem to place the device nodes
@@ -85,7 +85,7 @@
 .P
 The rules for udev to use when naming devices may specified at
 .I /etc/udev/udev.rules
-or specified by the 
+or specified by the
 .I udev_rules
 value in the 
 .I /etc/udev/udev.conf
@@ -94,73 +94,73 @@
 Every line in the rules file define the mapping between device attributes and
 the device file name. It starts with a keyword defining the method used to
 match, followed by one ore more keys to compare and the filename for the
-device. If no matching configuration is found, the default kernel device name
+device. Optional the name for a symlink targeting the node may specified.
+.br
+If no matching configuration is found, the default kernel device name
 is used.
 .P
 The line format is:
 .sp
-.I method, key,[key,...] name
+.I method, key,[key,...] name [, symlink]
 .sp
 where valid methods with corresponding keys are:
 .TP
 .B CALLOUT
 calling external program, that returns a string to match
 .br
-keys: \fBBUS\fP, \fBPROGRAM\fP, \fBID\fP
+.RB "keys: " BUS ", " PROGRAM ", " ID
 .TP
 .B LABEL
 device label or serial number, like USB serial number, SCSI UUID or
 file system label
 .br
-keys: \fBBUS\fP, \fIsysfs_attribute\fP
+.RB "keys: " BUS ", "
+.I sysfs_attribute
 .TP
 .B NUMBER
 device number on the bus, like PCI bus id
 .br
-keys: \fBBUS\fP, \fBID\fP
+.RB "keys: " BUS ", " ID
 .TP
 .B TOPOLOGY
 device position on bus, like physical port of USB device
 .br
-keys: \fBBUS\fP, \fBPLACE\fP
+.RB "keys: " BUS ", " PLACE
 .TP
 .B REPLACE
 string replacement of the kernel device name
 .br
-key: \fBKERNEL_NAME\fP
+.RB "key: " KERNEL_NAME
 .P
 The methods are applied in the following order:
-.BR CALLOUT ", " LABEL ", " NUMBER ",  " TOPOLOGY ", " REPLACE "."
+.BR CALLOUT ", " LABEL ", " NUMBER ", " TOPOLOGY ", " REPLACE "."
 .P
-The 
-.B NAME 
-and 
-.B PROGRAM 
+.RB "The " NAME " ," SYMLINK " and " PROGRAM
 fields support simple printf-like string substitution:
 .TP
 .B %n
-the "kernel number" of the device
+The "kernel number" of the device.
 for example, 'sda3' has a "kernel number" of '3'
 .TP
 .B %M
-the kernel major number for the device
+The kernel major number for the device.
 .TP
 .B %m
-the kernel minor number for the device
+The kernel minor number for the device.
 .TP
 .B %b
-the bus id for the device
+The bus id for the device.
 .TP
 .B %c
-the CALLOUT program returned string
-(this does not work within the PROGRAM field for the obvious reason.)
+The CALLOUT program returned string.
+(This does not work within the PROGRAM field for the obvious reason.)
 .TP
 .B %D
 Use the devfs style disk name for this device.
 For partitions, this will result in 'part%n'
-If this is not a partition, it will result in 'disk'
+If this is not a partition, it will result in 'disk'.
 .P
-A sample \fIudev.rules\fP might look like this:
+.RI "A sample " udev.rules " might look like this:"
 .sp
 .nf
 # if /sbin/scsi_id returns "OEM 0815" device will be called disk1
@@ -178,15 +178,15 @@
 # ttyUSB1 should always be called pda
 REPLACE, KERNEL="ttyUSB1", NAME="pda"
 
-# USB webcams to be called webcam0, webcam1, ...
-LABEL, BUS="usb", model="WebCam Version 3", NAME="webcam%n"
+# USB webcams with symlinks to be called webcam0, webcam1, ...
+LABEL, BUS="usb", model="WebCam Version 3", NAME="video%n", SYMLINK="webcam%n"
 .fi
 .P
 Permissions and ownership for the created device files may specified at
 .I /etc/udev/udev.permissions
-or specified by the 
+or specified by the
 .I udev_permission
-value in the 
+value in the
 .I /etc/udev/udev.conf
 file.
 .br
@@ -197,10 +197,9 @@
 If
 .B udev
 was built using klibc or is used before the user database is accessible (e.g.
-.B initrd
-), only numeric owner and group values may be used.
+.BR initrd "(4)), only numeric owner and group values may be used."
 .sp
-A sample \fIudev.permissions\fP might look like this:
+.RI "A sample " udev.permissions " might look like this:"
 .sp
 .nf
 #name:user:group:mode
@@ -227,8 +226,6 @@
 following the '[' is a '!' then any character not enclosed is matched.
 .SH "FILES"
 .nf
-.ft B
-.ft
 /sbin/udev                           udev program
 /etc/udev/*                          udev config files
 /etc/hotplug.d/default/udev.hotplug  hotplug symlink to udev program

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

* Re: [udev] experimental (very simple) SYMLINK creation
  2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
                   ` (2 preceding siblings ...)
  2003-12-07 17:45 ` Kay Sievers
@ 2003-12-07 17:58 ` Marco d'Itri
  2003-12-10  0:43 ` Greg KH
  2003-12-10  1:06 ` Greg KH
  5 siblings, 0 replies; 8+ messages in thread
From: Marco d'Itri @ 2003-12-07 17:58 UTC (permalink / raw)
  To: linux-hotplug

On Dec 07, Kay Sievers <kay.sievers@vrfy.org> wrote:

 >What do you think? Should we allow multiple symlinks? Separated by which character?
Yes! And again, it should be able to define symlinks on a different line
than the one with the definition of the device name.

 >So we may simply loop over the field and create more than one:
 >
 >..., SYMLINK="webcam%n:camera/%n:v4l/video%n"
Probably a space character would be a better separator, the odds you
want to use one in a device name are much lower.

-- 
ciao, |
Marco | [3500 uniyiB8SzEyTY]


-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id\x1278&alloc_id371&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] 8+ messages in thread

* Re: [udev] experimental (very simple) SYMLINK creation
  2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
                   ` (3 preceding siblings ...)
  2003-12-07 17:58 ` Marco d'Itri
@ 2003-12-10  0:43 ` Greg KH
  2003-12-10  1:06 ` Greg KH
  5 siblings, 0 replies; 8+ messages in thread
From: Greg KH @ 2003-12-10  0:43 UTC (permalink / raw)
  To: linux-hotplug

On Sun, Dec 07, 2003 at 06:45:43PM +0100, Kay Sievers wrote:
> On Sun, Dec 07, 2003 at 01:35:08AM -0800, Greg KH wrote:
> > > > On Fri, Dec 05, 2003 at 05:24:33AM +0100, Kay Sievers wrote:
> > > > > here is a experimental symlink creation patch - for discussion,
> > > > > in which direction we should go.
> > 
> > Very nice, applied.  I should wait a few days all the time before
> > applying your patches :)
> 
> Oh, so I have the time to discuss it with myself :)
> 
> What do you think? Should we allow multiple symlinks? Separated by which character?
> So we may simply loop over the field and create more than one:
> 
> ..., SYMLINK="webcam%n:camera/%n:v4l/video%n"

Hm, I don't really think that I would ever need more than one symlink,
but hey, it can't hurt to add support for it :)

> Attached is a trivial cleanup patch:
> 
> 01-cleanup_man+remove_symlink_comment.diff
>   remove "want symlinks" text from udev-add.c
>   mention SYMLINK in man page
>   man page format cleanup
>   man page example for SYMLINK

Applied, thanks.

greg k-h


-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id\x1278&alloc_id371&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] 8+ messages in thread

* Re: [udev] experimental (very simple) SYMLINK creation
  2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
                   ` (4 preceding siblings ...)
  2003-12-10  0:43 ` Greg KH
@ 2003-12-10  1:06 ` Greg KH
  5 siblings, 0 replies; 8+ messages in thread
From: Greg KH @ 2003-12-10  1:06 UTC (permalink / raw)
  To: linux-hotplug

On Sun, Dec 07, 2003 at 06:58:51PM +0100, Marco d'Itri wrote:
> On Dec 07, Kay Sievers <kay.sievers@vrfy.org> wrote:
> 
>  >What do you think? Should we allow multiple symlinks? Separated by which character?
> Yes! And again, it should be able to define symlinks on a different line
> than the one with the definition of the device name.

Yes, this will be necessary.  Just like permissions, we'll probably need
a different config file (as we are having one type of rule per file...)

thanks,

greg k-h


-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id\x1278&alloc_id371&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] 8+ messages in thread

end of thread, other threads:[~2003-12-10  1:06 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-12-05  7:26 [udev] experimental (very simple) SYMLINK creation Olaf Hering
2003-12-05 15:45 ` Kay Sievers
2003-12-07  6:02 ` Kay Sievers
2003-12-07 17:45 ` Kay Sievers
2003-12-07 17:58 ` Marco d'Itri
2003-12-10  0:43 ` Greg KH
2003-12-10  1:06 ` Greg KH
  -- strict thread matches above, loose matches on Subject: below --
2003-12-05  4:24 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).