chiark / gitweb /
allow IMPORT{db}="KEY"
[elogind.git] / udev / udev-rules.c
index 07cb4a7fbf8f58d18330232f6b4080e66d1a1160..c4a2724032c8648195b607a6c9a03952a9c8f2de 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
  * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -19,6 +19,7 @@
 #include <stddef.h>
 #include <limits.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <string.h>
 #include <stdio.h>
 #include <fcntl.h>
@@ -140,6 +141,7 @@ enum token_type {
        TK_M_PROGRAM,                   /* val */
        TK_M_IMPORT_FILE,               /* val */
        TK_M_IMPORT_PROG,               /* val */
+       TK_M_IMPORT_DB,                 /* val */
        TK_M_IMPORT_PARENT,             /* val */
        TK_M_RESULT,                    /* val */
        TK_M_MAX,
@@ -270,6 +272,7 @@ static const char *token_str(enum token_type type)
                [TK_M_PROGRAM] =                "M PROGRAM",
                [TK_M_IMPORT_FILE] =            "M IMPORT_FILE",
                [TK_M_IMPORT_PROG] =            "M IMPORT_PROG",
+               [TK_M_IMPORT_DB] =              "M IMPORT_DB",
                [TK_M_IMPORT_PARENT] =          "M IMPORT_PARENT",
                [TK_M_RESULT] =                 "M RESULT",
                [TK_M_MAX] =                    "M MAX",
@@ -336,6 +339,7 @@ static void dump_token(struct udev_rules *rules, struct token *token)
        case TK_M_PROGRAM:
        case TK_M_IMPORT_FILE:
        case TK_M_IMPORT_PROG:
+       case TK_M_IMPORT_DB:
        case TK_M_IMPORT_PARENT:
        case TK_M_RESULT:
        case TK_A_NAME:
@@ -716,7 +720,7 @@ static int import_property_from_string(struct udev_device *dev, char *line)
                entry = udev_device_add_property(dev, key, val);
                /* store in db, skip private keys */
                if (key[0] != '.')
-                       udev_list_entry_set_flag(entry, 1);
+                       udev_list_entry_set_flags(entry, 1);
        }
        return 0;
 }
@@ -784,7 +788,7 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
                        entry = udev_device_add_property(dev, key, val);
                        /* store in db, skip private keys */
                        if (key[0] != '.')
-                               udev_list_entry_set_flag(entry, 1);
+                               udev_list_entry_set_flags(entry, 1);
                }
        }
        return 0;
@@ -1000,6 +1004,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
        case TK_M_PROGRAM:
        case TK_M_IMPORT_FILE:
        case TK_M_IMPORT_PROG:
+       case TK_M_IMPORT_DB:
        case TK_M_IMPORT_PARENT:
        case TK_M_RESULT:
        case TK_A_OWNER:
@@ -1156,6 +1161,9 @@ static int add_rule(struct udev_rules *rules, char *line,
        char *linepos;
        char *attr;
        struct rule_tmp rule_tmp;
+       bool bus_warn = false;
+       bool sysfs_warn = false;
+       bool id_warn = false;
 
        memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
        rule_tmp.rules = rules;
@@ -1240,8 +1248,7 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strcmp(key, "KERNELS") == 0 ||
-                   strcmp(key, "ID") == 0) {
+               if (strcmp(key, "KERNELS") == 0) {
                        if (op > OP_MATCH_MAX) {
                                err(rules->udev, "invalid KERNELS operation\n");
                                goto invalid;
@@ -1250,8 +1257,37 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strcmp(key, "SUBSYSTEMS") == 0 ||
-                   strcmp(key, "BUS") == 0) {
+               if (strcmp(key, "ID") == 0) {
+                       if (!id_warn) {
+                               id_warn = true;
+                               err(rules->udev, "ID= will be removed in a future udev version, "
+                                   "please use KERNEL= to match the event device, or KERNELS= "
+                                   "to match a parent device, in %s:%u\n", filename, lineno);
+                       }
+                       if (op > OP_MATCH_MAX) {
+                               err(rules->udev, "invalid KERNELS operation\n");
+                               goto invalid;
+                       }
+                       rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
+                       continue;
+               }
+
+               if (strcmp(key, "SUBSYSTEMS") == 0) {
+                       if (op > OP_MATCH_MAX) {
+                               err(rules->udev, "invalid SUBSYSTEMS operation\n");
+                               goto invalid;
+                       }
+                       rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
+                       continue;
+               }
+
+               if (strcmp(key, "BUS") == 0) {
+                       if (!bus_warn) {
+                               bus_warn = true;
+                               err(rules->udev, "BUS= will be removed in a future udev version, "
+                                   "please use SUBSYSTEM= to match the event device, or SUBSYSTEMS= "
+                                   "to match a parent device, in %s:%u\n", filename, lineno);
+                       }
                        if (op > OP_MATCH_MAX) {
                                err(rules->udev, "invalid SUBSYSTEMS operation\n");
                                goto invalid;
@@ -1269,8 +1305,7 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 ||
-                   strncmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
+               if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0) {
                        if (op > OP_MATCH_MAX) {
                                err(rules->udev, "invalid ATTRS operation\n");
                                goto invalid;
@@ -1290,6 +1325,26 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
+               if (strncmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
+                       if (!sysfs_warn) {
+                               sysfs_warn = true;
+                               err(rules->udev, "SYSFS{}= will be removed in a future udev version, "
+                                   "please use ATTR{}= to match the event device, or ATTRS{}= "
+                                   "to match a parent device, in %s:%u\n", filename, lineno);
+                       }
+                       if (op > OP_MATCH_MAX) {
+                               err(rules->udev, "invalid ATTRS operation\n");
+                               goto invalid;
+                       }
+                       attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
+                       if (attr == NULL) {
+                               err(rules->udev, "error parsing ATTRS attribute\n");
+                               goto invalid;
+                       }
+                       rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
+                       continue;
+               }
+
                if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
                        attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
                        if (attr == NULL) {
@@ -1328,6 +1383,9 @@ static int add_rule(struct udev_rules *rules, char *line,
                        } else if (attr != NULL && strstr(attr, "file")) {
                                dbg(rules->udev, "IMPORT will be included as file\n");
                                rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
+                       } else if (attr != NULL && strstr(attr, "db")) {
+                               dbg(rules->udev, "IMPORT will include db values\n");
+                               rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
                        } else if (attr != NULL && strstr(attr, "parent")) {
                                dbg(rules->udev, "IMPORT will include the parent values\n");
                                rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
@@ -1780,13 +1838,13 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
                filename_off = add_string(rules, filename);
                /* the offset in the rule is limited to unsigned short */
                if (filename_off < USHRT_MAX)
-                       udev_list_entry_set_flag(file_loop, filename_off);
+                       udev_list_entry_set_flags(file_loop, filename_off);
        }
 
        /* parse list of files */
        udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
                const char *filename = udev_list_entry_get_name(file_loop);
-               unsigned int filename_off = udev_list_entry_get_flag(file_loop);
+               unsigned int filename_off = udev_list_entry_get_flags(file_loop);
 
                if (stat(filename, &statbuf) == 0 && statbuf.st_size > 0)
                        parse_file(rules, filename, filename_off);
@@ -2237,6 +2295,23 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                                goto nomatch;
                                break;
                        }
+               case TK_M_IMPORT_DB:
+                       {
+                               const char *key = &rules->buf[cur->key.value_off];
+                               const char *value;
+
+                               value = udev_device_get_property_value(event->dev_db, key);
+                               if (value != NULL) {
+                                       struct udev_list_entry *entry;
+
+                                       entry = udev_device_add_property(event->dev, key, value);
+                                       udev_list_entry_set_flags(entry, 1);
+                               } else {
+                                       if (cur->key.op != OP_NOMATCH)
+                                               goto nomatch;
+                               }
+                               break;
+                       }
                case TK_M_IMPORT_PARENT:
                        {
                                char import[UTIL_PATH_SIZE];
@@ -2369,7 +2444,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                        entry = udev_device_add_property(event->dev, name, temp_value);
                                        /* store in db, skip private keys */
                                        if (name[0] != '.')
-                                               udev_list_entry_set_flag(entry, 1);
+                                               udev_list_entry_set_flags(entry, 1);
                                } else {
                                        udev_device_add_property(event->dev, name, NULL);
                                }
@@ -2491,7 +2566,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                list_entry = udev_list_entry_add(event->udev, &event->run_list,
                                                                 &rules->buf[cur->key.value_off], NULL, 1, 0);
                                if (cur->key.fail_on_error)
-                                       udev_list_entry_set_flag(list_entry, 1);
+                                       udev_list_entry_set_flags(list_entry, 1);
                                break;
                        }
                case TK_A_GOTO: