From: Yu Watanabe Date: Mon, 13 Mar 2023 11:57:50 +0000 (+0900) Subject: udev-rule: rework logging about udev rules X-Git-Tag: v254-rc1~1037^2~6 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c06ab041c769a12fa6cc40b60c8289bff5e2d8bd;p=thirdparty%2Fsystemd.git udev-rule: rework logging about udev rules This makes the loggers take the most relevant object, i.e. when applying udev rules to a device, the loggers take sd_device and UdevRuleToken object, and when parsing udev rules, they take UdevRuleLine or UdevRuleFile object. To achieve that, this drops 'iterators' in UdevRules or friends named `current_file` or so. Instead of that, each object now has its parent object, e.g. UdevRuleToken.rule_line that references the UdevRuleLine object the token belonging to. And each function previously took UdevRules object now takes the most relevant object, e.g. UdevRuleToken. Solves the discussion in https://github.com/systemd/systemd/pull/26698#discussion_r1129261193. --- diff --git a/src/udev/fuzz-udev-rules.c b/src/udev/fuzz-udev-rules.c index 255d5df7570..1d487b94eec 100644 --- a/src/udev/fuzz-udev-rules.c +++ b/src/udev/fuzz-udev-rules.c @@ -27,11 +27,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { fflush(f); assert_se(rules = udev_rules_new(RESOLVE_NAME_EARLY)); - r = udev_rules_parse_file(rules, filename); + r = udev_rules_parse_file(rules, filename, NULL); log_info_errno(r, "Parsing %s: %m", filename); - assert_se(IN_SET(r, - 0, /* OK */ - -ENOBUFS /* line length exceeded */)); + assert_se(r >= 0 || /* OK */ + r == -ENOBUFS); /* line length exceeded */ return 0; } diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index 5e7d8d390e4..a789d6c9856 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -152,6 +152,8 @@ struct UdevRuleToken { bool attr_match_remove_trailing_whitespace:1; const char *value; void *data; + + UdevRuleLine *rule_line; LIST_FIELDS(UdevRuleToken, tokens); }; @@ -165,15 +167,15 @@ struct UdevRuleLine { UdevRuleLine *goto_line; UdevRuleFile *rule_file; - UdevRuleToken *current_token; LIST_HEAD(UdevRuleToken, tokens); LIST_FIELDS(UdevRuleLine, rule_lines); }; struct UdevRuleFile { char *filename; - UdevRuleLine *current_line; - unsigned issues; + unsigned issues; /* used by "udevadm verify" */ + + UdevRules *rules; LIST_HEAD(UdevRuleLine, rule_lines); LIST_FIELDS(UdevRuleFile, rule_files); }; @@ -183,128 +185,131 @@ struct UdevRules { Hashmap *known_users; Hashmap *known_groups; Hashmap *stats_by_path; - UdevRuleFile *current_file; LIST_HEAD(UdevRuleFile, rule_files); }; +#define LINE_GET_RULES(line) \ + ASSERT_PTR(ASSERT_PTR(ASSERT_PTR(line)->rule_file)->rules) + /*** Logging helpers ***/ -#define log_rule_full_errno_zerook(device, rules, level, error, fmt, ...) \ +#define log_udev_rule_internal(device, file, line_nr, level, error, fmt, ...) \ ({ \ - UdevRules *_r = (rules); \ int _lv = (level); \ - UdevRuleFile *_f = _r ? _r->current_file : NULL; \ - UdevRuleLine *_l = _f ? _f->current_line : NULL; \ + UdevRuleFile *_f = (file); \ const char *_n = _f ? _f->filename : NULL; \ \ rule_file_mark_issue(_f, _lv); \ log_device_full_errno_zerook( \ device, _lv, error, "%s:%u " fmt, \ - strna(_n), _l ? _l->line_number : 0, \ + strna(_n), line_nr, \ ##__VA_ARGS__); \ }) -#define log_rule_full_errno(device, rules, level, error, fmt, ...) \ +/* Mainly used when applying tokens to the event device. */ +#define log_event_full_errno_zerook(device, token, ...) \ + ({ \ + UdevRuleToken *_t = (token); \ + UdevRuleLine *_l = _t ? _t->rule_line : NULL; \ + \ + log_udev_rule_internal( \ + device, \ + _l ? _l->rule_file : NULL, \ + _l ? _l->line_number : 0, \ + __VA_ARGS__); \ + }) + +#define log_event_full_errno(device, token, level, error, ...) \ ({ \ int _error = (error); \ ASSERT_NON_ZERO(_error); \ - log_rule_full_errno_zerook( \ - device, rules, level, _error, fmt, ##__VA_ARGS__); \ + log_event_full_errno_zerook( \ + device, token, level, _error, ##__VA_ARGS__); \ }) -#define log_rule_full(device, rules, level, ...) (void) log_rule_full_errno_zerook(device, rules, level, 0, __VA_ARGS__) - -#define log_rule_debug(device, rules, ...) log_rule_full(device, rules, LOG_DEBUG, __VA_ARGS__) -#define log_rule_info(device, rules, ...) log_rule_full(device, rules, LOG_INFO, __VA_ARGS__) -#define log_rule_notice(device, rules, ...) log_rule_full(device, rules, LOG_NOTICE, __VA_ARGS__) -#define log_rule_warning(device, rules, ...) log_rule_full(device, rules, LOG_WARNING, __VA_ARGS__) -#define log_rule_error(device, rules, ...) log_rule_full(device, rules, LOG_ERR, __VA_ARGS__) - -#define log_rule_debug_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_DEBUG, error, __VA_ARGS__) -#define log_rule_info_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_INFO, error, __VA_ARGS__) -#define log_rule_notice_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_NOTICE, error, __VA_ARGS__) -#define log_rule_warning_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_WARNING, error, __VA_ARGS__) -#define log_rule_error_errno(device, rules, error, ...) log_rule_full_errno(device, rules, LOG_ERR, error, __VA_ARGS__) - -#define log_token_full_errno_zerook(rules, level, error, ...) log_rule_full_errno_zerook(NULL, rules, level, error, __VA_ARGS__) -#define log_token_full_errno(rules, level, error, ...) log_rule_full_errno(NULL, rules, level, error, __VA_ARGS__) -#define log_token_full(rules, level, ...) (void) log_token_full_errno_zerook(rules, level, 0, __VA_ARGS__) - -#define log_token_debug(rules, ...) log_token_full(rules, LOG_DEBUG, __VA_ARGS__) -#define log_token_info(rules, ...) log_token_full(rules, LOG_INFO, __VA_ARGS__) -#define log_token_notice(rules, ...) log_token_full(rules, LOG_NOTICE, __VA_ARGS__) -#define log_token_warning(rules, ...) log_token_full(rules, LOG_WARNING, __VA_ARGS__) -#define log_token_error(rules, ...) log_token_full(rules, LOG_ERR, __VA_ARGS__) - -#define log_token_debug_errno(rules, error, ...) log_token_full_errno(rules, LOG_DEBUG, error, __VA_ARGS__) -#define log_token_info_errno(rules, error, ...) log_token_full_errno(rules, LOG_INFO, error, __VA_ARGS__) -#define log_token_notice_errno(rules, error, ...) log_token_full_errno(rules, LOG_NOTICE, error, __VA_ARGS__) -#define log_token_warning_errno(rules, error, ...) log_token_full_errno(rules, LOG_WARNING, error, __VA_ARGS__) -#define log_token_error_errno(rules, error, ...) log_token_full_errno(rules, LOG_ERR, error, __VA_ARGS__) - -#define _log_token_invalid(rules, key, type) \ - log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \ - "Invalid %s for %s.", type, key) - -#define log_token_invalid_op(rules, key) _log_token_invalid(rules, key, "operator") -#define log_token_invalid_attr(rules, key) _log_token_invalid(rules, key, "attribute") - -#define log_token_invalid_attr_format(rules, key, attr, offset, hint) \ - log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \ - "Invalid attribute \"%s\" for %s (char %zu: %s), ignoring.", \ - attr, key, offset, hint) -#define log_token_invalid_value(rules, key, value, offset, hint) \ - log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \ - "Invalid value \"%s\" for %s (char %zu: %s), ignoring.", \ - value, key, offset, hint) - -#define log_line_full_errno_zerook(rule_file, line_nr, level, error, fmt, ...) \ +#define log_event_full(device, token, level, ...) (void) log_event_full_errno_zerook(device, token, level, 0, __VA_ARGS__) + +#define log_event_debug(device, token, ...) log_event_full(device, token, LOG_DEBUG, __VA_ARGS__) +#define log_event_info(device, token, ...) log_event_full(device, token, LOG_INFO, __VA_ARGS__) +#define log_event_notice(device, token, ...) log_event_full(device, token, LOG_NOTICE, __VA_ARGS__) +#define log_event_warning(device, token, ...) log_event_full(device, token, LOG_WARNING, __VA_ARGS__) +#define log_event_error(device, token, ...) log_event_full(device, token, LOG_ERR, __VA_ARGS__) + +#define log_event_debug_errno(device, token, error, ...) log_event_full_errno(device, token, LOG_DEBUG, error, __VA_ARGS__) +#define log_event_info_errno(device, token, error, ...) log_event_full_errno(device, token, LOG_INFO, error, __VA_ARGS__) +#define log_event_notice_errno(device, token, error, ...) log_event_full_errno(device, token, LOG_NOTICE, error, __VA_ARGS__) +#define log_event_warning_errno(device, token, error, ...) log_event_full_errno(device, token, LOG_WARNING, error, __VA_ARGS__) +#define log_event_error_errno(device, token, error, ...) log_event_full_errno(device, token, LOG_ERR, error, __VA_ARGS__) + +/* Mainly used when parsing .rules files. */ +#define log_file_full_errno_zerook(...) \ + log_udev_rule_internal(NULL, __VA_ARGS__) + +#define log_file_error(file, line_nr, ...) \ + log_file_full_errno_zerook(file, line_nr, LOG_ERR, 0, __VA_ARGS__) + +#define log_line_full_errno_zerook(line, ...) \ ({ \ - UdevRuleFile *_f = (rule_file); \ - int _lv = (level); \ - const char *_n = _f ? _f->filename : NULL; \ - \ - rule_file_mark_issue(_f, _lv); \ - log_device_full_errno_zerook( \ - NULL, _lv, error, "%s:%u " fmt, \ - strna(_n), line_nr, \ - ##__VA_ARGS__); \ + UdevRuleLine *_l = (line); \ + log_file_full_errno_zerook( \ + _l ? _l->rule_file : NULL, \ + _l ? _l->line_number : 0, \ + __VA_ARGS__); \ }) -#define log_line_full_errno(rule_file, line_nr, level, error, fmt, ...) \ +#define log_line_full_errno(line, level, error, ...) \ ({ \ int _error = (error); \ ASSERT_NON_ZERO(_error); \ log_line_full_errno_zerook( \ - rule_file, line_nr, level, _error, \ - fmt, ##__VA_ARGS__); \ + line, level, _error, ##__VA_ARGS__); \ }) -#define log_line_full(rule_file, line_nr, level, ...) \ - (void) log_line_full_errno_zerook(rule_file, line_nr, level, 0, __VA_ARGS__) +#define log_line_full(line, level, ...) (void) log_line_full_errno_zerook(line, level, 0, __VA_ARGS__) + +#define log_line_debug(line, ...) log_line_full(line, LOG_DEBUG, __VA_ARGS__) +#define log_line_info(line, ...) log_line_full(line, LOG_INFO, __VA_ARGS__) +#define log_line_notice(line, ...) log_line_full(line, LOG_NOTICE, __VA_ARGS__) +#define log_line_warning(line, ...) log_line_full(line, LOG_WARNING, __VA_ARGS__) +#define log_line_error(line, ...) log_line_full(line, LOG_ERR, __VA_ARGS__) + +#define log_line_debug_errno(line, error, ...) log_line_full_errno(line, LOG_DEBUG, error, __VA_ARGS__) +#define log_line_info_errno(line, error, ...) log_line_full_errno(line, LOG_INFO, error, __VA_ARGS__) +#define log_line_notice_errno(line, error, ...) log_line_full_errno(line, LOG_NOTICE, error, __VA_ARGS__) +#define log_line_warning_errno(line, error, ...) log_line_full_errno(line, LOG_WARNING, error, __VA_ARGS__) +#define log_line_error_errno(line, error, ...) log_line_full_errno(line, LOG_ERR, error, __VA_ARGS__) -#define log_line_debug(rule_file, line_nr, ...) log_line_full(rule_file, line_nr, LOG_DEBUG, __VA_ARGS__) -#define log_line_info(rule_file, line_nr, ...) log_line_full(rule_file, line_nr, LOG_INFO, __VA_ARGS__) -#define log_line_notice(rule_file, line_nr, ...) log_line_full(rule_file, line_nr, LOG_NOTICE, __VA_ARGS__) -#define log_line_warning(rule_file, line_nr, ...) log_line_full(rule_file, line_nr, LOG_WARNING, __VA_ARGS__) -#define log_line_error(rule_file, line_nr, ...) log_line_full(rule_file, line_nr, LOG_ERR, __VA_ARGS__) +#define _log_line_invalid_token(line, key, type) \ + log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \ + "Invalid %s for %s.", type, key) -#define log_line_debug_errno(rule_file, line_nr, error, ...) log_line_full_errno(rule_file, line_nr, LOG_DEBUG, error, __VA_ARGS__) -#define log_line_info_errno(rule_file, line_nr, error, ...) log_line_full_errno(rule_file, line_nr, LOG_INFO, error, __VA_ARGS__) -#define log_line_notice_errno(rule_file, line_nr, error, ...) log_line_full_errno(rule_file, line_nr, LOG_NOTICE, error, __VA_ARGS__) -#define log_line_warning_errno(rule_file, line_nr, error, ...) log_line_full_errno(rule_file, line_nr, LOG_WARNING, error, __VA_ARGS__) -#define log_line_error_errno(rule_file, line_nr, error, ...) log_line_full_errno(rule_file, line_nr, LOG_ERR, error, __VA_ARGS__) +#define log_line_invalid_op(line, key) _log_line_invalid_token(line, key, "operator") +#define log_line_invalid_attr(line, key) _log_line_invalid_token(line, key, "attribute") + +#define log_line_invalid_attr_format(line, key, attr, offset, hint) \ + log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \ + "Invalid attribute \"%s\" for %s (char %zu: %s), ignoring.", \ + attr, key, offset, hint) +#define log_line_invalid_value(line, key, value, offset, hint) \ + log_line_error_errno(line, SYNTHETIC_ERRNO(EINVAL), \ + "Invalid value \"%s\" for %s (char %zu: %s), ignoring.", \ + value, key, offset, hint) static void rule_file_mark_issue(UdevRuleFile *rule_file, uint8_t log_level) { if (rule_file) rule_file->issues |= (1U << log_level); } -static void log_unknown_owner(sd_device *dev, UdevRules *rules, int error, const char *entity, const char *name) { +static void log_unknown_owner(sd_device *dev, UdevRuleLine *line, int error, const char *entity, const char *name) { + assert(line); + ASSERT_NON_ZERO(error); + if (IN_SET(abs(error), ENOENT, ESRCH)) - log_rule_error(dev, rules, "Unknown %s '%s', ignoring", entity, name); + log_udev_rule_internal(dev, line->rule_file, line->line_number, LOG_ERR, error, + "Unknown %s '%s', ignoring", entity, name); else - log_rule_error_errno(dev, rules, error, "Failed to resolve %s '%s', ignoring: %m", entity, name); + log_udev_rule_internal(dev, line->rule_file, line->line_number, LOG_ERR, error, + "Failed to resolve %s '%s', ignoring: %m", entity, name); } /*** Other functions ***/ @@ -328,12 +333,8 @@ static UdevRuleLine* udev_rule_line_free(UdevRuleLine *rule_line) { udev_rule_line_clear_tokens(rule_line); - if (rule_line->rule_file) { - if (rule_line->rule_file->current_line == rule_line) - rule_line->rule_file->current_line = rule_line->rule_lines_prev; - + if (rule_line->rule_file) LIST_REMOVE(rule_lines, rule_line->rule_file->rule_lines, rule_line); - } free(rule_line->line); return mfree(rule_line); @@ -365,16 +366,17 @@ UdevRules *udev_rules_free(UdevRules *rules) { return mfree(rules); } -static int rule_resolve_user(UdevRules *rules, const char *name, uid_t *ret) { +static int rule_resolve_user(UdevRuleLine *rule_line, const char *name, uid_t *ret) { + Hashmap **known_users = &LINE_GET_RULES(rule_line)->known_users; _cleanup_free_ char *n = NULL; uid_t uid; void *val; int r; - assert(rules); assert(name); + assert(ret); - val = hashmap_get(rules->known_users, name); + val = hashmap_get(*known_users, name); if (val) { *ret = PTR_TO_UID(val); return 0; @@ -382,7 +384,7 @@ static int rule_resolve_user(UdevRules *rules, const char *name, uid_t *ret) { r = get_user_creds(&name, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING); if (r < 0) { - log_unknown_owner(NULL, rules, r, "user", name); + log_unknown_owner(NULL, rule_line, r, "user", name); *ret = UID_INVALID; return 0; } @@ -391,7 +393,7 @@ static int rule_resolve_user(UdevRules *rules, const char *name, uid_t *ret) { if (!n) return -ENOMEM; - r = hashmap_ensure_put(&rules->known_users, &string_hash_ops, n, UID_TO_PTR(uid)); + r = hashmap_ensure_put(known_users, &string_hash_ops, n, UID_TO_PTR(uid)); if (r < 0) return r; @@ -400,16 +402,17 @@ static int rule_resolve_user(UdevRules *rules, const char *name, uid_t *ret) { return 0; } -static int rule_resolve_group(UdevRules *rules, const char *name, gid_t *ret) { +static int rule_resolve_group(UdevRuleLine *rule_line, const char *name, gid_t *ret) { + Hashmap **known_groups = &LINE_GET_RULES(rule_line)->known_groups; _cleanup_free_ char *n = NULL; gid_t gid; void *val; int r; - assert(rules); assert(name); + assert(ret); - val = hashmap_get(rules->known_groups, name); + val = hashmap_get(*known_groups, name); if (val) { *ret = PTR_TO_GID(val); return 0; @@ -417,7 +420,7 @@ static int rule_resolve_group(UdevRules *rules, const char *name, gid_t *ret) { r = get_group_creds(&name, &gid, USER_CREDS_ALLOW_MISSING); if (r < 0) { - log_unknown_owner(NULL, rules, r, "group", name); + log_unknown_owner(NULL, rule_line, r, "group", name); *ret = GID_INVALID; return 0; } @@ -426,7 +429,7 @@ static int rule_resolve_group(UdevRules *rules, const char *name, gid_t *ret) { if (!n) return -ENOMEM; - r = hashmap_ensure_put(&rules->known_groups, &string_hash_ops, n, GID_TO_PTR(gid)); + r = hashmap_ensure_put(known_groups, &string_hash_ops, n, GID_TO_PTR(gid)); if (r < 0) return r; @@ -449,12 +452,8 @@ static void rule_line_append_token(UdevRuleLine *rule_line, UdevRuleToken *token assert(rule_line); assert(token); - if (rule_line->current_token) - LIST_APPEND(tokens, rule_line->current_token, token); - else - LIST_APPEND(tokens, rule_line->tokens, token); - - rule_line->current_token = token; + token->rule_line = rule_line; + LIST_APPEND(tokens, rule_line->tokens, token); } static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, UdevRuleOperatorType op, char *value, void *data) { @@ -567,98 +566,93 @@ static int rule_line_add_token(UdevRuleLine *rule_line, UdevRuleTokenType type, return 0; } -static void check_value_format_and_warn(UdevRules *rules, const char *key, const char *value, bool nonempty) { +static void check_value_format_and_warn(UdevRuleLine *line, const char *key, const char *value, bool nonempty) { size_t offset; const char *hint; if (nonempty && isempty(value)) - log_token_invalid_value(rules, key, value, (size_t) 0, "empty value"); + log_line_invalid_value(line, key, value, (size_t) 0, "empty value"); else if (udev_check_format(value, &offset, &hint) < 0) - log_token_invalid_value(rules, key, value, offset + 1, hint); + log_line_invalid_value(line, key, value, offset + 1, hint); } -static int check_attr_format_and_warn(UdevRules *rules, const char *key, const char *value) { +static int check_attr_format_and_warn(UdevRuleLine *line, const char *key, const char *value) { size_t offset; const char *hint; if (isempty(value)) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(line, key); if (udev_check_format(value, &offset, &hint) < 0) - log_token_invalid_attr_format(rules, key, value, offset + 1, hint); + log_line_invalid_attr_format(line, key, value, offset + 1, hint); return 0; } -static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOperatorType op, char *value) { +static int parse_token(UdevRuleLine *rule_line, const char *key, char *attr, UdevRuleOperatorType op, char *value) { + ResolveNameTiming resolve_name_timing = LINE_GET_RULES(rule_line)->resolve_name_timing; bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH); - UdevRuleLine *rule_line; int r; - assert(rules); - assert(rules->current_file); - assert(rules->current_file->current_line); assert(key); assert(value); - rule_line = rules->current_file->current_line; - if (streq(key, "ACTION")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_ACTION, op, value, NULL); } else if (streq(key, "DEVPATH")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_DEVPATH, op, value, NULL); } else if (streq(key, "KERNEL")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_KERNEL, op, value, NULL); } else if (streq(key, "SYMLINK")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) { - check_value_format_and_warn(rules, key, value, false); + check_value_format_and_warn(rule_line, key, value, false); r = rule_line_add_token(rule_line, TK_A_DEVLINK, op, value, NULL); } else r = rule_line_add_token(rule_line, TK_M_DEVLINK, op, value, NULL); } else if (streq(key, "NAME")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ADD) { - log_token_warning(rules, "%s key takes '==', '!=', '=', or ':=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '==', '!=', '=', or ':=' operator, assuming '='.", key); op = OP_ASSIGN; } if (!is_match) { if (streq(value, "%k")) - return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), - "Ignoring NAME=\"%%k\", as it will take no effect."); + return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), + "Ignoring NAME=\"%%k\", as it will take no effect."); if (isempty(value)) - return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), - "Ignoring NAME=\"\", as udev will not delete any network interfaces."); - check_value_format_and_warn(rules, key, value, false); + return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), + "Ignoring NAME=\"\", as udev will not delete any network interfaces."); + check_value_format_and_warn(rule_line, key, value, false); r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL); } else r = rule_line_add_token(rule_line, TK_M_NAME, op, value, NULL); } else if (streq(key, "ENV")) { if (isempty(attr)) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ASSIGN_FINAL) { - log_token_warning(rules, "%s key takes '==', '!=', '=', or '+=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '==', '!=', '=', or '+=' operator, assuming '='.", key); op = OP_ASSIGN; } @@ -666,122 +660,122 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp if (STR_IN_SET(attr, "ACTION", "DEVLINKS", "DEVNAME", "DEVPATH", "DEVTYPE", "DRIVER", "IFINDEX", "MAJOR", "MINOR", "SEQNUM", "SUBSYSTEM", "TAGS")) - return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), - "Invalid ENV attribute. '%s' cannot be set.", attr); + return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), + "Invalid ENV attribute. '%s' cannot be set.", attr); - check_value_format_and_warn(rules, key, value, false); + check_value_format_and_warn(rule_line, key, value, false); r = rule_line_add_token(rule_line, TK_A_ENV, op, value, attr); } else r = rule_line_add_token(rule_line, TK_M_ENV, op, value, attr); } else if (streq(key, "CONST")) { if (isempty(attr) || !STR_IN_SET(attr, "arch", "virt")) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_CONST, op, value, attr); } else if (streq(key, "TAG")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (op == OP_ASSIGN_FINAL) { - log_token_warning(rules, "%s key takes '==', '!=', '=', or '+=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '==', '!=', '=', or '+=' operator, assuming '='.", key); op = OP_ASSIGN; } if (!is_match) { - check_value_format_and_warn(rules, key, value, true); + check_value_format_and_warn(rule_line, key, value, true); r = rule_line_add_token(rule_line, TK_A_TAG, op, value, NULL); } else r = rule_line_add_token(rule_line, TK_M_TAG, op, value, NULL); } else if (streq(key, "SUBSYSTEM")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (STR_IN_SET(value, "bus", "class")) - log_token_warning(rules, "\"%s\" must be specified as \"subsystem\".", value); + log_line_warning(rule_line, "\"%s\" must be specified as \"subsystem\".", value); r = rule_line_add_token(rule_line, TK_M_SUBSYSTEM, op, value, NULL); } else if (streq(key, "DRIVER")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL); } else if (streq(key, "ATTR")) { - r = check_attr_format_and_warn(rules, key, attr); + r = check_attr_format_and_warn(rule_line, key, attr); if (r < 0) return r; if (op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (IN_SET(op, OP_ADD, OP_ASSIGN_FINAL)) { - log_token_warning(rules, "%s key takes '==', '!=', or '=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '==', '!=', or '=' operator, assuming '='.", key); op = OP_ASSIGN; } if (!is_match) { - check_value_format_and_warn(rules, key, value, false); + check_value_format_and_warn(rule_line, key, value, false); r = rule_line_add_token(rule_line, TK_A_ATTR, op, value, attr); } else r = rule_line_add_token(rule_line, TK_M_ATTR, op, value, attr); } else if (streq(key, "SYSCTL")) { - r = check_attr_format_and_warn(rules, key, attr); + r = check_attr_format_and_warn(rule_line, key, attr); if (r < 0) return r; if (op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (IN_SET(op, OP_ADD, OP_ASSIGN_FINAL)) { - log_token_warning(rules, "%s key takes '==', '!=', or '=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '==', '!=', or '=' operator, assuming '='.", key); op = OP_ASSIGN; } if (!is_match) { - check_value_format_and_warn(rules, key, value, false); + check_value_format_and_warn(rule_line, key, value, false); r = rule_line_add_token(rule_line, TK_A_SYSCTL, op, value, attr); } else r = rule_line_add_token(rule_line, TK_M_SYSCTL, op, value, attr); } else if (streq(key, "KERNELS")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_PARENTS_KERNEL, op, value, NULL); } else if (streq(key, "SUBSYSTEMS")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_PARENTS_SUBSYSTEM, op, value, NULL); } else if (streq(key, "DRIVERS")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL); } else if (streq(key, "ATTRS")) { - r = check_attr_format_and_warn(rules, key, attr); + r = check_attr_format_and_warn(rule_line, key, attr); if (r < 0) return r; if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (startswith(attr, "device/")) - log_token_warning(rules, "'device' link may not be available in future kernels."); + log_line_warning(rule_line, "'device' link may not be available in future kernels."); if (strstr(attr, "../")) - log_token_warning(rules, "Direct reference to parent sysfs directory, may break in future kernels."); + log_line_warning(rule_line, "Direct reference to parent sysfs directory, may break in future kernels."); r = rule_line_add_token(rule_line, TK_M_PARENTS_ATTR, op, value, attr); } else if (streq(key, "TAGS")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_PARENTS_TAG, op, value, NULL); } else if (streq(key, "TEST")) { @@ -790,29 +784,29 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp if (!isempty(attr)) { r = parse_mode(attr, &mode); if (r < 0) - return log_token_error_errno(rules, r, "Failed to parse mode '%s': %m", attr); + return log_line_error_errno(rule_line, r, "Failed to parse mode '%s': %m", attr); } - check_value_format_and_warn(rules, key, value, true); + check_value_format_and_warn(rule_line, key, value, true); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_TEST, op, value, MODE_TO_PTR(mode)); } else if (streq(key, "PROGRAM")) { if (attr) - return log_token_invalid_attr(rules, key); - check_value_format_and_warn(rules, key, value, true); + return log_line_invalid_attr(rule_line, key); + check_value_format_and_warn(rule_line, key, value, true); if (op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (!is_match) op = OP_MATCH; r = rule_line_add_token(rule_line, TK_M_PROGRAM, op, value, NULL); } else if (streq(key, "IMPORT")) { if (isempty(attr)) - return log_token_invalid_attr(rules, key); - check_value_format_and_warn(rules, key, value, true); + return log_line_invalid_attr(rule_line, key); + check_value_format_and_warn(rule_line, key, value, true); if (op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (!is_match) op = OP_MATCH; @@ -823,7 +817,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp cmd = udev_builtin_lookup(value); if (cmd >= 0) { - log_token_debug(rules,"Found builtin command '%s' for %s, replacing attribute", value, key); + log_line_debug(rule_line, "Found builtin command '%s' for %s, replacing attribute", value, key); r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd)); } else r = rule_line_add_token(rule_line, TK_M_IMPORT_PROGRAM, op, value, NULL); @@ -832,8 +826,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp cmd = udev_builtin_lookup(value); if (cmd < 0) - return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), - "Unknown builtin command: %s", value); + return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), + "Unknown builtin command: %s", value); r = rule_line_add_token(rule_line, TK_M_IMPORT_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd)); } else if (streq(attr, "db")) r = rule_line_add_token(rule_line, TK_M_IMPORT_DB, op, value, NULL); @@ -842,21 +836,21 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp else if (streq(attr, "parent")) r = rule_line_add_token(rule_line, TK_M_IMPORT_PARENT, op, value, NULL); else - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); } else if (streq(key, "RESULT")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (!is_match) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); r = rule_line_add_token(rule_line, TK_M_RESULT, op, value, NULL); } else if (streq(key, "OPTIONS")) { char *tmp; if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (is_match || op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ADD) op = OP_ASSIGN; @@ -877,7 +871,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp r = safe_atoi(tmp, &prio); if (r < 0) - return log_token_error_errno(rules, r, "Failed to parse link priority '%s': %m", tmp); + return log_line_error_errno(rule_line, r, "Failed to parse link priority '%s': %m", tmp); r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio)); } else if ((tmp = startswith(value, "log_level="))) { int level; @@ -887,103 +881,103 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp else { level = log_level_from_string(tmp); if (level < 0) - return log_token_error_errno(rules, level, "Failed to parse log level '%s': %m", tmp); + return log_line_error_errno(rule_line, level, "Failed to parse log level '%s': %m", tmp); } r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level)); } else { - log_token_warning(rules, "Invalid value for OPTIONS key, ignoring: '%s'", value); + log_line_warning(rule_line, "Invalid value for OPTIONS key, ignoring: '%s'", value); return 0; } } else if (streq(key, "OWNER")) { uid_t uid; if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (is_match || op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ADD) { - log_token_warning(rules, "%s key takes '=' or ':=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '=' or ':=' operator, assuming '='.", key); op = OP_ASSIGN; } if (parse_uid(value, &uid) >= 0) r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid)); - else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && + else if (resolve_name_timing == RESOLVE_NAME_EARLY && rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) { - r = rule_resolve_user(rules, value, &uid); + r = rule_resolve_user(rule_line, value, &uid); if (r < 0) - return log_token_error_errno(rules, r, "Failed to resolve user name '%s': %m", value); + return log_line_error_errno(rule_line, r, "Failed to resolve user name '%s': %m", value); r = rule_line_add_token(rule_line, TK_A_OWNER_ID, op, NULL, UID_TO_PTR(uid)); - } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) { - check_value_format_and_warn(rules, key, value, true); + } else if (resolve_name_timing != RESOLVE_NAME_NEVER) { + check_value_format_and_warn(rule_line, key, value, true); r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL); } else { - log_token_debug(rules, "User name resolution is disabled, ignoring %s=%s", key, value); + log_line_debug(rule_line, "User name resolution is disabled, ignoring %s=%s", key, value); return 0; } } else if (streq(key, "GROUP")) { gid_t gid; if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (is_match || op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ADD) { - log_token_warning(rules, "%s key takes '=' or ':=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '=' or ':=' operator, assuming '='.", key); op = OP_ASSIGN; } if (parse_gid(value, &gid) >= 0) r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid)); - else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && + else if (resolve_name_timing == RESOLVE_NAME_EARLY && rule_get_substitution_type(value) == SUBST_TYPE_PLAIN) { - r = rule_resolve_group(rules, value, &gid); + r = rule_resolve_group(rule_line, value, &gid); if (r < 0) - return log_token_error_errno(rules, r, "Failed to resolve group name '%s': %m", value); + return log_line_error_errno(rule_line, r, "Failed to resolve group name '%s': %m", value); r = rule_line_add_token(rule_line, TK_A_GROUP_ID, op, NULL, GID_TO_PTR(gid)); - } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER) { - check_value_format_and_warn(rules, key, value, true); + } else if (resolve_name_timing != RESOLVE_NAME_NEVER) { + check_value_format_and_warn(rule_line, key, value, true); r = rule_line_add_token(rule_line, TK_A_GROUP, op, value, NULL); } else { - log_token_debug(rules, "Resolving group name is disabled, ignoring GROUP=\"%s\"", value); + log_line_debug(rule_line, "Resolving group name is disabled, ignoring GROUP=\"%s\"", value); return 0; } } else if (streq(key, "MODE")) { mode_t mode; if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (is_match || op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ADD) { - log_token_warning(rules, "%s key takes '=' or ':=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '=' or ':=' operator, assuming '='.", key); op = OP_ASSIGN; } if (parse_mode(value, &mode) >= 0) r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode)); else { - check_value_format_and_warn(rules, key, value, true); + check_value_format_and_warn(rule_line, key, value, true); r = rule_line_add_token(rule_line, TK_A_MODE, op, value, NULL); } } else if (streq(key, "SECLABEL")) { if (isempty(attr)) - return log_token_invalid_attr(rules, key); - check_value_format_and_warn(rules, key, value, true); + return log_line_invalid_attr(rule_line, key); + check_value_format_and_warn(rule_line, key, value, true); if (is_match || op == OP_REMOVE) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (op == OP_ASSIGN_FINAL) { - log_token_warning(rules, "%s key takes '=' or '+=' operator, assuming '='.", key); + log_line_warning(rule_line, "%s key takes '=' or '+=' operator, assuming '='.", key); op = OP_ASSIGN; } r = rule_line_add_token(rule_line, TK_A_SECLABEL, op, value, attr); } else if (streq(key, "RUN")) { if (is_match || op == OP_REMOVE) - return log_token_invalid_op(rules, key); - check_value_format_and_warn(rules, key, value, true); + return log_line_invalid_op(rule_line, key); + check_value_format_and_warn(rule_line, key, value, true); if (!attr || streq(attr, "program")) r = rule_line_add_token(rule_line, TK_A_RUN_PROGRAM, op, value, NULL); else if (streq(attr, "builtin")) { @@ -991,18 +985,18 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp cmd = udev_builtin_lookup(value); if (cmd < 0) - return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), + return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), "Unknown builtin command '%s', ignoring", value); r = rule_line_add_token(rule_line, TK_A_RUN_BUILTIN, op, value, UDEV_BUILTIN_CMD_TO_PTR(cmd)); } else - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); } else if (streq(key, "GOTO")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (op != OP_ASSIGN) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (FLAGS_SET(rule_line->type, LINE_HAS_GOTO)) { - log_token_warning(rules, "Contains multiple GOTO keys, ignoring GOTO=\"%s\".", value); + log_line_warning(rule_line, "Contains multiple GOTO keys, ignoring GOTO=\"%s\".", value); return 0; } @@ -1011,18 +1005,18 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp return 1; } else if (streq(key, "LABEL")) { if (attr) - return log_token_invalid_attr(rules, key); + return log_line_invalid_attr(rule_line, key); if (op != OP_ASSIGN) - return log_token_invalid_op(rules, key); + return log_line_invalid_op(rule_line, key); if (FLAGS_SET(rule_line->type, LINE_HAS_LABEL)) - log_token_warning(rules, "Contains multiple LABEL keys, ignoring LABEL=\"%s\".", - rule_line->label); + log_line_warning(rule_line, "Contains multiple LABEL keys, ignoring LABEL=\"%s\".", + rule_line->label); rule_line->label = value; SET_FLAG(rule_line->type, LINE_HAS_LABEL, true); return 1; } else - return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), "Invalid key '%s'", key); + return log_line_error_errno(rule_line, SYNTHETIC_ERRNO(EINVAL), "Invalid key '%s'", key); if (r < 0) return log_oom(); @@ -1106,7 +1100,6 @@ static void sort_tokens(UdevRuleLine *rule_line) { assert(rule_line); UdevRuleToken *old_tokens = TAKE_PTR(rule_line->tokens); - rule_line->current_token = NULL; while (old_tokens) { UdevRuleToken *min_token = NULL; @@ -1120,19 +1113,15 @@ static void sort_tokens(UdevRuleLine *rule_line) { } } -static int rule_add_line(UdevRules *rules, const char *line_str, unsigned line_nr) { +static int rule_add_line(UdevRuleFile *rule_file, const char *line_str, unsigned line_nr) { _cleanup_(udev_rule_line_freep) UdevRuleLine *rule_line = NULL; _cleanup_free_ char *line = NULL; - UdevRuleFile *rule_file; char *p; int r; - assert(rules); - assert(rules->current_file); + assert(rule_file); assert(line_str); - rule_file = rules->current_file; - if (isempty(line_str)) return 0; @@ -1152,12 +1141,7 @@ static int rule_add_line(UdevRules *rules, const char *line_str, unsigned line_n .rule_file = rule_file, }; - if (rule_file->current_line) - LIST_APPEND(rule_lines, rule_file->current_line, rule_line); - else - LIST_APPEND(rule_lines, rule_file->rule_lines, rule_line); - - rule_file->current_line = rule_line; + LIST_APPEND(rule_lines, rule_file->rule_lines, rule_line); for (p = rule_line->line; !isempty(p); ) { char *key, *attr, *value; @@ -1165,17 +1149,17 @@ static int rule_add_line(UdevRules *rules, const char *line_str, unsigned line_n r = parse_line(&p, &key, &attr, &op, &value); if (r < 0) - return log_token_error_errno(rules, r, "Invalid key/value pair, ignoring."); + return log_line_error_errno(rule_line, r, "Invalid key/value pair, ignoring."); if (r == 0) break; - r = parse_token(rules, key, attr, op, value); + r = parse_token(rule_line, key, attr, op, value); if (r < 0) return r; } if (rule_line->type == 0) { - log_token_warning(rules, "The line takes no effect, ignoring."); + log_line_warning(rule_line, "The line takes no effect, ignoring."); return 0; } @@ -1200,16 +1184,14 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) { } if (!line->goto_line) { - log_line_error(rule_file, line->line_number, - "GOTO=\"%s\" has no matching label, ignoring", + log_line_error(line, "GOTO=\"%s\" has no matching label, ignoring", line->goto_label); SET_FLAG(line->type, LINE_HAS_GOTO, false); line->goto_label = NULL; if ((line->type & ~(LINE_HAS_LABEL|LINE_IS_REFERENCED)) == 0) { - log_line_notice(rule_file, line->line_number, - "The line takes no effect any more, dropping"); + log_line_notice(line, "The line takes no effect any more, dropping"); /* LINE_IS_REFERENCED implies LINE_HAS_LABEL */ if (line->type & LINE_HAS_LABEL) udev_rule_line_clear_tokens(line); @@ -1220,7 +1202,7 @@ static void rule_resolve_goto(UdevRuleFile *rule_file) { } } -int udev_rules_parse_file(UdevRules *rules, const char *filename) { +int udev_rules_parse_file(UdevRules *rules, const char *filename, UdevRuleFile **ret) { _cleanup_free_ char *continuation = NULL, *name = NULL; _cleanup_fclose_ FILE *f = NULL; UdevRuleFile *rule_file; @@ -1229,6 +1211,9 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { struct stat st; int r; + assert(rules); + assert(filename); + f = fopen(filename, "re"); if (!f) return log_warning_errno(errno, "Failed to open %s, ignoring: %m", filename); @@ -1238,6 +1223,8 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { if (null_or_empty(&st)) { log_debug("Skipping empty file: %s", filename); + if (ret) + *ret = NULL; return 0; } @@ -1259,14 +1246,10 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { *rule_file = (UdevRuleFile) { .filename = TAKE_PTR(name), + .rules = rules, }; - if (rules->current_file) - LIST_APPEND(rule_files, rules->current_file, rule_file); - else - LIST_APPEND(rule_files, rules->rule_files, rule_file); - - rules->current_file = rule_file; + LIST_APPEND(rule_files, rules->rule_files, rule_file); for (;;) { _cleanup_free_ char *buf = NULL; @@ -1316,39 +1299,39 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { } if (ignore_line) - log_line_error(rule_file, line_nr, "Line is too long, ignored"); + log_file_error(rule_file, line_nr, "Line is too long, ignored"); else if (len > 0) - (void) rule_add_line(rules, line, line_nr); + (void) rule_add_line(rule_file, line, line_nr); continuation = mfree(continuation); ignore_line = false; } if (continuation) - log_line_error(rule_file, line_nr, + log_file_error(rule_file, line_nr, "Unexpected EOF after line continuation, line ignored"); rule_resolve_goto(rule_file); - return 0; + + if (ret) + *ret = rule_file; + return 1; } -static void udev_check_rule_line(UdevRuleFile *rule_file, const UdevRuleLine *line) { +static void udev_check_rule_line(UdevRuleLine *line) { + assert(line); + /* check for unused labels */ if (FLAGS_SET(line->type, LINE_HAS_LABEL) && !FLAGS_SET(line->type, LINE_IS_REFERENCED)) - log_line_warning(rule_file, line->line_number, - "LABEL=\"%s\" is unused.", line->label); + log_line_warning(line, "LABEL=\"%s\" is unused.", line->label); } -unsigned udev_check_current_rule_file(UdevRules *rules) { - assert(rules); - - UdevRuleFile *rule_file = rules->current_file; - if (!rule_file) - return 0; +unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file) { + assert(rule_file); LIST_FOREACH(rule_lines, line, rule_file->rule_lines) - udev_check_rule_line(rule_file, line); + udev_check_rule_line(line); return rule_file->issues; } @@ -1381,7 +1364,7 @@ int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing return log_debug_errno(r, "Failed to enumerate rules files: %m"); STRV_FOREACH(f, files) { - r = udev_rules_parse_file(rules, *f); + r = udev_rules_parse_file(rules, *f, NULL); if (r < 0) log_debug_errno(r, "Failed to read rules file %s, ignoring: %m", *f); } @@ -1462,12 +1445,11 @@ static bool token_match_string(UdevRuleToken *token, const char *str) { return token->op == (match ? OP_MATCH : OP_NOMATCH); } -static bool token_match_attr(UdevRules *rules, UdevRuleToken *token, sd_device *dev, UdevEvent *event) { +static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *event) { char nbuf[UDEV_NAME_SIZE], vbuf[UDEV_NAME_SIZE]; const char *name, *value; bool truncated; - assert(rules); assert(token); assert(IN_SET(token->type, TK_M_ATTR, TK_M_PARENTS_ATTR)); assert(dev); @@ -1479,10 +1461,10 @@ static bool token_match_attr(UdevRules *rules, UdevRuleToken *token, sd_device * case SUBST_TYPE_FORMAT: (void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, - "The sysfs attribute name '%s' is truncated while substituting into '%s', " - "assuming the %s key does not match.", nbuf, name, - token->type == TK_M_ATTR ? "ATTR" : "ATTRS"); + log_event_debug(dev, token, + "The sysfs attribute name '%s' is truncated while substituting into '%s', " + "assuming the %s key does not match.", nbuf, name, + token->type == TK_M_ATTR ? "ATTR" : "ATTRS"); return false; } @@ -1629,17 +1611,16 @@ static int attr_subst_subdir(char attr[static UDEV_PATH_SIZE]) { } static int udev_rule_apply_token_to_event( - UdevRules *rules, + UdevRuleToken *token, sd_device *dev, UdevEvent *event, usec_t timeout_usec, int timeout_signal, Hashmap *properties_list) { - UdevRuleToken *token; int r; - assert(rules); + assert(token); assert(dev); assert(event); @@ -1648,15 +1629,13 @@ static int udev_rule_apply_token_to_event( * 1 on the current token matches the event, and * negative errno on some critical errors. */ - token = rules->current_file->current_line->current_token; - switch (token->type) { case TK_M_ACTION: { sd_device_action_t a; r = sd_device_get_action(dev, &a); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to get uevent action type: %m"); + return log_event_error_errno(dev, token, r, "Failed to get uevent action type: %m"); return token_match_string(token, device_action_to_string(a)); } @@ -1665,7 +1644,7 @@ static int udev_rule_apply_token_to_event( r = sd_device_get_devpath(dev, &val); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to get devpath: %m"); + return log_event_error_errno(dev, token, r, "Failed to get devpath: %m"); return token_match_string(token, val); } @@ -1675,7 +1654,7 @@ static int udev_rule_apply_token_to_event( r = sd_device_get_sysname(dev, &val); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to get sysname: %m"); + return log_event_error_errno(dev, token, r, "Failed to get sysname: %m"); return token_match_string(token, val); } @@ -1725,7 +1704,7 @@ static int udev_rule_apply_token_to_event( if (r == -ENOENT) val = NULL; else if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to get subsystem: %m"); + return log_event_error_errno(dev, token, r, "Failed to get subsystem: %m"); return token_match_string(token, val); } @@ -1737,13 +1716,13 @@ static int udev_rule_apply_token_to_event( if (r == -ENOENT) val = NULL; else if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to get driver: %m"); + return log_event_error_errno(dev, token, r, "Failed to get driver: %m"); return token_match_string(token, val); } case TK_M_ATTR: case TK_M_PARENTS_ATTR: - return token_match_attr(rules, token, dev, event); + return token_match_attr(token, dev, event); case TK_M_SYSCTL: { _cleanup_free_ char *value = NULL; char buf[UDEV_PATH_SIZE]; @@ -1751,14 +1730,15 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The sysctl entry name '%s' is truncated while substituting into '%s', " - "assuming the SYSCTL key does not match.", buf, (const char*) token->data); + log_event_debug(dev, token, + "The sysctl entry name '%s' is truncated while substituting into '%s', " + "assuming the SYSCTL key does not match.", buf, (const char*) token->data); return false; } r = sysctl_read(sysctl_normalize(buf), &value); if (r < 0 && r != -ENOENT) - return log_rule_error_errno(dev, rules, r, "Failed to read sysctl '%s': %m", buf); + return log_event_error_errno(dev, token, r, "Failed to read sysctl '%s': %m", buf); return token_match_string(token, strstrip(value)); } @@ -1770,8 +1750,9 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The file name '%s' is truncated while substituting into '%s', " - "assuming the TEST key does not match", buf, token->value); + log_event_debug(dev, token, + "The file name '%s' is truncated while substituting into '%s', " + "assuming the TEST key does not match", buf, token->value); return false; } @@ -1782,7 +1763,7 @@ static int udev_rule_apply_token_to_event( r = sd_device_get_syspath(dev, &val); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to get syspath: %m"); + return log_event_error_errno(dev, token, r, "Failed to get syspath: %m"); strscpy_full(tmp, sizeof(tmp), buf, &truncated); assert(!truncated); @@ -1795,7 +1776,7 @@ static int udev_rule_apply_token_to_event( if (r == -ENOENT) return token->op == OP_NOMATCH; if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to test for the existence of '%s': %m", buf); + return log_event_error_errno(dev, token, r, "Failed to test for the existence of '%s': %m", buf); if (stat(buf, &statbuf) < 0) return token->op == OP_NOMATCH; @@ -1814,27 +1795,29 @@ static int udev_rule_apply_token_to_event( event->program_result = mfree(event->program_result); (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The command '%s' is truncated while substituting into '%s', " - "assuming the PROGRAM key does not match.", buf, token->value); + log_event_debug(dev, token, + "The command '%s' is truncated while substituting into '%s', " + "assuming the PROGRAM key does not match.", buf, token->value); return false; } - log_rule_debug(dev, rules, "Running PROGRAM '%s'", buf); + log_event_debug(dev, token, "Running PROGRAM '%s'", buf); r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof(result), NULL); if (r != 0) { if (r < 0) - log_rule_warning_errno(dev, rules, r, "Failed to execute \"%s\": %m", buf); + log_event_warning_errno(dev, token, r, "Failed to execute \"%s\": %m", buf); else /* returned value is positive when program fails */ - log_rule_debug(dev, rules, "Command \"%s\" returned %d (error)", buf, r); + log_event_debug(dev, token, "Command \"%s\" returned %d (error)", buf, r); return token->op == OP_NOMATCH; } delete_trailing_chars(result, "\n"); count = udev_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT); if (count > 0) - log_rule_debug(dev, rules, "Replaced %zu character(s) in result of \"%s\"", - count, buf); + log_event_debug(dev, token, + "Replaced %zu character(s) in result of \"%s\"", + count, buf); event->program_result = strdup(result); return token->op == OP_MATCH; @@ -1846,18 +1829,18 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The file name '%s' to be imported is truncated while substituting into '%s', " - "assuming the IMPORT key does not match.", buf, token->value); + log_event_debug(dev, token, + "The file name '%s' to be imported is truncated while substituting into '%s', " + "assuming the IMPORT key does not match.", buf, token->value); return false; } - log_rule_debug(dev, rules, "Importing properties from '%s'", buf); + log_event_debug(dev, token, "Importing properties from '%s'", buf); f = fopen(buf, "re"); if (!f) { if (errno != ENOENT) - return log_rule_error_errno(dev, rules, errno, - "Failed to open '%s': %m", buf); + return log_event_error_errno(dev, token, errno, "Failed to open '%s': %m", buf); return token->op == OP_NOMATCH; } @@ -1867,8 +1850,7 @@ static int udev_rule_apply_token_to_event( r = read_line(f, LONG_LINE_MAX, &line); if (r < 0) { - log_rule_debug_errno(dev, rules, r, - "Failed to read '%s', ignoring: %m", buf); + log_event_debug_errno(dev, token, r, "Failed to read '%s', ignoring: %m", buf); return token->op == OP_NOMATCH; } if (r == 0) @@ -1876,9 +1858,9 @@ static int udev_rule_apply_token_to_event( r = get_property_from_string(line, &key, &value); if (r < 0) { - log_rule_debug_errno(dev, rules, r, - "Failed to parse key and value from '%s', ignoring: %m", - line); + log_event_debug_errno(dev, token, r, + "Failed to parse key and value from '%s', ignoring: %m", + line); continue; } if (r == 0) @@ -1886,9 +1868,9 @@ static int udev_rule_apply_token_to_event( r = device_add_property(dev, key, value); if (r < 0) - return log_rule_error_errno(dev, rules, r, - "Failed to add property %s=%s: %m", - key, value); + return log_event_error_errno(dev, token, r, + "Failed to add property %s=%s: %m", + key, value); } return token->op == OP_MATCH; @@ -1900,19 +1882,20 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The command '%s' is truncated while substituting into '%s', " - "assuming the IMPORT key does not match.", buf, token->value); + log_event_debug(dev, token, + "The command '%s' is truncated while substituting into '%s', " + "assuming the IMPORT key does not match.", buf, token->value); return false; } - log_rule_debug(dev, rules, "Importing properties from results of '%s'", buf); + log_event_debug(dev, token, "Importing properties from results of '%s'", buf); r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof result, &truncated); if (r != 0) { if (r < 0) - log_rule_warning_errno(dev, rules, r, "Failed to execute '%s', ignoring: %m", buf); + log_event_warning_errno(dev, token, r, "Failed to execute '%s', ignoring: %m", buf); else /* returned value is positive when program fails */ - log_rule_debug(dev, rules, "Command \"%s\" returned %d (error), ignoring", buf, r); + log_event_debug(dev, token, "Command \"%s\" returned %d (error), ignoring", buf, r); return token->op == OP_NOMATCH; } @@ -1932,8 +1915,8 @@ static int udev_rule_apply_token_to_event( if (r == -ENOMEM) return log_oom(); if (r < 0) { - log_rule_warning_errno(dev, rules, r, - "Failed to extract lines from result of command \"%s\", ignoring: %m", buf); + log_event_warning_errno(dev, token, r, + "Failed to extract lines from result of command \"%s\", ignoring: %m", buf); return false; } @@ -1942,9 +1925,9 @@ static int udev_rule_apply_token_to_event( r = get_property_from_string(*line, &key, &value); if (r < 0) { - log_rule_debug_errno(dev, rules, r, - "Failed to parse key and value from '%s', ignoring: %m", - *line); + log_event_debug_errno(dev, token, r, + "Failed to parse key and value from '%s', ignoring: %m", + *line); continue; } if (r == 0) @@ -1952,9 +1935,9 @@ static int udev_rule_apply_token_to_event( r = device_add_property(dev, key, value); if (r < 0) - return log_rule_error_errno(dev, rules, r, - "Failed to add property %s=%s: %m", - key, value); + return log_event_error_errno(dev, token, r, + "Failed to add property %s=%s: %m", + key, value); } return token->op == OP_MATCH; @@ -1969,8 +1952,8 @@ static int udev_rule_apply_token_to_event( if (udev_builtin_run_once(cmd)) { /* check if we ran already */ if (event->builtin_run & mask) { - log_rule_debug(dev, rules, "Skipping builtin '%s' in IMPORT key", - udev_builtin_name(cmd)); + log_event_debug(dev, token, "Skipping builtin '%s' in IMPORT key", + udev_builtin_name(cmd)); /* return the result from earlier run */ return token->op == (event->builtin_ret & mask ? OP_NOMATCH : OP_MATCH); } @@ -1980,17 +1963,18 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The builtin command '%s' is truncated while substituting into '%s', " - "assuming the IMPORT key does not match", buf, token->value); + log_event_debug(dev, token, + "The builtin command '%s' is truncated while substituting into '%s', " + "assuming the IMPORT key does not match", buf, token->value); return false; } - log_rule_debug(dev, rules, "Importing properties from results of builtin command '%s'", buf); + log_event_debug(dev, token, "Importing properties from results of builtin command '%s'", buf); r = udev_builtin_run(dev, &event->rtnl, cmd, buf, false); if (r < 0) { /* remember failure */ - log_rule_debug_errno(dev, rules, r, "Failed to run builtin '%s': %m", buf); + log_event_debug_errno(dev, token, r, "Failed to run builtin '%s': %m", buf); event->builtin_ret |= mask; } return token->op == (r >= 0 ? OP_MATCH : OP_NOMATCH); @@ -2004,14 +1988,14 @@ static int udev_rule_apply_token_to_event( if (r == -ENOENT) return token->op == OP_NOMATCH; if (r < 0) - return log_rule_error_errno(dev, rules, r, - "Failed to get property '%s' from database: %m", - token->value); + return log_event_error_errno(dev, token, r, + "Failed to get property '%s' from database: %m", + token->value); r = device_add_property(dev, token->value, val); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to add property '%s=%s': %m", - token->value, val); + return log_event_error_errno(dev, token, r, "Failed to add property '%s=%s': %m", + token->value, val); return token->op == OP_MATCH; } case TK_M_IMPORT_CMDLINE: { @@ -2019,16 +2003,16 @@ static int udev_rule_apply_token_to_event( r = proc_cmdline_get_key(token->value, PROC_CMDLINE_VALUE_OPTIONAL|PROC_CMDLINE_IGNORE_EFI_OPTIONS, &value); if (r < 0) - return log_rule_error_errno(dev, rules, r, - "Failed to read '%s' option from /proc/cmdline: %m", - token->value); + return log_event_error_errno(dev, token, r, + "Failed to read '%s' option from /proc/cmdline: %m", + token->value); if (r == 0) return token->op == OP_NOMATCH; r = device_add_property(dev, token->value, value ?: "1"); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to add property '%s=%s': %m", - token->value, value ?: "1"); + return log_event_error_errno(dev, token, r, "Failed to add property '%s=%s': %m", + token->value, value ?: "1"); return token->op == OP_MATCH; } case TK_M_IMPORT_PARENT: { @@ -2037,16 +2021,17 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_debug(dev, rules, "The property name '%s' is truncated while substituting into '%s', " - "assuming the IMPORT key does not match.", buf, token->value); + log_event_debug(dev, token, + "The property name '%s' is truncated while substituting into '%s', " + "assuming the IMPORT key does not match.", buf, token->value); return false; } r = import_parent_into_properties(dev, buf); if (r < 0) - return log_rule_error_errno(dev, rules, r, - "Failed to import properties '%s' from parent: %m", - buf); + return log_event_error_errno(dev, token, r, + "Failed to import properties '%s' from parent: %m", + buf); return token->op == (r > 0 ? OP_MATCH : OP_NOMATCH); } case TK_M_RESULT: @@ -2099,16 +2084,17 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The user name '%s' is truncated while substituting into '%s', " - "refusing to apply the OWNER key.", owner, token->value); + log_event_warning(dev, token, + "The user name '%s' is truncated while substituting into '%s', " + "refusing to apply the OWNER key.", owner, token->value); break; } r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING); if (r < 0) - log_unknown_owner(dev, rules, r, "user", owner); + log_unknown_owner(dev, token->rule_line, r, "user", owner); else - log_rule_debug(dev, rules, "OWNER %s(%u)", owner, event->uid); + log_event_debug(dev, token, "OWNER %s(%u)", owner, event->uid); break; } case TK_A_GROUP: { @@ -2123,16 +2109,17 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, group, sizeof(group), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The group name '%s' is truncated while substituting into '%s', " - "refusing to apply the GROUP key.", group, token->value); + log_event_warning(dev, token, + "The group name '%s' is truncated while substituting into '%s', " + "refusing to apply the GROUP key.", group, token->value); break; } r = get_group_creds(&gr, &event->gid, USER_CREDS_ALLOW_MISSING); if (r < 0) - log_unknown_owner(dev, rules, r, "group", group); + log_unknown_owner(dev, token->rule_line, r, "group", group); else - log_rule_debug(dev, rules, "GROUP %s(%u)", group, event->gid); + log_event_debug(dev, token, "GROUP %s(%u)", group, event->gid); break; } case TK_A_MODE: { @@ -2146,16 +2133,17 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The mode '%s' is truncated while substituting into %s, " - "refusing to apply the MODE key.", mode_str, token->value); + log_event_warning(dev, token, + "The mode '%s' is truncated while substituting into %s, " + "refusing to apply the MODE key.", mode_str, token->value); break; } r = parse_mode(mode_str, &event->mode); if (r < 0) - log_rule_error_errno(dev, rules, r, "Failed to parse mode '%s', ignoring: %m", mode_str); + log_event_error_errno(dev, token, r, "Failed to parse mode '%s', ignoring: %m", mode_str); else - log_rule_debug(dev, rules, "MODE %#o", event->mode); + log_event_debug(dev, token, "MODE %#o", event->mode); break; } case TK_A_OWNER_ID: @@ -2166,7 +2154,7 @@ static int udev_rule_apply_token_to_event( if (!token->data) break; event->uid = PTR_TO_UID(token->data); - log_rule_debug(dev, rules, "OWNER %u", event->uid); + log_event_debug(dev, token, "OWNER %u", event->uid); break; case TK_A_GROUP_ID: if (event->group_final) @@ -2176,7 +2164,7 @@ static int udev_rule_apply_token_to_event( if (!token->data) break; event->gid = PTR_TO_GID(token->data); - log_rule_debug(dev, rules, "GROUP %u", event->gid); + log_event_debug(dev, token, "GROUP %u", event->gid); break; case TK_A_MODE_ID: if (event->mode_final) @@ -2186,7 +2174,7 @@ static int udev_rule_apply_token_to_event( if (!token->data) break; event->mode = PTR_TO_MODE(token->data); - log_rule_debug(dev, rules, "MODE %#o", event->mode); + log_event_debug(dev, token, "MODE %#o", event->mode); break; case TK_A_SECLABEL: { _cleanup_free_ char *name = NULL, *label = NULL; @@ -2199,8 +2187,9 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The security label '%s' is truncated while substituting into '%s', " - "refusing to apply the SECLABEL key.", label_str, token->value); + log_event_warning(dev, token, + "The security label '%s' is truncated while substituting into '%s', " + "refusing to apply the SECLABEL key.", label_str, token->value); break; } @@ -2218,9 +2207,9 @@ static int udev_rule_apply_token_to_event( if (r == -ENOMEM) return log_oom(); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to store SECLABEL{%s}='%s': %m", name, label); + return log_event_error_errno(dev, token, r, "Failed to store SECLABEL{%s}='%s': %m", name, label); - log_rule_debug(dev, rules, "SECLABEL{%s}='%s'", name, label); + log_event_debug(dev, token, "SECLABEL{%s}='%s'", name, label); TAKE_PTR(name); TAKE_PTR(label); @@ -2237,7 +2226,7 @@ static int udev_rule_apply_token_to_event( break; r = device_add_property(dev, name, NULL); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to remove property '%s': %m", name); + return log_event_error_errno(dev, token, r, "Failed to remove property '%s': %m", name); break; } @@ -2245,29 +2234,32 @@ static int udev_rule_apply_token_to_event( sd_device_get_property_value(dev, name, &val) >= 0) { l = strpcpyl_full(&p, l, &truncated, val, " ", NULL); if (truncated) { - log_rule_warning(dev, rules, "The buffer for the property '%s' is full, " - "refusing to append the new value '%s'.", name, token->value); + log_event_warning(dev, token, + "The buffer for the property '%s' is full, " + "refusing to append the new value '%s'.", name, token->value); break; } } (void) udev_event_apply_format(event, token->value, p, l, false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The property value '%s' is truncated while substituting into '%s', " - "refusing to add property '%s'.", p, token->value, name); + log_event_warning(dev, token, + "The property value '%s' is truncated while substituting into '%s', " + "refusing to add property '%s'.", p, token->value, name); break; } if (event->esc == ESCAPE_REPLACE) { count = udev_replace_chars(p, NULL); if (count > 0) - log_rule_debug(dev, rules, "Replaced %zu slash(es) from result of ENV{%s}%s=\"%s\"", - count, name, token->op == OP_ADD ? "+" : "", token->value); + log_event_debug(dev, token, + "Replaced %zu slash(es) from result of ENV{%s}%s=\"%s\"", + count, name, token->op == OP_ADD ? "+" : "", token->value); } r = device_add_property(dev, name, value_new); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to add property '%s=%s': %m", name, value_new); + return log_event_error_errno(dev, token, r, "Failed to add property '%s=%s': %m", name, value_new); break; } case TK_A_TAG: { @@ -2276,9 +2268,10 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The tag name '%s' is truncated while substituting into '%s'," - "refusing to %s the tag.", buf, token->value, - token->op == OP_REMOVE ? "remove" : "add"); + log_event_warning(dev, token, + "The tag name '%s' is truncated while substituting into '%s'," + "refusing to %s the tag.", buf, token->value, + token->op == OP_REMOVE ? "remove" : "add"); break; } @@ -2286,7 +2279,7 @@ static int udev_rule_apply_token_to_event( device_cleanup_tags(dev); if (buf[strspn(buf, ALPHANUMERICAL "-_")] != '\0') { - log_rule_error(dev, rules, "Invalid tag name '%s', ignoring", buf); + log_event_error(dev, token, "Invalid tag name '%s', ignoring", buf); break; } if (token->op == OP_REMOVE) @@ -2294,7 +2287,7 @@ static int udev_rule_apply_token_to_event( else { r = device_add_tag(dev, buf, true); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to add tag '%s': %m", buf); + return log_event_error_errno(dev, token, r, "Failed to add tag '%s': %m", buf); } break; } @@ -2309,16 +2302,17 @@ static int udev_rule_apply_token_to_event( event->name_final = true; if (sd_device_get_ifindex(dev, NULL) < 0) { - log_rule_error(dev, rules, - "Only network interfaces can be renamed, ignoring NAME=\"%s\".", - token->value); + log_event_error(dev, token, + "Only network interfaces can be renamed, ignoring NAME=\"%s\".", + token->value); break; } (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The network interface name '%s' is truncated while substituting into '%s', " - "refusing to set the name.", buf, token->value); + log_event_warning(dev, token, + "The network interface name '%s' is truncated while substituting into '%s', " + "refusing to set the name.", buf, token->value); break; } @@ -2328,14 +2322,15 @@ static int udev_rule_apply_token_to_event( else count = udev_replace_chars(buf, "/"); if (count > 0) - log_rule_debug(dev, rules, "Replaced %zu character(s) from result of NAME=\"%s\"", - count, token->value); + log_event_debug(dev, token, + "Replaced %zu character(s) from result of NAME=\"%s\"", + count, token->value); } r = free_and_strdup_warn(&event->name, buf); if (r < 0) return r; - log_rule_debug(dev, rules, "NAME '%s'", event->name); + log_event_debug(dev, token, "NAME '%s'", event->name); break; } case TK_A_DEVLINK: { @@ -2355,8 +2350,9 @@ static int udev_rule_apply_token_to_event( /* allow multiple symlinks separated by spaces */ (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), event->esc != ESCAPE_NONE, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The symbolic link path '%s' is truncated while substituting into '%s', " - "refusing to add the device symbolic link.", buf, token->value); + log_event_warning(dev, token, + "The symbolic link path '%s' is truncated while substituting into '%s', " + "refusing to add the device symbolic link.", buf, token->value); break; } @@ -2367,8 +2363,9 @@ static int udev_rule_apply_token_to_event( else count = 0; if (count > 0) - log_rule_debug(dev, rules, "Replaced %zu character(s) from result of SYMLINK=\"%s\"", - count, token->value); + log_event_debug(dev, token, + "Replaced %zu character(s) from result of SYMLINK=\"%s\"", + count, token->value); p = skip_leading_chars(buf, NULL); while (!isempty(p)) { @@ -2386,13 +2383,13 @@ static int udev_rule_apply_token_to_event( if (token->op == OP_REMOVE) { device_remove_devlink(dev, filename); - log_rule_debug(dev, rules, "Dropped SYMLINK '%s'", p); + log_event_debug(dev, token, "Dropped SYMLINK '%s'", p); } else { r = device_add_devlink(dev, filename); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to add devlink '%s': %m", filename); + return log_event_error_errno(dev, token, r, "Failed to add devlink '%s': %m", filename); - log_rule_debug(dev, rules, "Added SYMLINK '%s'", p); + log_event_debug(dev, token, "Added SYMLINK '%s'", p); } p = next; @@ -2408,33 +2405,34 @@ static int udev_rule_apply_token_to_event( sd_device_get_syspath(dev, &val) >= 0) { strscpyl_full(buf, sizeof(buf), &truncated, val, "/", key_name, NULL); if (truncated) { - log_rule_warning(dev, rules, - "The path to the attribute '%s/%s' is too long, refusing to set the attribute.", - val, key_name); + log_event_warning(dev, token, + "The path to the attribute '%s/%s' is too long, refusing to set the attribute.", + val, key_name); break; } } r = attr_subst_subdir(buf); if (r < 0) { - log_rule_error_errno(dev, rules, r, "Could not find file matches '%s', ignoring: %m", buf); + log_event_error_errno(dev, token, r, "Could not find file matches '%s', ignoring: %m", buf); break; } (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The attribute value '%s' is truncated while substituting into '%s', " - "refusing to set the attribute '%s'", value, token->value, buf); + log_event_warning(dev, token, + "The attribute value '%s' is truncated while substituting into '%s', " + "refusing to set the attribute '%s'", value, token->value, buf); break; } - log_rule_debug(dev, rules, "ATTR '%s' writing '%s'", buf, value); + log_event_debug(dev, token, "ATTR '%s' writing '%s'", buf, value); r = write_string_file(buf, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_AVOID_NEWLINE | WRITE_STRING_FILE_VERIFY_IGNORE_NEWLINE); if (r < 0) - log_rule_error_errno(dev, rules, r, "Failed to write ATTR{%s}, ignoring: %m", buf); + log_event_error_errno(dev, token, r, "Failed to write ATTR{%s}, ignoring: %m", buf); break; } case TK_A_SYSCTL: { @@ -2443,23 +2441,25 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The sysctl entry name '%s' is truncated while substituting into '%s', " - "refusing to set the sysctl entry.", buf, (const char*) token->data); + log_event_warning(dev, token, + "The sysctl entry name '%s' is truncated while substituting into '%s', " + "refusing to set the sysctl entry.", buf, (const char*) token->data); break; } (void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The sysctl value '%s' is truncated while substituting into '%s', " - "refusing to set the sysctl entry '%s'", value, token->value, buf); + log_event_warning(dev, token, + "The sysctl value '%s' is truncated while substituting into '%s', " + "refusing to set the sysctl entry '%s'", value, token->value, buf); break; } sysctl_normalize(buf); - log_rule_debug(dev, rules, "SYSCTL '%s' writing '%s'", buf, value); + log_event_debug(dev, token, "SYSCTL '%s' writing '%s'", buf, value); r = sysctl_write(buf, value); if (r < 0) - log_rule_error_errno(dev, rules, r, "Failed to write SYSCTL{%s}='%s', ignoring: %m", buf, value); + log_event_error_errno(dev, token, r, "Failed to write SYSCTL{%s}='%s', ignoring: %m", buf, value); break; } case TK_A_RUN_BUILTIN: @@ -2478,8 +2478,9 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated); if (truncated) { - log_rule_warning(dev, rules, "The command '%s' is truncated while substituting into '%s', " - "refusing to invoke the command.", buf, token->value); + log_event_warning(dev, token, + "The command '%s' is truncated while substituting into '%s', " + "refusing to invoke the command.", buf, token->value); break; } @@ -2491,11 +2492,11 @@ static int udev_rule_apply_token_to_event( if (r == -ENOMEM) return log_oom(); if (r < 0) - return log_rule_error_errno(dev, rules, r, "Failed to store command '%s': %m", cmd); + return log_event_error_errno(dev, token, r, "Failed to store command '%s': %m", cmd); TAKE_PTR(cmd); - log_rule_debug(dev, rules, "RUN '%s'", token->value); + log_event_debug(dev, token, "RUN '%s'", token->value); break; } case TK_A_OPTIONS_STATIC_NODE: @@ -2513,29 +2514,23 @@ static bool token_is_for_parents(UdevRuleToken *token) { } static int udev_rule_apply_parent_token_to_event( - UdevRules *rules, + UdevRuleToken *head_token, UdevEvent *event, int timeout_signal) { - UdevRuleLine *line; - UdevRuleToken *head; int r; - assert(rules); - assert(rules->current_file); + assert(head_token); assert(event); - line = ASSERT_PTR(rules->current_file->current_line); - head = ASSERT_PTR(rules->current_file->current_line->current_token); event->dev_parent = ASSERT_PTR(event->dev); for (;;) { - LIST_FOREACH(tokens, token, head) { + LIST_FOREACH(tokens, token, head_token) { if (!token_is_for_parents(token)) return true; /* All parent tokens match. */ - line->current_token = token; - r = udev_rule_apply_token_to_event(rules, event->dev_parent, event, 0, timeout_signal, NULL); + r = udev_rule_apply_token_to_event(token, event->dev_parent, event, 0, timeout_signal, NULL); if (r < 0) return r; if (r == 0) @@ -2553,19 +2548,22 @@ static int udev_rule_apply_parent_token_to_event( } static int udev_rule_apply_line_to_event( - UdevRules *rules, + UdevRuleLine *line, UdevEvent *event, usec_t timeout_usec, int timeout_signal, Hashmap *properties_list, UdevRuleLine **next_line) { - UdevRuleLine *line = rules->current_file->current_line; UdevRuleLineType mask = LINE_HAS_GOTO | LINE_UPDATE_SOMETHING; bool parents_done = false; sd_device_action_t action; int r; + assert(line); + assert(event); + assert(next_line); + r = sd_device_get_action(event->dev, &action); if (r < 0) return r; @@ -2586,13 +2584,11 @@ static int udev_rule_apply_line_to_event( DEVICE_TRACE_POINT(rules_apply_line, event->dev, line->rule_file->filename, line->line_number); LIST_FOREACH(tokens, token, line->tokens) { - line->current_token = token; - if (token_is_for_parents(token)) { if (parents_done) continue; - r = udev_rule_apply_parent_token_to_event(rules, event, timeout_signal); + r = udev_rule_apply_parent_token_to_event(token, event, timeout_signal); if (r <= 0) return r; @@ -2600,13 +2596,13 @@ static int udev_rule_apply_line_to_event( continue; } - r = udev_rule_apply_token_to_event(rules, event->dev, event, timeout_usec, timeout_signal, properties_list); + r = udev_rule_apply_token_to_event(token, event->dev, event, timeout_usec, timeout_signal, properties_list); if (r <= 0) return r; } if (line->goto_line) - *next_line = line->goto_line; + *next_line = line->goto_line; /* update next_line only when the line has GOTO token. */ return 0; } @@ -2623,15 +2619,12 @@ int udev_rules_apply_to_event( assert(rules); assert(event); - LIST_FOREACH(rule_files, file, rules->rule_files) { - rules->current_file = file; + LIST_FOREACH(rule_files, file, rules->rule_files) LIST_FOREACH_WITH_NEXT(rule_lines, line, next_line, file->rule_lines) { - file->current_line = line; - r = udev_rule_apply_line_to_event(rules, event, timeout_usec, timeout_signal, properties_list, &next_line); + r = udev_rule_apply_line_to_event(line, event, timeout_usec, timeout_signal, properties_list, &next_line); if (r < 0) return r; } - } return 0; } diff --git a/src/udev/udev-rules.h b/src/udev/udev-rules.h index 44f30e1c137..cecc285b2cc 100644 --- a/src/udev/udev-rules.h +++ b/src/udev/udev-rules.h @@ -6,6 +6,7 @@ #include "time-util.h" #include "udev-util.h" +typedef struct UdevRuleFile UdevRuleFile; typedef struct UdevRules UdevRules; typedef struct UdevEvent UdevEvent; @@ -17,8 +18,8 @@ typedef enum { _ESCAPE_TYPE_INVALID = -EINVAL, } UdevRuleEscapeType; -int udev_rules_parse_file(UdevRules *rules, const char *filename); -unsigned udev_check_current_rule_file(UdevRules *rules); +int udev_rules_parse_file(UdevRules *rules, const char *filename, UdevRuleFile **ret); +unsigned udev_rule_file_get_issues(UdevRuleFile *rule_file); UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing); int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing); UdevRules *udev_rules_free(UdevRules *rules); diff --git a/src/udev/udevadm-verify.c b/src/udev/udevadm-verify.c index 26f317711e9..576120c0e15 100644 --- a/src/udev/udevadm-verify.c +++ b/src/udev/udevadm-verify.c @@ -101,13 +101,16 @@ static int parse_argv(int argc, char *argv[]) { } static int verify_rules_file(UdevRules *rules, const char *fname) { + UdevRuleFile *file; int r; - r = udev_rules_parse_file(rules, fname); + r = udev_rules_parse_file(rules, fname, &file); if (r < 0) return log_error_errno(r, "Failed to parse rules file %s: %m", fname); + if (r == 0) /* empty file. */ + return 0; - unsigned issues = udev_check_current_rule_file(rules); + unsigned issues = udev_rule_file_get_issues(file); unsigned mask = (1U << LOG_ERR) | (1U << LOG_WARNING); if (issues & mask) return log_error_errno(SYNTHETIC_ERRNO(EINVAL),