- if (rule->test.operation == KEY_OP_MATCH ||
- rule->test.operation == KEY_OP_NOMATCH) {
- char filename[UTIL_PATH_SIZE];
- char *subsys;
- char *sysname;
- char *attrib;
- struct stat statbuf;
- int match;
-
- util_strlcpy(filename, key_val(rule, &rule->test), sizeof(filename));
- udev_rules_apply_format(event, filename, sizeof(filename));
-
- if (split_subsys_sysname(event->udev, filename, &subsys, &sysname, &attrib) == 0) {
- struct udev_device *d;
- d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
- if (d != NULL) {
- util_strlcpy(filename, udev_device_get_syspath(d), sizeof(filename));
- if (attrib != NULL) {
- util_strlcat(filename, "/", sizeof(filename));
- util_strlcat(filename, attrib, sizeof(filename));
+ if (strncasecmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 ||
+ strncasecmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
+ 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;
+ }
+ if (strncmp(attr, "device/", 7) == 0)
+ err(rules->udev, "the 'device' link may not be available in a future kernel, "
+ "please fix it in %s:%u", filename, lineno);
+ else if (strstr(attr, "../") != NULL)
+ err(rules->udev, "do not reference parent sysfs directories directly, "
+ "it may break with a future kernel, please fix it in %s:%u", filename, lineno);
+ rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
+ valid = 1;
+ continue;
+ }
+
+ if (strncasecmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
+ attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
+ if (attr == NULL) {
+ err(rules->udev, "error parsing ENV attribute\n");
+ goto invalid;
+ }
+ if (strncmp(attr, "PHYSDEV", 7) == 0)
+ physdev = 1;
+ if (op < OP_MATCH_MAX) {
+ if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0)
+ goto invalid;
+ } else {
+ if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
+ goto invalid;
+ }
+ valid = 1;
+ continue;
+ }
+
+ if (strcasecmp(key, "PROGRAM") == 0) {
+ rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
+ valid = 1;
+ continue;
+ }
+
+ if (strcasecmp(key, "RESULT") == 0) {
+ if (op > OP_MATCH_MAX) {
+ err(rules->udev, "invalid RESULT operation\n");
+ goto invalid;
+ }
+ rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
+ valid = 1;
+ continue;
+ }
+
+ if (strncasecmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
+ attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1);
+ if (attr != NULL && strstr(attr, "program")) {
+ dbg(rules->udev, "IMPORT will be executed\n");
+ rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
+ valid = 1;
+ } 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);
+ valid = 1;
+ } 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);
+ valid = 1;
+ } else {
+ /* figure it out if it is executable */
+ char file[UTIL_PATH_SIZE];
+ char *pos;
+ struct stat statbuf;
+
+ util_strlcpy(file, value, sizeof(file));
+ pos = strchr(file, ' ');
+ if (pos)
+ pos[0] = '\0';
+
+ /* allow programs in /lib/udev called without the path */
+ if (strchr(file, '/') == NULL) {
+ util_strlcpy(file, UDEV_PREFIX "/lib/udev/", sizeof(file));
+ util_strlcat(file, value, sizeof(file));
+ pos = strchr(file, ' ');
+ if (pos)
+ pos[0] = '\0';
+ }
+
+ dbg(rules->udev, "IMPORT auto mode for '%s'\n", file);
+ if (!lstat(file, &statbuf) && (statbuf.st_mode & S_IXUSR)) {
+ dbg(rules->udev, "IMPORT will be executed (autotype)\n");
+ rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
+ valid = 1;
+ } else {
+ dbg(rules->udev, "IMPORT will be included as file (autotype)\n");
+ rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
+ valid = 1;