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: [udev] experimental (very simple) SYMLINK creation
Date: Fri, 05 Dec 2003 04:24:33 +0000	[thread overview]
Message-ID: <marc-linux-hotplug-107059831725212@msgid-missing> (raw)

[-- 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];

             reply	other threads:[~2003-12-05  4:24 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-12-05  4:24 Kay Sievers [this message]
  -- strict thread matches above, loose matches on Subject: below --
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

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=marc-linux-hotplug-107059831725212@msgid-missing \
    --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).