X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fudev%2Fudev-rules.c;h=58da79b876def0e546a2c26b3adb55659f577231;hb=16b9b87aeee9353b5b8dae6089a69752422a5b09;hp=8ace7050dbdf49432d4524bae049582d66877ef2;hpb=84b6ad702e64db534f67ce32d4dd2fec00a16784;p=elogind.git diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 8ace7050d..58da79b87 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -34,6 +34,7 @@ #include "conf-files.h" #include "strbuf.h" #include "strv.h" +#include "util.h" #define PREALLOC_TOKEN 2048 @@ -155,6 +156,7 @@ enum token_type { TK_A_MODE_ID, /* mode_t */ TK_A_TAG, /* val */ TK_A_STATIC_NODE, /* val */ + TK_A_SECLABEL, /* val, attr */ TK_A_ENV, /* val, attr */ TK_A_NAME, /* val */ TK_A_DEVLINK, /* val */ @@ -290,6 +292,7 @@ static const char *token_str(enum token_type type) [TK_A_OWNER_ID] = "A OWNER_ID", [TK_A_GROUP_ID] = "A GROUP_ID", [TK_A_STATIC_NODE] = "A STATIC_NODE", + [TK_A_SECLABEL] = "A SECLABEL", [TK_A_MODE_ID] = "A MODE_ID", [TK_A_ENV] = "A ENV", [TK_A_TAG] = "A ENV", @@ -398,6 +401,9 @@ static void dump_token(struct udev_rules *rules, struct token *token) case TK_A_STATIC_NODE: log_debug("%s '%s'\n", token_str(type), value); break; + case TK_A_SECLABEL: + log_debug("%s %s '%s' '%s'\n", token_str(type), operation_str(op), attr, value); + break; case TK_M_EVENT_TIMEOUT: log_debug("%s %u\n", token_str(type), token->key.event_timeout); break; @@ -910,6 +916,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_M_ATTRS: case TK_A_ATTR: case TK_A_ENV: + case TK_A_SECLABEL: attr = data; token->key.value_off = rules_add_string(rule_tmp->rules, value); token->key.attr_off = rules_add_string(rule_tmp->rules, attr); @@ -1066,8 +1073,28 @@ static int add_rule(struct udev_rules *rules, char *line, char *value; enum operation_type op; - if (get_key(rules->udev, &linepos, &key, &op, &value) != 0) + if (get_key(rules->udev, &linepos, &key, &op, &value) != 0) { + /* Avoid erroring on trailing whitespace. This is probably rare + * so save the work for the error case instead of always trying + * to strip the trailing whitespace with strstrip(). */ + while (isblank(*linepos)) + linepos++; + + /* If we aren't at the end of the line, this is a parsing error. + * Make a best effort to describe where the problem is. */ + if (*linepos != '\n') { + char buf[2] = {linepos[1]}; + _cleanup_free_ char *tmp; + + tmp = cescape(buf); + log_error("invalid key/value pair in file %s on line %u," + "starting at character %tu ('%s')\n", + filename, lineno, linepos - line + 1, tmp); + if (linepos[1] == '#') + log_info("hint: comments can only start at beginning of line"); + } break; + } if (streq(key, "ACTION")) { if (op > OP_MATCH_MAX) { @@ -1137,6 +1164,17 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } + if (startswith(key, "SECLABEL{")) { + attr = get_key_attribute(rules->udev, key + sizeof("SECLABEL")-1); + if (!attr) { + log_error("error parsing SECLABEL attribute\n"); + goto invalid; + } + + rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr); + continue; + } + if (streq(key, "KERNELS")) { if (op > OP_MATCH_MAX) { log_error("invalid KERNELS operation\n"); @@ -1680,32 +1718,7 @@ struct udev_rules *udev_rules_unref(struct udev_rules *rules) bool udev_rules_check_timestamp(struct udev_rules *rules) { - unsigned int i; - bool changed = false; - - if (rules == NULL) - goto out; - - for (i = 0; rules->dirs[i]; i++) { - struct stat stats; - - if (stat(rules->dirs[i], &stats) < 0) - continue; - - if (rules->dirs_ts_usec[i] == timespec_load(&stats.st_mtim)) - continue; - - /* first check */ - if (rules->dirs_ts_usec[i] != 0) { - log_debug("reload - timestamp of '%s' changed\n", rules->dirs[i]); - changed = true; - } - - /* update timestamp */ - rules->dirs_ts_usec[i] = timespec_load(&stats.st_mtim); - } -out: - return changed; + return paths_check_timestamp(rules->dirs, rules->dirs_ts_usec, true); } static int match_key(struct udev_rules *rules, struct token *token, const char *val) @@ -2308,6 +2321,20 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); break; + case TK_A_SECLABEL: { + const char *name, *label; + + name = rules_str(rules, cur->key.attr_off); + label = rules_str(rules, cur->key.value_off); + if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) + udev_list_cleanup(&event->seclabel_list); + udev_list_entry_add(&event->seclabel_list, name, label); + log_debug("SECLABEL{%s}='%s' %s:%u\n", + name, label, + rules_str(rules, rule->rule.filename_off), + rule->rule.filename_line); + break; + } case TK_A_ENV: { const char *name = rules_str(rules, cur->key.attr_off); char *value = rules_str(rules, cur->key.value_off); @@ -2586,6 +2613,10 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) } } + /* don't touch the permissions if only the tags were set */ + if (mode == 0 && uid == 0 && gid == 0) + goto next; + if (mode == 0) { if (gid > 0) mode = 0660; @@ -2593,13 +2624,21 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) mode = 0600; } if (mode != (stats.st_mode & 01777)) { - chmod(device_node, mode); - log_debug("chmod '%s' %#o\n", device_node, mode); + r = chmod(device_node, mode); + if (r < 0) { + log_error("failed to chmod '%s' %#o\n", device_node, mode); + return -errno; + } else + log_debug("chmod '%s' %#o\n", device_node, mode); } if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) { - chown(device_node, uid, gid); - log_debug("chown '%s' %u %u\n", device_node, uid, gid); + r = chown(device_node, uid, gid); + if (r < 0) { + log_error("failed to chown '%s' %u %u \n", device_node, uid, gid); + return -errno; + } else + log_debug("chown '%s' %u %u\n", device_node, uid, gid); } utimensat(AT_FDCWD, device_node, NULL, 0);