X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudev-rules.c;h=11948caccea8b7d03204e90998394274346334bf;hp=6eb8350343c3f7c55391376b2d9c2c7f40190d23;hb=88cbfb09ee5510277503ff1830ecc3aa6c380b00;hpb=5d69a34caffd595d918dd859a5b079f95d250064 diff --git a/udev/udev-rules.c b/udev/udev-rules.c index 6eb835034..11948cacc 100644 --- a/udev/udev-rules.c +++ b/udev/udev-rules.c @@ -125,6 +125,7 @@ enum token_type { TK_M_DEVLINK, /* val */ TK_M_NAME, /* val */ TK_M_ENV, /* val, attr */ + TK_M_TAG, /* val */ TK_M_SUBSYSTEM, /* val */ TK_M_DRIVER, /* val */ TK_M_WAITFOR, /* val */ @@ -156,7 +157,9 @@ enum token_type { TK_A_OWNER_ID, /* uid_t */ TK_A_GROUP_ID, /* gid_t */ TK_A_MODE_ID, /* mode_t */ + TK_A_STATIC_NODE, /* val */ TK_A_ENV, /* val, attr */ + TK_A_TAG, /* val */ TK_A_NAME, /* val */ TK_A_DEVLINK, /* val */ TK_A_EVENT_TIMEOUT, /* int */ @@ -170,10 +173,12 @@ enum token_type { /* we try to pack stuff in a way that we take only 12 bytes per token */ struct token { union { - unsigned char type; /* same as in rule and key */ + unsigned char type; /* same in rule and key */ struct { enum token_type type:8; - unsigned int flags:8; + bool can_set_name:1; + bool has_static_node:1; + unsigned int unused:6; unsigned short token_count; unsigned int label_off; unsigned short filename_off; @@ -253,6 +258,7 @@ static const char *token_str(enum token_type type) [TK_M_DEVLINK] = "M DEVLINK", [TK_M_NAME] = "M NAME", [TK_M_ENV] = "M ENV", + [TK_M_TAG] = "M TAG", [TK_M_SUBSYSTEM] = "M SUBSYSTEM", [TK_M_DRIVER] = "M DRIVER", [TK_M_WAITFOR] = "M WAITFOR", @@ -283,8 +289,10 @@ static const char *token_str(enum token_type type) [TK_A_MODE] = "A MODE", [TK_A_OWNER_ID] = "A OWNER_ID", [TK_A_GROUP_ID] = "A GROUP_ID", + [TK_A_STATIC_NODE] = "A STATIC_NODE", [TK_A_MODE_ID] = "A MODE_ID", [TK_A_ENV] = "A ENV", + [TK_A_TAG] = "A ENV", [TK_A_NAME] = "A NAME", [TK_A_DEVLINK] = "A DEVLINK", [TK_A_EVENT_TIMEOUT] = "A EVENT_TIMEOUT", @@ -313,11 +321,10 @@ static void dump_token(struct udev_rules *rules, struct token *token) const char *tk_ptr = (char *)token; unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token); - dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s', flags: 0x%02x\n", + dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s'\n", &rules->buf[token->rule.filename_off], token->rule.filename_line, idx, token->rule.token_count, - &rules->buf[token->rule.label_off], - token->rule.flags); + &rules->buf[token->rule.label_off]); break; } case TK_M_ACTION: @@ -354,6 +361,10 @@ static void dump_token(struct udev_rules *rules, struct token *token) dbg(rules->udev, "%s %s '%s' '%s'(%s)\n", token_str(type), operation_str(op), attr, value, string_glob_str(glob)); break; + case TK_M_TAG: + case TK_A_TAG: + dbg(rules->udev, "%s %s '%s'\n", token_str(type), operation_str(op), value); + break; case TK_A_STRING_ESCAPE_NONE: case TK_A_STRING_ESCAPE_REPLACE: dbg(rules->udev, "%s\n", token_str(type)); @@ -366,7 +377,7 @@ static void dump_token(struct udev_rules *rules, struct token *token) dbg(rules->udev, "%s %u\n", token_str(type), token->key.watch); break; case TK_A_DEVLINK_PRIO: - dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.devlink_prio); + dbg(rules->udev, "%s %u\n", token_str(type), token->key.devlink_prio); break; case TK_A_OWNER_ID: dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.uid); @@ -377,8 +388,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) case TK_A_MODE_ID: dbg(rules->udev, "%s %s %#o\n", token_str(type), operation_str(op), token->key.mode); break; + case TK_A_STATIC_NODE: + dbg(rules->udev, "%s '%s'\n", token_str(type), value); + break; case TK_A_EVENT_TIMEOUT: - dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.event_timeout); + dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout); break; case TK_A_GOTO: dbg(rules->udev, "%s '%s' %u\n", token_str(type), value, token->key.rule_goto); @@ -739,7 +753,7 @@ static int import_program_into_properties(struct udev_device *dev, const char *p char *line; envp = udev_device_get_properties_envp(dev); - if (util_run_program(udev, program, envp, result, sizeof(result), &reslen, NULL) != 0) + if (util_run_program(udev, program, envp, result, sizeof(result), &reslen, NULL, false) != 0) return -1; line = result; @@ -826,7 +840,7 @@ static int wait_for_file(struct udev_device *dev, const char *file, int timeout) static int attr_subst_subdir(char *attr, size_t len) { - int found = 0; + bool found = false; if (strstr(attr, "/*/")) { char *pos; @@ -851,7 +865,7 @@ static int attr_subst_subdir(char *attr, size_t len) continue; util_strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL); if (stat(attr, &stats) == 0) { - found = 1; + found = true; break; } } @@ -880,7 +894,7 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty return -1; *key = linepos; - while (1) { + for (;;) { linepos++; if (linepos[0] == '\0') return -1; @@ -1003,6 +1017,8 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_A_MODE: case TK_A_NAME: case TK_A_GOTO: + case TK_M_TAG: + case TK_A_TAG: token->key.value_off = add_string(rule_tmp->rules, value); break; case TK_M_ENV: @@ -1043,6 +1059,9 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_A_MODE_ID: token->key.mode = *(mode_t *)data; break; + case TK_A_STATIC_NODE: + token->key.value_off = add_string(rule_tmp->rules, value); + break; case TK_A_EVENT_TIMEOUT: token->key.event_timeout = *(int *)data; break; @@ -1161,7 +1180,7 @@ static int add_rule(struct udev_rules *rules, char *line, rule_tmp.rule.rule.filename_line = lineno; linepos = line; - while (1) { + for (;;) { char *key; char *value; enum operation_type op; @@ -1350,6 +1369,14 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } + if (strcmp(key, "TAG") == 0) { + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL); + else + rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL); + continue; + } + if (strcmp(key, "PROGRAM") == 0) { rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); continue; @@ -1450,14 +1477,19 @@ static int add_rule(struct udev_rules *rules, char *line, if (op < OP_MATCH_MAX) { rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL); } else { - if (value[0] == '\0') - info(rules->udev, "name empty, node creation suppressed\n"); - else if (strcmp(value, "%k") == 0) - err(rules->udev, "NAME=\"%%k\" is superfluous and breaks " - "kernel supplied names, please remove it from %s:%u\n", filename, lineno); + if (strcmp(value, "%k") == 0) { + err(rules->udev, "NAME=\"%%k\" is ignored, because it breaks kernel supplied names, " + "please remove it from %s:%u\n", filename, lineno); + continue; + } + if (value[0] == '\0') { + info(rules->udev, "NAME=\"\" is ignored, because udev will not delete any device nodes, " + "please remove it from %s:%u\n", filename, lineno); + continue; + } rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); } - rule_tmp.rule.rule.flags = 1; + rule_tmp.rule.rule.can_set_name = true; continue; } @@ -1472,7 +1504,7 @@ static int add_rule(struct udev_rules *rules, char *line, flag = 1; rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag); } - rule_tmp.rule.rule.flags = 1; + rule_tmp.rule.rule.can_set_name = true; continue; } @@ -1489,7 +1521,7 @@ static int add_rule(struct udev_rules *rules, char *line, } else if (rules->resolve_names >= 0) { rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); } - rule_tmp.rule.rule.flags = 1; + rule_tmp.rule.rule.can_set_name = true; continue; } @@ -1506,7 +1538,7 @@ static int add_rule(struct udev_rules *rules, char *line, } else if (rules->resolve_names >= 0) { rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); } - rule_tmp.rule.rule.flags = 1; + rule_tmp.rule.rule.can_set_name = true; continue; } @@ -1519,7 +1551,7 @@ static int add_rule(struct udev_rules *rules, char *line, rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode); else rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL); - rule_tmp.rule.rule.flags = 1; + rule_tmp.rule.rule.can_set_name = true; continue; } @@ -1563,6 +1595,11 @@ 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, 0, &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); @@ -1670,7 +1707,7 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis return -1; } - while (1) { + for (;;) { struct dirent *dent; dent = readdir(dir); @@ -1884,7 +1921,7 @@ static int match_key(struct udev_rules *rules, struct token *token, const char * { char *key_value = &rules->buf[token->key.value_off]; char *pos; - int match = 0; + bool match = false; if (val == NULL) val = ""; @@ -1903,7 +1940,7 @@ static int match_key(struct udev_rules *rules, struct token *token, const char * split = &rules->buf[token->key.value_off]; len = strlen(val); - while (1) { + for (;;) { const char *next; next = strchr(split, '|'); @@ -2033,14 +2070,14 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event /* loop through token list, match, run actions or forward to next rule */ cur = &rules->tokens[0]; rule = cur; - while (1) { + for (;;) { dump_token(rules, cur); switch (cur->type) { case TK_RULE: /* current rule */ rule = cur; /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */ - if (!can_set_name && rule->rule.flags) + if (!can_set_name && rule->rule.can_set_name) goto nomatch; esc = ESCAPE_UNSET; break; @@ -2060,14 +2097,14 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event { size_t devlen = strlen(udev_get_dev_path(event->udev))+1; struct udev_list_entry *list_entry; - int match = 0; + bool match = false; udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) { const char *devlink; devlink = &udev_list_entry_get_name(list_entry)[devlen]; if (match_key(rules, cur, devlink) == 0) { - match = 1; + match = true; break; } } @@ -2093,6 +2130,21 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event goto nomatch; break; } + case TK_M_TAG: + { + struct udev_list_entry *list_entry; + bool match = false; + + udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) { + if (strcmp(&rules->buf[cur->key.value_off], udev_list_entry_get_name(list_entry)) == 0) { + match = true; + break; + } + } + if (!match && (cur->key.op != OP_NOMATCH)) + goto nomatch; + break; + } case TK_M_SUBSYSTEM: if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0) goto nomatch; @@ -2130,7 +2182,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event /* loop over parents */ event->dev_parent = event->dev; - while (1) { + for (;;) { struct token *key; dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent)); @@ -2217,7 +2269,7 @@ 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) != 0) { + if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL, NULL, false) != 0) { if (cur->key.op != OP_NOMATCH) goto nomatch; } else { @@ -2310,7 +2362,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->owner_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->owner_final = 1; + event->owner_final = true; udev_event_apply_format(event, &rules->buf[cur->key.value_off], owner, sizeof(owner)); event->uid = util_lookup_user(event->udev, owner); info(event->udev, "OWNER %u %s:%u\n", @@ -2326,7 +2378,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->group_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->group_final = 1; + event->group_final = true; udev_event_apply_format(event, &rules->buf[cur->key.value_off], group, sizeof(group)); event->gid = util_lookup_group(event->udev, group); info(event->udev, "GROUP %u %s:%u\n", @@ -2343,12 +2395,12 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->mode_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->mode_final = 1; + event->mode_final = true; udev_event_apply_format(event, &rules->buf[cur->key.value_off], mode, sizeof(mode)); event->mode = strtol(mode, &endptr, 8); if (endptr[0] != '\0') { - err(event->udev, "invalide mode '%s' set default mode 0660\n", mode); - event->mode = 0660; + err(event->udev, "invalide mode '%s' set default mode 0600\n", mode); + event->mode = 0600; } info(event->udev, "MODE %#o %s:%u\n", event->mode, @@ -2360,7 +2412,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->owner_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->owner_final = 1; + event->owner_final = true; event->uid = cur->key.uid; info(event->udev, "OWNER %u %s:%u\n", event->uid, @@ -2371,7 +2423,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->group_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->group_final = 1; + event->group_final = true; event->gid = cur->key.gid; info(event->udev, "GROUP %u %s:%u\n", event->gid, @@ -2382,13 +2434,15 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->mode_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->mode_final = 1; + event->mode_final = true; event->mode = cur->key.mode; info(event->udev, "MODE %#o %s:%u\n", event->mode, &rules->buf[rule->rule.filename_off], rule->rule.filename_line); break; + case TK_A_STATIC_NODE: + break; case TK_A_ENV: { const char *name = &rules->buf[cur->key.attr_off]; @@ -2408,6 +2462,11 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event } break; } + case TK_A_TAG: + if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) + udev_device_cleanup_tags_list(event->dev); + udev_device_add_tag(event->dev, &rules->buf[cur->key.value_off]); + break; case TK_A_NAME: { const char *name = &rules->buf[cur->key.value_off]; @@ -2417,7 +2476,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (event->name_final) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->name_final = 1; + event->name_final = true; udev_event_apply_format(event, name, name_str, sizeof(name_str)); if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) { count = udev_util_replace_chars(name_str, "/"); @@ -2444,7 +2503,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event if (major(udev_device_get_devnum(event->dev)) == 0) break; if (cur->key.op == OP_ASSIGN_FINAL) - event->devlink_final = 1; + event->devlink_final = true; if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL) udev_device_cleanup_devlinks_list(event->dev); @@ -2549,3 +2608,75 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event (unsigned int) (cur - rules->tokens)); } } + +void udev_rules_apply_static_dev_perms(struct udev_rules *rules) +{ + struct token *cur; + struct token *rule; + uid_t uid = 0; + gid_t gid = 0; + mode_t mode = 0; + + if (rules->tokens == NULL) + return; + + cur = &rules->tokens[0]; + rule = cur; + for (;;) { + switch (cur->type) { + case TK_RULE: + /* current rule */ + rule = cur; + + /* skip rules without a static_node tag */ + if (!rule->rule.has_static_node) + goto next; + + uid = 0; + gid = 0; + mode = 0; + break; + case TK_A_OWNER_ID: + uid = cur->key.uid; + break; + case TK_A_GROUP_ID: + gid = cur->key.gid; + break; + case TK_A_MODE_ID: + mode = cur->key.mode; + break; + case TK_A_STATIC_NODE: { + char filename[UTIL_PATH_SIZE]; + struct stat stats; + /* we assure, that the permissions tokens are sorted before the static token */ + if (mode == 0 && uid == 0 && gid == 0) + goto next; + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(rules->udev), "/", + &rules->buf[cur->key.value_off], NULL); + if (stat(filename, &stats) != 0) + goto next; + if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) + goto next; + if (mode != 0 && mode != (stats.st_mode & 0777)) { + chmod(filename, mode); + info(rules->udev, "chmod '%s' %#o\n", filename, mode); + } + if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) { + chown(filename, uid, gid); + info(rules->udev, "chown '%s' %u %u\n", filename, uid, gid); + } + utimensat(AT_FDCWD, filename, NULL, 0); + break; + } + case TK_END: + return; + } + + cur++; + continue; +next: + /* fast-forward to next rule */ + cur = rule + rule->rule.token_count; + continue; + } +}