Skip to contentSkip to conversation

compatibility symlinks for udev

PATCH In review David Zeuthen 3 participants 6 messages Sep 6, 2004 – Sep 14, 2004

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 compatibility symlinks for udev

Hey Greg,

Here's a patch against udev-030 that can help create compatibility symlinks like /dev/cdrom, /dev/cdrom1 etc. The patch introduces a new substitution type %C (for Compatibility) that can be used as follows

        KERNEL="sr*", NAME="%k", SYMLINK="cdrom%C"
        KERNEL="scd*", NAME="%k", SYMLINK="cdrom%C"
        KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%C"
        KERNEL="fd[0-9]", NAME="%k", SYMLINK="floppy%C"
        KERNEL="hd[a-z]", PROGRAM="/home/david/udev_ide_cdrom_or_floppy.sh %k", NAME="%k", SYMLINK="%c%C"
        KERNEL="fd[0-9]", NAME="%k", SYMLINK="floppy%C"

%C will be substitued with nothing if the text prior to the %C doesn't exist, otherwise it will be substituted with the minimal positive integer such that text prior to %C and the integer doesn't exist. Pretty basic.

Together with a simple helper script (that can be removed as soon as IDE exports the type in sysfs; alternatively this is trivial to write in C for e.g. early boot)

#!/bin/sh
TYPE=cat /proc/ide/$1/media
if test "$TYPE" = "cdrom"; then
echo -n cdrom
exit 0
elif test "$TYPE" = "floppy"; then
echo -n floppy
exit 0
fi
exit 1

I get the following symlinks

        [root@laptop udev]# ls -l floppy
        lrwxrwxrwx  1 root root 3 Sep  6 16:29 floppy -> hdc
        [root@laptop udev]# ls -l cdrom*
        lrwxrwxrwx  1 root root 3 Sep  6 16:29 cdrom -> hdd
        lrwxrwxrwx  1 root root 3 Sep  6 16:29 cdrom1 -> sr0

which I think is nice (... as far as programs relying on names of device nodes is nice, ahem). While the patch is somewhat against the spirit of udev it's very useful for maintaining compatibility with old software. People who depend and care about what /dev/cdrom%d is can always write exact rules to match them perfectly.

I hope you will apply this patch.

Thanks,
David

namedev.c +40 -0
@@ -42,6 +42,7 @@
 #include "logging.h"
 #include "namedev.h"
 #include "klibc_fixups.h"
+#include "udevdb.h"
 
 static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, char *attr);
 
@@ -179,6 +180,37 @@ static int get_format_len(char **str)
 	return -1;
 }
 
+/** Finds the lowest positive N such that <name>N isn't present in 
+ *  $(udevroot) either as a file or a symlink.
+ *
+ *  @param  name                Name to check for
+ *  @return                     0 if <name> didn't exist and N otherwise.
+ */
+static unsigned int find_free_number (struct udevice *udev, char *name)
+{
+	char temp[NAME_SIZE];
+	char path[NAME_SIZE];
+	struct udevice dev;
+	int result;
+
+	/* have to sweep the database for each lookup */
+	result = 0;
+	strncpy(temp, name, sizeof (temp));
+	while (1) {
+		if (udevdb_get_dev_byname(temp, path, &dev) != 0)
+			goto found;
+		/* symlink might be stale if $(udevroot) isn't cleaned; check
+		 * on major/minor to see if it's the same device
+		 */
+		if (dev.major == udev->major && dev.minor == udev->minor)
+			goto found;
+		snprintf (temp, sizeof(temp), "%s%d", name, ++result);
+	}
+
+found:
+	return result;
+}
+
 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
 			 struct sysfs_class_device *class_dev,
 			 struct sysfs_device *sysfs_device)
@@ -195,6 +227,7 @@ static void apply_format(struct udevice 
 	char *rest;
 	int slen;
 	struct sysfs_attribute *tmpattr;
+	unsigned int next_free_number;
 
 	pos = string;
 	while (1) {
@@ -284,6 +317,13 @@ static void apply_format(struct udevice 
 			strfieldcatmax(string, "%", maxsize);
 			pos++;
 			break;
+		case 'C':
+			next_free_number = find_free_number(udev, string);
+			if (next_free_number > 0) {
+				snprintf(temp2, sizeof(temp2), "%d", next_free_number);
+				strfieldcatmax(string, temp2, maxsize);
+			}
+			break;
 		default:
 			dbg("unknown substitution type '%%%c'", c);
 			break;
#1 lore raw

On Mon, 2004-09-06 at 16:46 +0200, David Zeuthen wrote:

Nice, I like it. It's a easy way to group device nodes of the same type, but coming from different kernel subsystems.

Quoted 3 lines

Here's a patch against udev-030 that can help create compatibility symlinks like /dev/cdrom, /dev/cdrom1 etc. The patch introduces a new substitution type %C (for Compatibility) that can be used as follows

I suggest using %e for enumeration here, cause "compatibility" can easily be misunderstood.

Quoted 4 lines

Together with a simple helper script (that can be removed as soon as IDE exports the type in sysfs; alternatively this is trivial to write in C for e.g. early boot)

Quoted 10 lines

#!/bin/sh
TYPE=cat /proc/ide/$1/media
if test "$TYPE" = "cdrom"; then
echo -n cdrom
exit 0
elif test "$TYPE" = "floppy"; then
echo -n floppy
exit 0
fi
exit 1

I will look into it, if it's easy to add to sysfs.

And we need a few lines added to the man page at udev.8.in :)

Thanks,
Kay

-------------------------------------------------------
This SF.Net email is sponsored by BEA Weblogic Workshop FREE Java Enterprise J2EE developer tools!
Get your free copy of BEA WebLogic Workshop 8.1 today.
http://ads.osdn.com/?ad_idP47&alloc_id808&op=click
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

#2 lore raw
In reply to David Zeuthen
Quoted 5 lines · Kay Sievers

On Mon, 2004-09-06 at 16:46 +0200, David Zeuthen wrote:

Nice, I like it. It's a easy way to group device nodes of the same type, but coming from different kernel subsystems.

That's a good way of putting it, yeah.

Quoted 7 lines
Quoted 3 lines

Here's a patch against udev-030 that can help create compatibility symlinks like /dev/cdrom, /dev/cdrom1 etc. The patch introduces a new substitution type %C (for Compatibility) that can be used as follows

I suggest using %e for enumeration here, cause "compatibility" can easily be misunderstood.

Good point, I've changed that.

Quoted 2 lines

And we need a few lines added to the man page at udev.8.in :)

Done. I've also added an example.

Also, Kay pointed out offlist that the rules can be written to not require a shell script; this actually works

        KERNEL="sr*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="scd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="\%k", SYMLINK="cdrom%e"
        KERNEL="fd[0-9]", NAME="%k", SYMLINK="floppy%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="floppy", NAME=\"%k", SYMLINK="floppy%e"

New patch is attached.

David

namedev.c +40 -0
@@ -42,6 +42,7 @@
 #include "logging.h"
 #include "namedev.h"
 #include "klibc_fixups.h"
+#include "udevdb.h"
 
 static struct sysfs_attribute *find_sysfs_attribute(struct sysfs_class_device *class_dev, struct sysfs_device *sysfs_device, char *attr);
 
@@ -179,6 +180,37 @@ static int get_format_len(char **str)
 	return -1;
 }
 
+/** Finds the lowest positive N such that <name>N isn't present in 
+ *  $(udevroot) either as a file or a symlink.
+ *
+ *  @param  name                Name to check for
+ *  @return                     0 if <name> didn't exist and N otherwise.
+ */
+static unsigned int find_free_number (struct udevice *udev, char *name)
+{
+	char temp[NAME_SIZE];
+	char path[NAME_SIZE];
+	struct udevice dev;
+	int result;
+
+	/* have to sweep the database for each lookup */
+	result = 0;
+	strncpy(temp, name, sizeof (temp));
+	while (1) {
+		if (udevdb_get_dev_byname(temp, path, &dev) != 0)
+			goto found;
+		/* symlink might be stale if $(udevroot) isn't cleaned; check
+		 * on major/minor to see if it's the same device
+		 */
+		if (dev.major == udev->major && dev.minor == udev->minor)
+			goto found;
+		snprintf (temp, sizeof(temp), "%s%d", name, ++result);
+	}
+
+found:
+	return result;
+}
+
 static void apply_format(struct udevice *udev, char *string, size_t maxsize,
 			 struct sysfs_class_device *class_dev,
 			 struct sysfs_device *sysfs_device)
@@ -195,6 +227,7 @@ static void apply_format(struct udevice 
 	char *rest;
 	int slen;
 	struct sysfs_attribute *tmpattr;
+	unsigned int next_free_number;
 
 	pos = string;
 	while (1) {
@@ -284,6 +317,13 @@ static void apply_format(struct udevice 
 			strfieldcatmax(string, "%", maxsize);
 			pos++;
 			break;
+		case 'e':
+			next_free_number = find_free_number(udev, string);
+			if (next_free_number > 0) {
+				snprintf(temp2, sizeof(temp2), "%d", next_free_number);
+				strfieldcatmax(string, temp2, maxsize);
+			}
+			break;
 		default:
 			dbg("unknown substitution type '%%%c'", c);
 			break;
udev.8.in +15 -0
@@ -272,6 +272,13 @@ all remaining parts of the result string
 .BI %s{ filename }
 The content of a sysfs attribute.
 .TP
+.B %e
+If a device node already exists with the name, the smallest positive
+decimal integer N is substituted such that the resulting name doesn't
+match an existing device node. Otherwise nothing is substituted. This
+can be used to create compatibility symlinks and enumerate devices of
+the same type originating from different kernel subsystems.
+.TP
 .B %%
 The '%' character itself.
 .P
@@ -302,6 +309,14 @@ KERNEL="ttyUSB1", NAME="pda", SYMLINK="p
 
 # multiple USB webcams with symlinks to be called webcam0, webcam1, ...
 BUS="usb", SYSFS{model}="XV3", NAME="video%n", SYMLINK="webcam%n"
+
+# grouping of optical drives from multiple kernel subsystems
+KERNEL="sr*", NAME="%k", SYMLINK="cdrom%e"
+KERNEL="scd*", NAME="%k", SYMLINK="cdrom%e"
+KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%e"
+KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom",
+  NAME="%k", SYMLINK="cdrom%e"
+
 .fi
 .P
 The permissions and ownership of the created device file is read from
#3 lore raw
In reply to David Zeuthen
Quoted 27 lines · David Zeuthen
Quoted 5 lines · Kay Sievers

On Mon, 2004-09-06 at 16:46 +0200, David Zeuthen wrote:

Nice, I like it. It's a easy way to group device nodes of the same type, but coming from different kernel subsystems.

That's a good way of putting it, yeah.

Quoted 7 lines
Quoted 3 lines

Here's a patch against udev-030 that can help create compatibility symlinks like /dev/cdrom, /dev/cdrom1 etc. The patch introduces a new substitution type %C (for Compatibility) that can be used as follows

I suggest using %e for enumeration here, cause "compatibility" can easily be misunderstood.

Good point, I've changed that.

Quoted 2 lines

And we need a few lines added to the man page at udev.8.in :)

Done. I've also added an example.

Also, Kay pointed out offlist that the rules can be written to not require a shell script; this actually works

Quoted 8 lines
        KERNEL="sr*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="scd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="\%k", SYMLINK="cdrom%e"
        KERNEL="fd[0-9]", NAME="%k", SYMLINK="floppy%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="floppy", NAME=\"%k", SYMLINK="floppy%e"

New patch is attached.

Nice, I've applied this.

How about sending a patch for the test/udev-test.pl script that adds a test for this new paramater, so we make sure to not break it in the future.

thanks,

greg k-h

-------------------------------------------------------
This SF.Net email is sponsored by: YOU BE THE JUDGE. Be one of 170 Project Admins to receive an Apple iPod Mini FREE for your judgement on who ports your project to Linux PPC the best. Sponsored by IBM.
Deadline: Sept. 13. Go here: http://sf.net/ppc_contest.php
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel

#4 lore raw
In reply to David Zeuthen
Quoted 9 lines · Greg KH
Quoted 8 lines · David Zeuthen
        KERNEL="sr*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="scd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="\%k", SYMLINK="cdrom%e"
        KERNEL="fd[0-9]", NAME="%k", SYMLINK="floppy%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="floppy", NAME=\"%k", SYMLINK="floppy%e"
Quoted 7 lines
Quoted 1 line

New patch is attached.

Nice, I've applied this.

How about sending a patch for the test/udev-test.pl script that adds a test for this new paramater, so we make sure to not break it in the future.

Here are the tests for the enumeration character %e. I've added a option string to be able to do a whole sequence of tests without node removal, so we can skip the "remove" event and get an increasing number to append to the name. After the sequence test the whole directory is cleaned for the next tests.

Thanks,
Kay

===== test/udev-test.pl 1.57 vs edited =====

test/udev-test.pl +86 -3
@@ -1017,6 +1017,74 @@
 BUS="scsi", PROGRAM="/bin/echo -n node link1 link2 link3 link4", RESULT="node *", NAME="%c{1}", SYMLINK="%c{2+}"
 EOF
 	},
+	{
+		desc		=> "enumeration char test (single test)",
+		subsys		=> "block",
+		devpath		=> "/block/sda",
+		exp_name	=> "cdrom",
+		conf		=> <<EOF
+KERNEL="sda", NAME="cdrom%e"
+EOF
+	},
+	{
+		desc		=> "enumeration char test sequence (1/5 keep)",
+		subsys		=> "block",
+		devpath		=> "/block/sda",
+		exp_name	=> "cdrom",
+		option		=> "keep",
+		conf		=> <<EOF
+KERNEL="sda", NAME="cdrom%e"
+EOF
+	},
+	{
+		desc		=> "enumeration char test sequence 2/5 (keep)",
+		subsys		=> "block",
+		devpath		=> "/block/sda/sda1",
+		exp_name	=> "enum",
+		option		=> "keep",
+		conf		=> <<EOF
+KERNEL="sda1", NAME="enum%e"
+EOF
+	},
+	{
+		desc		=> "enumeration char test sequence 3/5 (keep)",
+		subsys		=> "block",
+		devpath		=> "/block/sda/sda2",
+		exp_name	=> "cdrom1",
+		option		=> "keep",
+		conf		=> <<EOF
+KERNEL="sda2", NAME="cdrom%e"
+EOF
+	},
+	{
+		desc		=> "enumeration char test sequence 4/5 (keep)",
+		subsys		=> "block",
+		devpath		=> "/block/sda/sda3",
+		exp_name	=> "enum1",
+		option		=> "keep",
+		conf		=> <<EOF
+KERNEL="sda3", NAME="enum%e"
+EOF
+	},
+	{
+		desc		=> "enumeration char test sequence 5/5 (clean)",
+		subsys		=> "block",
+		devpath		=> "/block/sda/sda4",
+		exp_name	=> "cdrom2",
+		option		=> "clear",
+		conf		=> <<EOF
+KERNEL="sda4", NAME="cdrom%e"
+EOF
+	},
+	{
+		desc		=> "enumeration char test after cleanup (single test)",
+		subsys		=> "block",
+		devpath		=> "/block/sda",
+		exp_name	=> "cdrom",
+		conf		=> <<EOF
+KERNEL="sda", NAME="cdrom%e"
+EOF
+	},
 );
 
 # set env
@@ -1160,6 +1228,11 @@
 		}
 	}
 
+	if (defined($config->{option}) && $config->{option} eq "keep") {
+		print "\n\n";
+		return;
+	}
+
 	udev("remove", $config->{subsys}, $config->{devpath}, \$config->{conf});
 	if ((-e "$PWD/$udev_root$config->{exp_name}") ||
 	    (-l "$PWD/$udev_root$config->{exp_name}")) {
@@ -1175,6 +1248,13 @@
 	} else {
 		print "remove: ok\n\n";
 	}
+
+	if (defined($config->{option}) && $config->{option} eq "clear") {
+		unlink($udev_db);
+		system("rm -rf $udev_root");
+		mkdir($udev_root) || die "unable to create udev_root: $udev_root\n";
+	}
+
 }
 
 # prepare
@@ -1194,9 +1274,13 @@
 if ($ARGV[0]) {
 	# only run one test
 	$test_num = $ARGV[0];
-	print "udev-test will run test number $test_num only\n";
 
-	run_test($tests[$test_num-1], $test_num);
+	if (defined($tests[$test_num-1]->{desc})) {
+		print "udev-test will run test number $test_num only:\n\n";
+		run_test($tests[$test_num-1], $test_num);
+	} else {
+		print "test does not exist.\n";
+	}
 } else {
 	# test all
 	print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
@@ -1204,7 +1288,6 @@
 	foreach my $config (@tests) {
 		run_test($config, $test_num);
 		$test_num++;
-
 	}
 }
 
#5 lore raw
In reply to David Zeuthen
Quoted 18 lines · Kay Sievers
Quoted 9 lines · Greg KH
Quoted 8 lines · David Zeuthen
        KERNEL="sr*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="scd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="pcd*", NAME="%k", SYMLINK="cdrom%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="cdrom", NAME="\%k", SYMLINK="cdrom%e"
        KERNEL="fd[0-9]", NAME="%k", SYMLINK="floppy%e"
        KERNEL="hd[a-z]", PROGRAM="/bin/cat /proc/ide/%k/media", RESULT="floppy", NAME=\"%k", SYMLINK="floppy%e"
Quoted 7 lines
Quoted 1 line

New patch is attached.

Nice, I've applied this.

How about sending a patch for the test/udev-test.pl script that adds a test for this new paramater, so we make sure to not break it in the future.

Quoted 5 lines

Here are the tests for the enumeration character %e. I've added a option string to be able to do a whole sequence of tests without node removal, so we can skip the "remove" event and get an increasing number to append to the name. After the sequence test the whole directory is cleaned for the next tests.

Ah, very nice. Applied, thanks.

greg k-h

-------------------------------------------------------
This SF.Net email is sponsored by: thawte's Crypto Challenge Vl Crack the code and win a Sony DCRHC40 MiniDV Digital Handycam Camcorder. More prizes in the weekly Lunch Hour Challenge. Sign up NOW http://ad.doubleclick.net/clk;10740251;10262165;m
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel