Skip to contentSkip to conversation

pattern matching for namedev

udev Kay Sievers 1 participant 1 message Dec 3, 2003

lore
Share & tools
lore
#0 lore raw

As promised yesterday, here is a patch to implement a more advanced pattern matching instead of the simple '*'.

We can remove the "tty"="tty" line from udev.rules now and replace "tty*" by "tty[0-9]*" to catch only the vc's.

thanks,
Kay

02-the-real-pattern-matching.diff
implement pattern matching in namedev
'*' - to match zero or more chars
'?' - to match exactly one char
'[]' - character classes with ranges '[0-9]'and negation [!A]

namedev.c +53 -14
diff -Nru a/namedev.c b/namedev.c
@@ -40,17 +40,56 @@
 
 LIST_HEAD(config_device_list);
 
-/* s2 may end with '*' to match everything */
-static int strncmp_wildcard(char *s1, char *s2, int max)
+/* compare string with pattern (supports * ? [0-9] [!A-Z]) */
+static int strcmp_pattern(const char *p, const char *s)
 {
-	int len = strlen(s2);
-	if (len > max)
-		len = max;
-	if (s2[len-1] == '*')
-		len--;
-	else
-		len = max;
-	return strncmp(s1, s2, len);
+	if (*s == '\0') {
+		while (*p == '*')
+			p++;
+		return (*p != '\0');
+	}
+	switch (*p) {
+	case '[':
+		{
+			int not = 0;
+			p++;
+			if (*p == '!') {
+				not = 1;
+				p++;
+			}
+			while (*p && (*p != ']')) {
+				int match = 0;
+				if (p[1] == '-') {
+					if ((*s >= *p) && (*s <= p[2]))
+						match = 1;
+					p += 3;
+				} else {
+					match = (*p == *s);
+					p++;
+				}
+				if (match ^ not) {
+					while (*p && (*p != ']'))
+						p++;
+					return strcmp_pattern(p+1, s+1);
+				}
+			}
+		}
+		break;
+	case '*':
+		if (strcmp_pattern(p, s+1))
+			return strcmp_pattern(p+1, s);
+		return 0;
+	case '\0':
+		if (*s == '\0') {
+			return 0;
+		}
+		break;
+	default:
+		if ((*p == *s) || (*p == '?'))
+			return strcmp_pattern(p+1, s+1);
+		break;
+	}
+	return 1;
 }
 
 #define copy_var(a, b, var)		\
@@ -69,7 +108,7 @@
 	/* update the values if we already have the device */
 	list_for_each(tmp, &config_device_list) {
 		struct config_device *dev = list_entry(tmp, struct config_device, node);
-		if (strncmp_wildcard(dev->name, new_dev->name, sizeof(dev->name)))
+		if (strcmp_pattern(new_dev->name, dev->name))
 			continue;
 		if (strncmp(dev->bus, new_dev->bus, sizeof(dev->name)))
 			continue;
@@ -282,7 +321,7 @@
 		apply_format(udev, dev->exec_program);
 		if (exec_callout(dev, udev->callout_value, NAME_SIZE))
 			continue;
-		if (strncmp_wildcard(udev->callout_value, dev->id, NAME_SIZE) != 0)
+		if (strcmp_pattern(dev->id, udev->callout_value) != 0)
 			continue;
 		strfieldcpy(udev->name, dev->name);
 		if (dev->mode != 0) {
@@ -468,7 +507,7 @@
 			continue;
 
 		dbg("compare name '%s' with '%s'", dev->kernel_name, class_dev->name);
-		if (strncmp_wildcard(class_dev->name, dev->kernel_name, NAME_SIZE) != 0)
+		if (strcmp_pattern(dev->kernel_name, class_dev->name) != 0)
 			continue;
 
 		strfieldcpy(udev->name, dev->name);
@@ -498,7 +537,7 @@
 	list_for_each(tmp, &config_device_list) {
 		dev = list_entry(tmp, struct config_device, node);
 		len = strlen(dev->name);
-		if (strncmp_wildcard(class_dev->name, dev->name, sizeof(dev->name)))
+		if (strcmp_pattern(dev->name, class_dev->name))
 			continue;
 		if (dev->mode != 0) {
 			dbg("found permissions for '%s'", class_dev->name);
test/udev-test.pl +24 -2
diff -Nru a/test/udev-test.pl b/test/udev-test.pl
@@ -51,7 +51,7 @@
 EOF
 	},
 	{
-		desc     => "catch device by wildcard",
+		desc     => "catch device by *",
 		subsys   => "tty",
 		devpath  => "class/tty/ttyUSB0",
 		expected => "visor/0" ,
@@ -60,6 +60,28 @@
 EOF
 	},
 	{
+		desc     => "catch device by ?",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "visor/0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB??*", NAME="visor/%n-1"
+REPLACE, KERNEL="ttyUSB??", NAME="visor/%n-2"
+REPLACE, KERNEL="ttyUSB?", NAME="visor/%n"
+EOF
+	},
+	{
+		desc     => "catch device by character class",
+		subsys   => "tty",
+		devpath  => "class/tty/ttyUSB0",
+		expected => "visor/0" ,
+		conf     => <<EOF
+REPLACE, KERNEL="ttyUSB[A-Z]*", NAME="visor/%n-1"
+REPLACE, KERNEL="ttyUSB?[0-9]", NAME="visor/%n-2"
+REPLACE, KERNEL="ttyUSB[0-9]*", NAME="visor/%n"
+EOF
+	},
+	{
 		desc     => "replace kernel name",
 		subsys   => "tty",
 		devpath  => "class/tty/ttyUSB0",
@@ -96,7 +118,7 @@
 EOF
 	},
 	{
-		desc     => "callout result substitution, only last should match",
+		desc     => "callout result substitution",
 		subsys   => "block",
 		devpath  => "block/sda/sda3",
 		expected => "special-device-3" ,