chiark / gitweb /
[PATCH] pattern matching for namedev
authorkay.sievers@vrfy.org <kay.sievers@vrfy.org>
Wed, 3 Dec 2003 14:22:53 +0000 (06:22 -0800)
committerGreg KH <gregkh@suse.de>
Wed, 27 Apr 2005 04:13:05 +0000 (21:13 -0700)
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.

  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
test/udev-test.pl

index a81721a9cf4378cd45f2517e8701ebde98f211f7..b9e099413bc3bec815d860f11b730ddb6227adf2 100644 (file)
--- a/namedev.c
+++ b/namedev.c
 
 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 @@ int add_config_dev(struct config_device *new_dev)
        /* 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 @@ static int do_callout(struct sysfs_class_device *class_dev, struct udevice *udev
                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 @@ static int do_replace(struct sysfs_class_device *class_dev, struct udevice *udev
                        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 @@ static void do_kernelname(struct sysfs_class_device *class_dev, struct udevice *
        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);
index 8af09a027b99555f372fd713528bd92b3718f4e4..47190f6e5de217ebf88db1d5dd57144f7ba04724 100644 (file)
@@ -51,12 +51,34 @@ LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="boot_disk%n"
 EOF
        },
        {
-               desc     => "catch device by wildcard",
+               desc     => "catch device by *",
                subsys   => "tty",
                devpath  => "class/tty/ttyUSB0",
                expected => "visor/0" ,
                conf     => <<EOF
 REPLACE, KERNEL="ttyUSB*", NAME="visor/%n"
+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
        },
        {
@@ -96,7 +118,7 @@ TOPOLOGY, BUS="scsi", PLACE="0:0:0:0", NAME="Major:%M:minor:%m:kernelnumber:%n:b
 EOF
        },
        {
-               desc     => "callout result substitution, only last should match",
+               desc     => "callout result substitution",
                subsys   => "block",
                devpath  => "block/sda/sda3",
                expected => "special-device-3" ,