Merge pull request #12905 from keszybz/udev-warnings

Udev warnings
This commit is contained in:
Yu Watanabe
2019-06-29 03:35:12 +09:00
committed by GitHub
4 changed files with 291 additions and 267 deletions
+32 -17
View File
@@ -157,24 +157,24 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType
assert(*str);
assert(ret_type);
if (p[0] == '$') {
if (*p == '$') {
p++;
if (p[0] == '$') {
if (*p == '$') {
*str = p;
return 0;
}
for (i = 0; i < ELEMENTSOF(map); i++)
if ((q = startswith(p, map[i].name)))
break;
} else if (p[0] == '%') {
} else if (*p == '%') {
p++;
if (p[0] == '%') {
if (*p == '%') {
*str = p;
return 0;
}
for (i = 0; i < ELEMENTSOF(map); i++)
if (p[0] == map[i].fmt) {
if (*p == map[i].fmt) {
q = p + 1;
break;
}
@@ -184,7 +184,7 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType
/* When 'strict' flag is set, then '$' and '%' must be escaped. */
return strict ? -EINVAL : 0;
if (q[0] == '{') {
if (*q == '{') {
const char *start, *end;
size_t len;
@@ -200,7 +200,7 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType
strnscpy(ret_attr, UTIL_PATH_SIZE, start, len);
q = end + 1;
} else
ret_attr[0] = '\0';
*ret_attr = '\0';
*str = q;
*ret_type = map[i].type;
@@ -311,7 +311,7 @@ static ssize_t udev_event_subst_format(
p = skip_leading_chars(event->program_result, NULL);
for (i = 1; i < index; i++) {
while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
while (*p && !strchr(WHITESPACE, *p))
p++;
p = skip_leading_chars(p, NULL);
if (*p == '\0')
@@ -327,7 +327,7 @@ static ssize_t udev_event_subst_format(
if (has_plus)
l = strpcpy(&s, l, start);
else {
while (p[0] != '\0' && !strchr(WHITESPACE, p[0]))
while (*p && !strchr(WHITESPACE, *p))
p++;
l = strnpcpy(&s, l, start, p - start);
}
@@ -447,7 +447,7 @@ ssize_t udev_event_apply_format(UdevEvent *event,
assert(dest);
assert(size > 0);
while (s[0] != '\0') {
while (*s) {
FormatSubstitutionType type;
char attr[UTIL_PATH_SIZE];
ssize_t subst_len;
@@ -480,33 +480,48 @@ ssize_t udev_event_apply_format(UdevEvent *event,
}
assert(size >= 1);
dest[0] = '\0';
*dest = '\0';
return size;
}
int udev_check_format(const char *s) {
int udev_check_format(const char *value, size_t *offset, const char **hint) {
FormatSubstitutionType type;
const char *s = value;
char attr[UTIL_PATH_SIZE];
int r;
while (s[0] != '\0') {
while (*s) {
r = get_subst_type(&s, true, &type, attr);
if (r < 0)
if (r < 0) {
if (offset)
*offset = s - value;
if (hint)
*hint = "invalid substitution type";
return r;
if (r == 0) {
} else if (r == 0) {
s++;
continue;
}
if (IN_SET(type, FORMAT_SUBST_ATTR, FORMAT_SUBST_ENV) && isempty(attr))
if (IN_SET(type, FORMAT_SUBST_ATTR, FORMAT_SUBST_ENV) && isempty(attr)) {
if (offset)
*offset = s - value;
if (hint)
*hint = "attribute value missing";
return -EINVAL;
}
if (type == FORMAT_SUBST_RESULT && !isempty(attr)) {
unsigned i;
r = safe_atou_optional_plus(attr, &i);
if (r < 0)
if (r < 0) {
if (offset)
*offset = s - value;
if (hint)
*hint = "attribute value not a valid number";
return r;
}
}
}
+1 -1
View File
@@ -51,7 +51,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free);
ssize_t udev_event_apply_format(UdevEvent *event,
const char *src, char *dest, size_t size,
bool replace_whitespace);
int udev_check_format(const char *s);
int udev_check_format(const char *value, size_t *offset, const char **hint);
int udev_event_spawn(UdevEvent *event,
usec_t timeout_usec,
bool accept_failure,
+258 -50
View File
@@ -14,6 +14,7 @@
#include "fs-util.h"
#include "glob-util.h"
#include "libudev-util.h"
#include "list.h"
#include "mkdir.h"
#include "nulstr-util.h"
#include "parse-util.h"
@@ -30,6 +31,217 @@
#define RULES_DIRS (const char* const*) CONF_PATHS_STRV("udev/rules.d")
typedef enum {
OP_MATCH, /* == */
OP_NOMATCH, /* != */
OP_ADD, /* += */
OP_REMOVE, /* -= */
OP_ASSIGN, /* = */
OP_ASSIGN_FINAL, /* := */
_OP_TYPE_MAX,
_OP_TYPE_INVALID = -1
} UdevRuleOperatorType;
typedef enum {
MATCH_TYPE_EMPTY, /* empty string */
MATCH_TYPE_PLAIN, /* no special characters */
MATCH_TYPE_GLOB, /* shell globs ?,*,[] */
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
_MATCH_TYPE_MAX,
_MATCH_TYPE_INVALID = -1
} UdevRuleMatchType;
typedef enum {
SUBST_TYPE_PLAIN, /* no substitution */
SUBST_TYPE_FORMAT, /* % or $ */
SUBST_TYPE_SUBSYS, /* "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
_SUBST_TYPE_MAX,
_SUBST_TYPE_INVALID = -1
} UdevRuleSubstituteType;
typedef enum {
/* lvalues which take match or nomatch operator */
TK_M_ACTION, /* string, device_get_action() */
TK_M_DEVPATH, /* path, sd_device_get_devpath() */
TK_M_KERNEL, /* string, sd_device_get_sysname() */
TK_M_DEVLINK, /* strv, sd_device_get_devlink_first(), sd_device_get_devlink_next() */
TK_M_NAME, /* string, name of network interface */
TK_M_ENV, /* string, device property, takes key through attribute */
TK_M_TAG, /* strv, sd_device_get_tag_first(), sd_device_get_tag_next() */
TK_M_SUBSYSTEM, /* string, sd_device_get_subsystem() */
TK_M_DRIVER, /* string, sd_device_get_driver() */
TK_M_ATTR, /* string, takes filename through attribute, sd_device_get_sysattr_value(), util_resolve_subsys_kernel(), etc. */
TK_M_SYSCTL, /* string, takes kernel parameter through attribute */
/* matches parent paramters */
TK_M_PARENTS_KERNEL, /* string */
TK_M_PARENTS_SUBSYSTEM, /* string */
TK_M_PARENTS_DRIVER, /* string */
TK_M_PARENTS_ATTR, /* string */
TK_M_PARENTS_TAG, /* strv */
TK_M_TEST, /* path, optionally mode_t can be specified by attribute, test the existence of a file */
TK_M_PROGRAM, /* string, execute a program */
TK_M_IMPORT_FILE, /* path */
TK_M_IMPORT_PROGRAM, /* string, import properties from the result of program */
TK_M_IMPORT_BUILTIN, /* string, import properties from the result of built-in command */
TK_M_IMPORT_DB, /* string, import properties from database */
TK_M_IMPORT_CMDLINE, /* string, kernel command line */
TK_M_IMPORT_PARENT, /* string, parent property */
TK_M_RESULT, /* string, result of TK_M_PROGRAM */
#define _TK_M_MAX (TK_M_RESULT + 1)
#define _TK_A_MIN _TK_M_MAX
/* lvalues which take one of assign operators */
TK_A_OPTIONS_STRING_ESCAPE_NONE, /* no argument */
TK_A_OPTIONS_STRING_ESCAPE_REPLACE, /* no argument */
TK_A_OPTIONS_DB_PERSIST, /* no argument */
TK_A_OPTIONS_INOTIFY_WATCH, /* boolean */
TK_A_OPTIONS_DEVLINK_PRIORITY, /* int */
TK_A_OWNER, /* user name */
TK_A_GROUP, /* group name */
TK_A_MODE, /* mode string */
TK_A_OWNER_ID, /* uid_t */
TK_A_GROUP_ID, /* gid_t */
TK_A_MODE_ID, /* mode_t */
TK_A_TAG, /* string */
TK_A_OPTIONS_STATIC_NODE, /* device path, /dev/... */
TK_A_SECLABEL, /* string with attribute */
TK_A_ENV, /* string with attribute */
TK_A_NAME, /* ifname */
TK_A_DEVLINK, /* string */
TK_A_ATTR, /* string with attribute */
TK_A_SYSCTL, /* string with attribute */
TK_A_RUN_BUILTIN, /* string */
TK_A_RUN_PROGRAM, /* string */
_TK_TYPE_MAX,
_TK_TYPE_INVALID = -1,
} UdevRuleTokenType;
typedef enum {
LINE_HAS_NAME = 1 << 0, /* has NAME= */
LINE_HAS_DEVLINK = 1 << 1, /* has SYMLINK=, OWNER=, GROUP= or MODE= */
LINE_HAS_STATIC_NODE = 1 << 2, /* has OPTIONS=static_node */
LINE_HAS_GOTO = 1 << 3, /* has GOTO= */
LINE_HAS_LABEL = 1 << 4, /* has LABEL= */
LINE_UPDATE_SOMETHING = 1 << 5, /* has other TK_A_* or TK_M_IMPORT tokens */
} UdevRuleLineType;
typedef struct UdevRuleFile UdevRuleFile;
typedef struct UdevRuleLine UdevRuleLine;
typedef struct UdevRuleToken UdevRuleToken;
struct UdevRuleToken {
UdevRuleTokenType type:8;
UdevRuleOperatorType op:8;
UdevRuleMatchType match_type:8;
UdevRuleSubstituteType attr_subst_type:7;
bool attr_match_remove_trailing_whitespace:1;
const char *value;
void *data;
LIST_FIELDS(UdevRuleToken, tokens);
};
struct UdevRuleLine {
char *line;
unsigned line_number;
UdevRuleLineType type;
const char *label;
const char *goto_label;
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;
LIST_HEAD(UdevRuleLine, rule_lines);
LIST_FIELDS(UdevRuleFile, rule_files);
};
struct UdevRules {
usec_t dirs_ts_usec;
ResolveNameTiming resolve_name_timing;
Hashmap *known_users;
Hashmap *known_groups;
UdevRuleFile *current_file;
LIST_HEAD(UdevRuleFile, rule_files);
};
/*** Logging helpers ***/
#define log_rule_full(device, rules, level, error, fmt, ...) \
({ \
UdevRules *_r = (rules); \
UdevRuleFile *_f = _r ? _r->current_file : NULL; \
UdevRuleLine *_l = _f ? _f->current_line : NULL; \
const char *_n = _f ? _f->filename : NULL; \
\
log_device_full(device, level, error, "%s:%u " fmt, \
strna(_n), _l ? _l->line_number : 0, \
##__VA_ARGS__); \
})
#define log_rule_debug(device, rules, ...) log_rule_full(device, rules, LOG_DEBUG, 0, ##__VA_ARGS__)
#define log_rule_info(device, rules, ...) log_rule_full(device, rules, LOG_INFO, 0, ##__VA_ARGS__)
#define log_rule_notice(device, rules, ...) log_rule_full(device, rules, LOG_NOTICE, 0, ##__VA_ARGS__)
#define log_rule_warning(device, rules, ...) log_rule_full(device, rules, LOG_WARNING, 0, ##__VA_ARGS__)
#define log_rule_error(device, rules, ...) log_rule_full(device, rules, LOG_ERR, 0, ##__VA_ARGS__)
#define log_rule_debug_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_DEBUG, error, ##__VA_ARGS__)
#define log_rule_info_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_INFO, error, ##__VA_ARGS__)
#define log_rule_notice_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_NOTICE, error, ##__VA_ARGS__)
#define log_rule_warning_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_WARNING, error, ##__VA_ARGS__)
#define log_rule_error_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_ERR, error, ##__VA_ARGS__)
#define log_token_full(rules, ...) log_rule_full(NULL, rules, ##__VA_ARGS__)
#define log_token_debug(rules, ...) log_token_full(rules, LOG_DEBUG, 0, ##__VA_ARGS__)
#define log_token_info(rules, ...) log_token_full(rules, LOG_INFO, 0, ##__VA_ARGS__)
#define log_token_notice(rules, ...) log_token_full(rules, LOG_NOTICE, 0, ##__VA_ARGS__)
#define log_token_warning(rules, ...) log_token_full(rules, LOG_WARNING, 0, ##__VA_ARGS__)
#define log_token_error(rules, ...) log_token_full(rules, LOG_ERR, 0, ##__VA_ARGS__)
#define log_token_debug_errno(rules, error, ...) log_token_full(rules, LOG_DEBUG, error, ##__VA_ARGS__)
#define log_token_info_errno(rules, error, ...) log_token_full(rules, LOG_INFO, error, ##__VA_ARGS__)
#define log_token_notice_errno(rules, error, ...) log_token_full(rules, LOG_NOTICE, error, ##__VA_ARGS__)
#define log_token_warning_errno(rules, error, ...) log_token_full(rules, LOG_WARNING, error, ##__VA_ARGS__)
#define log_token_error_errno(rules, error, ...) log_token_full(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, but please fix it.", \
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, but please fix it.", \
value, key, offset, hint)
static void log_unknown_owner(sd_device *dev, UdevRules *rules, int error, const char *entity, const char *name) {
if (IN_SET(abs(error), ENOENT, ESRCH))
log_rule_error(dev, rules, "Unknown %s '%s', ignoring", entity, name);
else
log_rule_error_errno(dev, rules, error, "Failed to resolve %s '%s', ignoring: %m", entity, name);
}
/*** Other functions ***/
static void udev_rule_token_free(UdevRuleToken *token) {
free(token);
}
@@ -91,13 +303,6 @@ UdevRules *udev_rules_free(UdevRules *rules) {
return mfree(rules);
}
static void log_unknown_owner(sd_device *dev, UdevRules *rules, int error, const char *entity, const char *name) {
if (IN_SET(abs(error), ENOENT, ESRCH))
log_rule_error(dev, rules, "Unknown %s '%s', ignoring", entity, name);
else
log_rule_error_errno(dev, rules, error, "Failed to resolve %s '%s', ignoring: %m", entity, name);
}
static int rule_resolve_user(UdevRules *rules, const char *name, uid_t *ret) {
_cleanup_free_ char *n = NULL;
uid_t uid;
@@ -305,6 +510,27 @@ 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) {
size_t offset;
const char *hint;
if (nonempty && isempty(value))
log_token_invalid_value(rules, 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);
}
static int check_attr_format_and_warn(UdevRules *rules, const char *key, const char *value) {
size_t offset;
const char *hint;
if (isempty(value))
return log_token_invalid_attr(rules, key);
if (udev_check_format(value, &offset, &hint) < 0)
log_token_invalid_attr_format(rules, key, value, offset + 1, hint);
return 0;
}
static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOperatorType op, char *value) {
bool is_match = IN_SET(op, OP_MATCH, OP_NOMATCH);
UdevRuleLine *rule_line;
@@ -346,9 +572,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
return log_token_invalid_op(rules, key);
if (!is_match) {
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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);
@@ -369,8 +593,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (isempty(value))
return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL),
"Ignoring NAME=\"\", as udev will not delete any device nodes.");
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, key, value, false);
r = rule_line_add_token(rule_line, TK_A_NAME, op, value, NULL);
} else
@@ -392,8 +615,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
return log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL),
"Invalid ENV attribute. '%s' cannot be set.", attr);
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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);
@@ -406,8 +629,8 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
}
if (!is_match) {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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);
@@ -429,10 +652,9 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
r = rule_line_add_token(rule_line, TK_M_DRIVER, op, value, NULL);
} else if (streq(key, "ATTR")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (udev_check_format(attr) < 0)
log_token_invalid_attr_format(rules, key, attr);
r = check_attr_format_and_warn(rules, key, attr);
if (r < 0)
return r;
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (IN_SET(op, OP_ADD, OP_ASSIGN_FINAL)) {
@@ -441,17 +663,14 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
}
if (!is_match) {
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (udev_check_format(attr) < 0)
log_token_invalid_attr_format(rules, key, attr);
r = check_attr_format_and_warn(rules, key, attr);
if (r < 0)
return r;
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (IN_SET(op, OP_ADD, OP_ASSIGN_FINAL)) {
@@ -460,9 +679,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
}
if (!is_match) {
if (udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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);
@@ -488,10 +705,9 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
r = rule_line_add_token(rule_line, TK_M_PARENTS_DRIVER, op, value, NULL);
} else if (streq(key, "ATTRS")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (udev_check_format(attr) < 0)
log_token_invalid_attr_format(rules, key, attr);
r = check_attr_format_and_warn(rules, key, attr);
if (r < 0)
return r;
if (!is_match)
return log_token_invalid_op(rules, key);
@@ -516,8 +732,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (r < 0)
return log_token_error_errno(rules, r, "Failed to parse mode '%s': %m", attr);
}
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, key, value, true);
if (!is_match)
return log_token_invalid_op(rules, key);
@@ -525,8 +740,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "PROGRAM")) {
if (attr)
return log_token_invalid_attr(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, key, value, true);
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (!is_match) {
@@ -541,8 +755,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "IMPORT")) {
if (isempty(attr))
return log_token_invalid_attr(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, key, value, true);
if (op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (!is_match) {
@@ -644,8 +857,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
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) {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, key, value, true);
r = rule_line_add_token(rule_line, TK_A_OWNER, op, value, NULL);
} else {
log_token_debug(rules, "Resolving user name is disabled, ignoring %s=%s", key, value);
@@ -673,8 +885,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
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) {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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 %s=%s", key, value);
@@ -695,15 +906,13 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
if (parse_mode(value, &mode) >= 0)
r = rule_line_add_token(rule_line, TK_A_MODE_ID, op, NULL, MODE_TO_PTR(mode));
else {
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, key, value, true);
if (is_match || op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (op == OP_ASSIGN_FINAL) {
@@ -715,8 +924,7 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp
} else if (streq(key, "RUN")) {
if (is_match || op == OP_REMOVE)
return log_token_invalid_op(rules, key);
if (isempty(value) || udev_check_format(value) < 0)
log_token_invalid_value(rules, key, value);
check_value_format_and_warn(rules, 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")) {
-199
View File
@@ -1,46 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0+ */
#pragma once
#include "device-util.h"
#include "hashmap.h"
#include "list.h"
#include "time-util.h"
#include "udev-util.h"
typedef struct UdevRules UdevRules;
typedef struct UdevRuleFile UdevRuleFile;
typedef struct UdevRuleLine UdevRuleLine;
typedef struct UdevRuleToken UdevRuleToken;
typedef struct UdevEvent UdevEvent;
typedef enum {
OP_MATCH, /* == */
OP_NOMATCH, /* != */
OP_ADD, /* += */
OP_REMOVE, /* -= */
OP_ASSIGN, /* = */
OP_ASSIGN_FINAL, /* := */
_OP_TYPE_MAX,
_OP_TYPE_INVALID = -1
} UdevRuleOperatorType;
typedef enum {
MATCH_TYPE_EMPTY, /* empty string */
MATCH_TYPE_PLAIN, /* no special characters */
MATCH_TYPE_GLOB, /* shell globs ?,*,[] */
MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */
_MATCH_TYPE_MAX,
_MATCH_TYPE_INVALID = -1
} UdevRuleMatchType;
typedef enum {
SUBST_TYPE_PLAIN, /* no substitution */
SUBST_TYPE_FORMAT, /* % or $ */
SUBST_TYPE_SUBSYS, /* "[<SUBSYSTEM>/<KERNEL>]<attribute>" format */
_SUBST_TYPE_MAX,
_SUBST_TYPE_INVALID = -1
} UdevRuleSubstituteType;
typedef enum {
ESCAPE_UNSET,
ESCAPE_NONE, /* OPTIONS="string_escape=none" */
@@ -49,118 +16,6 @@ typedef enum {
_ESCAPE_TYPE_INVALID = -1
} UdevRuleEscapeType;
typedef enum {
/* lvalues which take match or nomatch operator */
TK_M_ACTION, /* string, device_get_action() */
TK_M_DEVPATH, /* path, sd_device_get_devpath() */
TK_M_KERNEL, /* string, sd_device_get_sysname() */
TK_M_DEVLINK, /* strv, sd_device_get_devlink_first(), sd_device_get_devlink_next() */
TK_M_NAME, /* string, name of network interface */
TK_M_ENV, /* string, device property, takes key through attribute */
TK_M_TAG, /* strv, sd_device_get_tag_first(), sd_device_get_tag_next() */
TK_M_SUBSYSTEM, /* string, sd_device_get_subsystem() */
TK_M_DRIVER, /* string, sd_device_get_driver() */
TK_M_ATTR, /* string, takes filename through attribute, sd_device_get_sysattr_value(), util_resolve_subsys_kernel(), etc. */
TK_M_SYSCTL, /* string, takes kernel parameter through attribute */
/* matches parent paramters */
TK_M_PARENTS_KERNEL, /* string */
TK_M_PARENTS_SUBSYSTEM, /* string */
TK_M_PARENTS_DRIVER, /* string */
TK_M_PARENTS_ATTR, /* string */
TK_M_PARENTS_TAG, /* strv */
TK_M_TEST, /* path, optionally mode_t can be specified by attribute, test the existence of a file */
TK_M_PROGRAM, /* string, execute a program */
TK_M_IMPORT_FILE, /* path */
TK_M_IMPORT_PROGRAM, /* string, import properties from the result of program */
TK_M_IMPORT_BUILTIN, /* string, import properties from the result of built-in command */
TK_M_IMPORT_DB, /* string, import properties from database */
TK_M_IMPORT_CMDLINE, /* string, kernel command line */
TK_M_IMPORT_PARENT, /* string, parent property */
TK_M_RESULT, /* string, result of TK_M_PROGRAM */
#define _TK_M_MAX (TK_M_RESULT + 1)
#define _TK_A_MIN _TK_M_MAX
/* lvalues which take one of assign operators */
TK_A_OPTIONS_STRING_ESCAPE_NONE, /* no argument */
TK_A_OPTIONS_STRING_ESCAPE_REPLACE, /* no argument */
TK_A_OPTIONS_DB_PERSIST, /* no argument */
TK_A_OPTIONS_INOTIFY_WATCH, /* boolean */
TK_A_OPTIONS_DEVLINK_PRIORITY, /* int */
TK_A_OWNER, /* user name */
TK_A_GROUP, /* group name */
TK_A_MODE, /* mode string */
TK_A_OWNER_ID, /* uid_t */
TK_A_GROUP_ID, /* gid_t */
TK_A_MODE_ID, /* mode_t */
TK_A_TAG, /* string */
TK_A_OPTIONS_STATIC_NODE, /* device path, /dev/... */
TK_A_SECLABEL, /* string with attribute */
TK_A_ENV, /* string with attribute */
TK_A_NAME, /* ifname */
TK_A_DEVLINK, /* string */
TK_A_ATTR, /* string with attribute */
TK_A_SYSCTL, /* string with attribute */
TK_A_RUN_BUILTIN, /* string */
TK_A_RUN_PROGRAM, /* string */
_TK_TYPE_MAX,
_TK_TYPE_INVALID = -1,
} UdevRuleTokenType;
typedef enum {
LINE_HAS_NAME = 1 << 0, /* has NAME= */
LINE_HAS_DEVLINK = 1 << 1, /* has SYMLINK=, OWNER=, GROUP= or MODE= */
LINE_HAS_STATIC_NODE = 1 << 2, /* has OPTIONS=static_node */
LINE_HAS_GOTO = 1 << 3, /* has GOTO= */
LINE_HAS_LABEL = 1 << 4, /* has LABEL= */
LINE_UPDATE_SOMETHING = 1 << 5, /* has other TK_A_* or TK_M_IMPORT tokens */
} UdevRuleLineType;
struct UdevRuleToken {
UdevRuleTokenType type:8;
UdevRuleOperatorType op:8;
UdevRuleMatchType match_type:8;
UdevRuleSubstituteType attr_subst_type:7;
bool attr_match_remove_trailing_whitespace:1;
const char *value;
void *data;
LIST_FIELDS(UdevRuleToken, tokens);
};
struct UdevRuleLine {
char *line;
unsigned line_number;
UdevRuleLineType type;
const char *label;
const char *goto_label;
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;
LIST_HEAD(UdevRuleLine, rule_lines);
LIST_FIELDS(UdevRuleFile, rule_files);
};
struct UdevRules {
usec_t dirs_ts_usec;
ResolveNameTiming resolve_name_timing;
Hashmap *known_users;
Hashmap *known_groups;
UdevRuleFile *current_file;
LIST_HEAD(UdevRuleFile, rule_files);
};
int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing);
UdevRules *udev_rules_free(UdevRules *rules);
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free);
@@ -170,57 +25,3 @@ int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event,
usec_t timeout_usec,
Hashmap *properties_list);
int udev_rules_apply_static_dev_perms(UdevRules *rules);
#define log_rule_full(device, rules, level, error, fmt, ...) \
({ \
UdevRules *_r = (rules); \
UdevRuleFile *_f = _r ? _r->current_file : NULL; \
UdevRuleLine *_l = _f ? _f->current_line : NULL; \
const char *_n = _f ? _f->filename : NULL; \
\
log_device_full(device, level, error, "%s:%u " fmt, \
strna(_n), _l ? _l->line_number : 0, \
##__VA_ARGS__); \
})
#define log_rule_debug(device, rules, ...) log_rule_full(device, rules, LOG_DEBUG, 0, ##__VA_ARGS__)
#define log_rule_info(device, rules, ...) log_rule_full(device, rules, LOG_INFO, 0, ##__VA_ARGS__)
#define log_rule_notice(device, rules, ...) log_rule_full(device, rules, LOG_NOTICE, 0, ##__VA_ARGS__)
#define log_rule_warning(device, rules, ...) log_rule_full(device, rules, LOG_WARNING, 0, ##__VA_ARGS__)
#define log_rule_error(device, rules, ...) log_rule_full(device, rules, LOG_ERR, 0, ##__VA_ARGS__)
#define log_rule_debug_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_DEBUG, error, ##__VA_ARGS__)
#define log_rule_info_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_INFO, error, ##__VA_ARGS__)
#define log_rule_notice_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_NOTICE, error, ##__VA_ARGS__)
#define log_rule_warning_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_WARNING, error, ##__VA_ARGS__)
#define log_rule_error_errno(device, rules, error, ...) log_rule_full(device, rules, LOG_ERR, error, ##__VA_ARGS__)
#define log_token_full(rules, ...) log_rule_full(NULL, rules, ##__VA_ARGS__)
#define log_token_debug(rules, ...) log_token_full(rules, LOG_DEBUG, 0, ##__VA_ARGS__)
#define log_token_info(rules, ...) log_token_full(rules, LOG_INFO, 0, ##__VA_ARGS__)
#define log_token_notice(rules, ...) log_token_full(rules, LOG_NOTICE, 0, ##__VA_ARGS__)
#define log_token_warning(rules, ...) log_token_full(rules, LOG_WARNING, 0, ##__VA_ARGS__)
#define log_token_error(rules, ...) log_token_full(rules, LOG_ERR, 0, ##__VA_ARGS__)
#define log_token_debug_errno(rules, error, ...) log_token_full(rules, LOG_DEBUG, error, ##__VA_ARGS__)
#define log_token_info_errno(rules, error, ...) log_token_full(rules, LOG_INFO, error, ##__VA_ARGS__)
#define log_token_notice_errno(rules, error, ...) log_token_full(rules, LOG_NOTICE, error, ##__VA_ARGS__)
#define log_token_warning_errno(rules, error, ...) log_token_full(rules, LOG_WARNING, error, ##__VA_ARGS__)
#define log_token_error_errno(rules, error, ...) log_token_full(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) \
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
"Invalid attribute \"%s\" for %s, ignoring, but please fix it.", \
attr, key)
#define log_token_invalid_value(rules, key, value) \
log_token_error_errno(rules, SYNTHETIC_ERRNO(EINVAL), \
"Invalid value \"%s\" for %s, ignoring, but please fix it.", \
value, key)