+ if (op < OP_MATCH_MAX) {
+ rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
+ } else {
+ rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
+ }
+ continue;
+ }
+
+ if (strcmp(key, "KERNELS") == 0) {
+ 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, "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;
+ }
+ rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
+ continue;
+ }
+
+ if (strcmp(key, "DRIVERS") == 0) {
+ if (op > OP_MATCH_MAX) {
+ err(rules->udev, "invalid DRIVERS operation\n");
+ goto invalid;
+ }
+ rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
+ continue;
+ }
+
+ if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-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);
+ 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) {
+ err(rules->udev, "error parsing ENV attribute\n");
+ goto invalid;
+ }
+ 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;
+ }
+ continue;
+ }
+
+ if (strcmp(key, "PROGRAM") == 0) {
+ rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
+ continue;
+ }
+
+ if (strcmp(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);
+ continue;