summaryrefslogtreecommitdiff
path: root/udev/udev-rules.c
diff options
context:
space:
mode:
Diffstat (limited to 'udev/udev-rules.c')
-rw-r--r--udev/udev-rules.c199
1 files changed, 96 insertions, 103 deletions
diff --git a/udev/udev-rules.c b/udev/udev-rules.c
index 221865c9dc..63123e083a 100644
--- a/udev/udev-rules.c
+++ b/udev/udev-rules.c
@@ -139,6 +139,7 @@ enum token_type {
TK_M_PARENTS_MAX,
TK_M_TEST, /* val, mode_t */
+ TK_M_EVENT_TIMEOUT, /* int */
TK_M_PROGRAM, /* val */
TK_M_IMPORT_FILE, /* val */
TK_M_IMPORT_PROG, /* val */
@@ -150,6 +151,7 @@ enum token_type {
TK_A_STRING_ESCAPE_NONE,
TK_A_STRING_ESCAPE_REPLACE,
+ TK_A_DB_PERSIST,
TK_A_INOTIFY_WATCH, /* int */
TK_A_DEVLINK_PRIO, /* int */
TK_A_OWNER, /* val */
@@ -163,7 +165,6 @@ enum token_type {
TK_A_TAG, /* val */
TK_A_NAME, /* val */
TK_A_DEVLINK, /* val */
- TK_A_EVENT_TIMEOUT, /* int */
TK_A_ATTR, /* val, attr */
TK_A_RUN, /* val, bool */
TK_A_GOTO, /* size_t */
@@ -273,6 +274,7 @@ static const char *token_str(enum token_type type)
[TK_M_PARENTS_MAX] = "M PARENTS_MAX",
[TK_M_TEST] = "M TEST",
+ [TK_M_EVENT_TIMEOUT] = "M EVENT_TIMEOUT",
[TK_M_PROGRAM] = "M PROGRAM",
[TK_M_IMPORT_FILE] = "M IMPORT_FILE",
[TK_M_IMPORT_PROG] = "M IMPORT_PROG",
@@ -284,6 +286,7 @@ static const char *token_str(enum token_type type)
[TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE",
[TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE",
+ [TK_A_DB_PERSIST] = "A DB_PERSIST",
[TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH",
[TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO",
[TK_A_OWNER] = "A OWNER",
@@ -297,7 +300,6 @@ static const char *token_str(enum token_type type)
[TK_A_TAG] = "A ENV",
[TK_A_NAME] = "A NAME",
[TK_A_DEVLINK] = "A DEVLINK",
- [TK_A_EVENT_TIMEOUT] = "A EVENT_TIMEOUT",
[TK_A_ATTR] = "A ATTR",
[TK_A_RUN] = "A RUN",
[TK_A_GOTO] = "A GOTO",
@@ -370,6 +372,7 @@ static void dump_token(struct udev_rules *rules, struct token *token)
break;
case TK_A_STRING_ESCAPE_NONE:
case TK_A_STRING_ESCAPE_REPLACE:
+ case TK_A_DB_PERSIST:
dbg(rules->udev, "%s\n", token_str(type));
break;
case TK_M_TEST:
@@ -394,7 +397,7 @@ static void dump_token(struct udev_rules *rules, struct token *token)
case TK_A_STATIC_NODE:
dbg(rules->udev, "%s '%s'\n", token_str(type), value);
break;
- case TK_A_EVENT_TIMEOUT:
+ case TK_M_EVENT_TIMEOUT:
dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout);
break;
case TK_A_GOTO:
@@ -728,7 +731,7 @@ static int import_property_from_string(struct udev_device *dev, char *line)
entry = udev_device_add_property(dev, key, val);
/* store in db, skip private keys */
if (key[0] != '.')
- udev_list_entry_set_flags(entry, 1);
+ udev_list_entry_set_num(entry, true);
}
return 0;
}
@@ -747,17 +750,18 @@ static int import_file_into_properties(struct udev_device *dev, const char *file
return 0;
}
-static int import_program_into_properties(struct udev_device *dev, const char *program)
+static int import_program_into_properties(struct udev_event *event, const char *program, const sigset_t *sigmask)
{
- struct udev *udev = udev_device_get_udev(dev);
+ struct udev_device *dev = event->dev;
char **envp;
char result[UTIL_LINE_SIZE];
- size_t reslen;
char *line;
+ int err;
envp = udev_device_get_properties_envp(dev);
- if (util_run_program(udev, program, envp, result, sizeof(result), &reslen, NULL, false) != 0)
- return -1;
+ err = udev_event_spawn(event, program, envp, sigmask, result, sizeof(result));
+ if (err < 0)
+ return err;
line = result;
while (line != NULL) {
@@ -796,7 +800,7 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi
entry = udev_device_add_property(dev, key, val);
/* store in db, skip private keys */
if (key[0] != '.')
- udev_list_entry_set_flags(entry, 1);
+ udev_list_entry_set_num(entry, true);
}
}
return 0;
@@ -1045,6 +1049,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
break;
case TK_A_STRING_ESCAPE_NONE:
case TK_A_STRING_ESCAPE_REPLACE:
+ case TK_A_DB_PERSIST:
break;
case TK_A_RUN:
token->key.value_off = add_string(rule_tmp->rules, value);
@@ -1066,7 +1071,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
case TK_A_STATIC_NODE:
token->key.value_off = add_string(rule_tmp->rules, value);
break;
- case TK_A_EVENT_TIMEOUT:
+ case TK_M_EVENT_TIMEOUT:
token->key.event_timeout = *(int *)data;
break;
case TK_RULE:
@@ -1572,13 +1577,15 @@ static int add_rule(struct udev_rules *rules, char *line,
rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio);
dbg(rules->udev, "link priority=%i\n", prio);
}
+
pos = strstr(value, "event_timeout=");
if (pos != NULL) {
int tout = atoi(&pos[strlen("event_timeout=")]);
- rule_add_key(&rule_tmp, TK_A_EVENT_TIMEOUT, op, NULL, &tout);
+ rule_add_key(&rule_tmp, TK_M_EVENT_TIMEOUT, op, NULL, &tout);
dbg(rules->udev, "event timeout=%i\n", tout);
}
+
pos = strstr(value, "string_escape=");
if (pos != NULL) {
pos = &pos[strlen("string_escape=")];
@@ -1587,6 +1594,11 @@ static int add_rule(struct udev_rules *rules, char *line,
else if (strncmp(pos, "replace", strlen("replace")) == 0)
rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL);
}
+
+ pos = strstr(value, "db_persist");
+ if (pos != NULL)
+ rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL);
+
pos = strstr(value, "nowatch");
if (pos != NULL) {
const int off = 0;
@@ -1602,11 +1614,13 @@ static int add_rule(struct udev_rules *rules, char *line,
dbg(rules->udev, "inotify watch of device requested\n");
}
}
+
pos = strstr(value, "static_node=");
if (pos != NULL) {
rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL);
rule_tmp.rule.rule.has_static_node = true;
}
+
continue;
}
err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
@@ -1705,6 +1719,7 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s
static int add_matching_files(struct udev *udev, struct udev_list_node *file_list, const char *dirname, const char *suffix)
{
DIR *dir;
+ struct dirent *dent;
char filename[UTIL_PATH_SIZE];
dbg(udev, "open directory '%s'\n", dirname);
@@ -1714,13 +1729,7 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis
return -1;
}
- for (;;) {
- struct dirent *dent;
-
- dent = readdir(dir);
- if (dent == NULL || dent->d_name[0] == '\0')
- break;
-
+ for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
if (dent->d_name[0] == '.')
continue;
@@ -1736,7 +1745,12 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis
}
util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
dbg(udev, "put file '%s' into list\n", filename);
- udev_list_entry_add(udev, file_list, filename, NULL, 1, 1);
+ /*
+ * the basename is the key, the filename the value
+ * identical basenames from different directories overwrite each other
+ * entries are sorted after basename
+ */
+ udev_list_entry_add(udev, file_list, dent->d_name, filename, UDEV_LIST_UNIQUE|UDEV_LIST_SORT);
}
closedir(dir);
@@ -1746,9 +1760,8 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis
struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
{
struct udev_rules *rules;
- struct stat statbuf;
struct udev_list_node file_list;
- struct udev_list_entry *file_loop, *file_tmp;
+ struct udev_list_entry *file_loop;
struct token end_token;
rules = calloc(1, sizeof(struct udev_rules));
@@ -1791,85 +1804,55 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
rules->trie_nodes_cur = 1;
- if (udev_get_rules_path(udev) != NULL) {
- /* custom rules location for testing */
- add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
- } else {
- char filename[PATH_MAX];
- struct udev_list_node sort_list;
- struct udev_list_entry *sort_loop, *sort_tmp;
+ if (udev_get_rules_path(udev) == NULL) {
+ char filename[UTIL_PATH_SIZE];
+
+ /* /lib/udev -- default/package rules */
+ add_matching_files(udev, &file_list, LIBEXECDIR "/rules.d", ".rules");
- /* read user/custom rules */
+ /* /etc/udev -- system-specific/user/admin rules */
add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules");
- /* read dynamic/temporary rules */
+ /* /run/udev -- throw-away/temporary rules */
util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
- udev_list_init(&sort_list);
- add_matching_files(udev, &sort_list, filename, ".rules");
-
- /* read default rules */
- add_matching_files(udev, &sort_list, LIBEXECDIR "/rules.d", ".rules");
-
- /* sort all rules files by basename into list of files */
- udev_list_entry_foreach_safe(sort_loop, sort_tmp, udev_list_get_entry(&sort_list)) {
- const char *sort_name = udev_list_entry_get_name(sort_loop);
- const char *sort_base = strrchr(sort_name, '/');
-
- if (sort_base == NULL)
- continue;
- /* sort entry into existing list */
- udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
- const char *file_name = udev_list_entry_get_name(file_loop);
- const char *file_base = strrchr(file_name, '/');
-
- if (file_base == NULL)
- continue;
- if (strcmp(file_base, sort_base) == 0) {
- info(udev, "rule file basename '%s' already added, ignoring '%s'\n",
- file_name, sort_name);
- udev_list_entry_delete(sort_loop);
- sort_loop = NULL;
- break;
- }
- if (strcmp(file_base, sort_base) > 0) {
- /* found later file, insert before */
- udev_list_entry_remove(sort_loop);
- udev_list_entry_insert_before(sort_loop, file_loop);
- sort_loop = NULL;
- break;
- }
- }
- /* current file already handled */
- if (sort_loop == NULL)
- continue;
- /* no later file, append to end of list */
- udev_list_entry_remove(sort_loop);
- udev_list_entry_append(sort_loop, &file_list);
- }
+ add_matching_files(udev, &file_list, filename, ".rules");
+ } else {
+ /* custom rules files location for testing */
+ add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
}
/* add all filenames to the string buffer */
udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
- const char *filename = udev_list_entry_get_name(file_loop);
+ const char *filename = udev_list_entry_get_value(file_loop);
unsigned int filename_off;
filename_off = add_string(rules, filename);
/* the offset in the rule is limited to unsigned short */
if (filename_off < USHRT_MAX)
- udev_list_entry_set_flags(file_loop, filename_off);
+ udev_list_entry_set_num(file_loop, filename_off);
}
- /* parse list of files */
- udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
- const char *filename = udev_list_entry_get_name(file_loop);
- unsigned int filename_off = udev_list_entry_get_flags(file_loop);
+ /* parse all rules files */
+ udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
+ const char *filename = udev_list_entry_get_value(file_loop);
+ unsigned int filename_off = udev_list_entry_get_num(file_loop);
+ struct stat st;
- if (stat(filename, &statbuf) == 0 && statbuf.st_size > 0)
- parse_file(rules, filename, filename_off);
- else
- err(udev, "can not read '%s'\n", filename);
- udev_list_entry_delete(file_loop);
+ if (stat(filename, &st) != 0) {
+ err(udev, "can not find '%s': %m\n", filename);
+ continue;
+ }
+ if (S_ISREG(st.st_mode) && st.st_size <= 0) {
+ info(udev, "ignore empty '%s'\n", filename);
+ continue;
+ }
+ if (S_ISCHR(st.st_mode)) {
+ info(udev, "ignore masked '%s'\n", filename);
+ continue;
+ }
+ parse_file(rules, filename, filename_off);
}
+ udev_list_cleanup_entries(udev, &file_list);
memset(&end_token, 0x00, sizeof(struct token));
end_token.type = TK_END;
@@ -2068,7 +2051,7 @@ enum escape_type {
ESCAPE_REPLACE,
};
-int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event)
+int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask)
{
struct token *cur;
struct token *rule;
@@ -2270,6 +2253,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
goto nomatch;
break;
}
+ case TK_M_EVENT_TIMEOUT:
+ info(event->udev, "OPTIONS event_timeout=%u\n", cur->key.event_timeout);
+ event->timeout_usec = cur->key.event_timeout * 1000 * 1000;
+ break;
case TK_M_PROGRAM:
{
char program[UTIL_PATH_SIZE];
@@ -2284,7 +2271,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
program,
&rules->buf[rule->rule.filename_off],
rule->rule.filename_line);
- if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL, NULL, false) != 0) {
+
+ if (udev_event_spawn(event, program, envp, sigmask, result, sizeof(result)) < 0) {
if (cur->key.op != OP_NOMATCH)
goto nomatch;
} else {
@@ -2322,7 +2310,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
import,
&rules->buf[rule->rule.filename_off],
rule->rule.filename_line);
- if (import_program_into_properties(event->dev, import) != 0)
+
+ if (import_program_into_properties(event, import, sigmask) != 0)
if (cur->key.op != OP_NOMATCH)
goto nomatch;
break;
@@ -2337,7 +2326,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
struct udev_list_entry *entry;
entry = udev_device_add_property(event->dev, key, value);
- udev_list_entry_set_flags(entry, 1);
+ udev_list_entry_set_num(entry, true);
} else {
if (cur->key.op != OP_NOMATCH)
goto nomatch;
@@ -2365,7 +2354,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
if (pos[0] == '\0' || isspace(pos[0])) {
/* we import simple flags as 'FLAG=1' */
entry = udev_device_add_property(event->dev, key, "1");
- udev_list_entry_set_flags(entry, 1);
+ udev_list_entry_set_num(entry, true);
imported = true;
} else if (pos[0] == '=') {
const char *value;
@@ -2376,7 +2365,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
pos++;
pos[0] = '\0';
entry = udev_device_add_property(event->dev, key, value);
- udev_list_entry_set_flags(entry, 1);
+ udev_list_entry_set_num(entry, true);
imported = true;
}
}
@@ -2407,6 +2396,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
case TK_A_STRING_ESCAPE_REPLACE:
esc = ESCAPE_REPLACE;
break;
+ case TK_A_DB_PERSIST:
+ udev_device_set_db_persist(event->dev);
+ break;
case TK_A_INOTIFY_WATCH:
if (event->inotify_watch_final)
break;
@@ -2451,19 +2443,22 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
}
case TK_A_MODE:
{
- char mode[UTIL_NAME_SIZE];
+ char mode_str[UTIL_NAME_SIZE];
+ mode_t mode;
char *endptr;
if (event->mode_final)
break;
- if (cur->key.op == OP_ASSIGN_FINAL)
- event->mode_final = true;
- udev_event_apply_format(event, &rules->buf[cur->key.value_off], mode, sizeof(mode));
- event->mode = strtol(mode, &endptr, 8);
+ udev_event_apply_format(event, &rules->buf[cur->key.value_off], mode_str, sizeof(mode_str));
+ mode = strtol(mode_str, &endptr, 8);
if (endptr[0] != '\0') {
- err(event->udev, "invalide mode '%s' set default mode 0600\n", mode);
- event->mode = 0600;
+ err(event->udev, "ignoring invalid mode '%s'\n", mode_str);
+ break;
}
+ if (cur->key.op == OP_ASSIGN_FINAL)
+ event->mode_final = true;
+ event->mode_set = true;
+ event->mode = mode;
info(event->udev, "MODE %#o %s:%u\n",
event->mode,
&rules->buf[rule->rule.filename_off],
@@ -2497,6 +2492,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
break;
if (cur->key.op == OP_ASSIGN_FINAL)
event->mode_final = true;
+ event->mode_set = true;
event->mode = cur->key.mode;
info(event->udev, "MODE %#o %s:%u\n",
event->mode,
@@ -2518,7 +2514,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
entry = udev_device_add_property(event->dev, name, temp_value);
/* store in db, skip private keys */
if (name[0] != '.')
- udev_list_entry_set_flags(entry, 1);
+ udev_list_entry_set_num(entry, true);
} else {
udev_device_add_property(event->dev, name, NULL);
}
@@ -2601,9 +2597,6 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
}
}
break;
- case TK_A_EVENT_TIMEOUT:
- udev_device_set_event_timeout(event->dev, cur->key.event_timeout);
- break;
case TK_A_ATTR:
{
const char *key_name = &rules->buf[cur->key.attr_off];
@@ -2640,9 +2633,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
&rules->buf[rule->rule.filename_off],
rule->rule.filename_line);
list_entry = udev_list_entry_add(event->udev, &event->run_list,
- &rules->buf[cur->key.value_off], NULL, 1, 0);
+ &rules->buf[cur->key.value_off], NULL, UDEV_LIST_UNIQUE);
if (cur->key.fail_on_error)
- udev_list_entry_set_flags(list_entry, 1);
+ udev_list_entry_set_num(list_entry, true);
break;
}
case TK_A_GOTO: