X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fudev%2Fudev-rules.c;h=4262119886b4ab5f007236abd4d10b0602784b14;hb=e530ed5e1407e0571afc01552e41365ffb01befa;hp=db95442fda916730f1fb392ded5cecf64629e336;hpb=671174136525ddf208cdbe75d6d6bd159afa961f;p=elogind.git diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index db95442fd..426211988 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -35,6 +35,7 @@ #include "strbuf.h" #include "strv.h" #include "util.h" +#include "sysctl-util.h" #define PREALLOC_TOKEN 2048 @@ -128,6 +129,7 @@ enum token_type { TK_M_DRIVER, /* val */ TK_M_WAITFOR, /* val */ TK_M_ATTR, /* val, attr */ + TK_M_SYSCTL, /* val, attr */ TK_M_PARENTS_MIN, TK_M_KERNELS, /* val */ @@ -166,6 +168,7 @@ enum token_type { TK_A_NAME, /* val */ TK_A_DEVLINK, /* val */ TK_A_ATTR, /* val, attr */ + TK_A_SYSCTL, /* val, attr */ TK_A_RUN_BUILTIN, /* val, bool */ TK_A_RUN_PROGRAM, /* val, bool */ TK_A_GOTO, /* size_t */ @@ -262,6 +265,7 @@ static const char *token_str(enum token_type type) { [TK_M_DRIVER] = "M DRIVER", [TK_M_WAITFOR] = "M WAITFOR", [TK_M_ATTR] = "M ATTR", + [TK_M_SYSCTL] = "M SYSCTL", [TK_M_PARENTS_MIN] = "M PARENTS_MIN", [TK_M_KERNELS] = "M KERNELS", @@ -300,6 +304,7 @@ static const char *token_str(enum token_type type) { [TK_A_NAME] = "A NAME", [TK_A_DEVLINK] = "A DEVLINK", [TK_A_ATTR] = "A ATTR", + [TK_A_SYSCTL] = "A SYSCTL", [TK_A_RUN_BUILTIN] = "A RUN_BUILTIN", [TK_A_RUN_PROGRAM] = "A RUN_PROGRAM", [TK_A_GOTO] = "A GOTO", @@ -363,9 +368,11 @@ static void dump_token(struct udev_rules *rules, struct token *token) { log_debug("%s %i '%s'", token_str(type), token->key.builtin_cmd, value); break; case TK_M_ATTR: + case TK_M_SYSCTL: case TK_M_ATTRS: case TK_M_ENV: case TK_A_ATTR: + case TK_A_SYSCTL: case TK_A_ENV: log_debug("%s %s '%s' '%s'(%s)", token_str(type), operation_str(op), attr, value, string_glob_str(glob)); @@ -459,8 +466,9 @@ static int add_token(struct udev_rules *rules, struct token *token) { static uid_t add_uid(struct udev_rules *rules, const char *owner) { unsigned int i; - uid_t uid; + uid_t uid = 0; unsigned int off; + int r; /* lookup, if we know it already */ for (i = 0; i < rules->uids_cur; i++) { @@ -470,7 +478,13 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) { return uid; } } - uid = util_lookup_user(rules->udev, owner); + r = get_user_creds(&owner, &uid, NULL, NULL, NULL); + if (r < 0) { + if (r == -ENOENT || r == -ESRCH) + log_error("specified user '%s' unknown", owner); + else + log_error_errno(r, "error resolving user '%s': %m", owner); + } /* grow buffer if needed */ if (rules->uids_cur+1 >= rules->uids_max) { @@ -499,8 +513,9 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) { static gid_t add_gid(struct udev_rules *rules, const char *group) { unsigned int i; - gid_t gid; + gid_t gid = 0; unsigned int off; + int r; /* lookup, if we know it already */ for (i = 0; i < rules->gids_cur; i++) { @@ -510,7 +525,13 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) { return gid; } } - gid = util_lookup_group(rules->udev, group); + r = get_group_creds(&group, &gid); + if (r < 0) { + if (r == -ENOENT || r == -ESRCH) + log_error("specified group '%s' unknown", group); + else + log_error_errno(r, "error resolving group '%s': %m", group); + } /* grow buffer if needed */ if (rules->gids_cur+1 >= rules->gids_max) { @@ -541,7 +562,6 @@ static int import_property_from_string(struct udev_device *dev, char *line) { char *key; char *val; size_t len; - struct udev_list_entry *entry; /* find key */ key = line; @@ -592,10 +612,7 @@ static int import_property_from_string(struct udev_device *dev, char *line) { val++; } - entry = udev_device_add_property(dev, key, val); - /* store in db, skip private keys */ - if (key[0] != '.') - udev_list_entry_set_num(entry, true); + udev_device_add_property(dev, key, val); return 0; } @@ -656,12 +673,7 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi const char *val = udev_list_entry_get_value(list_entry); if (fnmatch(filter, key, 0) == 0) { - struct udev_list_entry *entry; - - entry = udev_device_add_property(dev, key, val); - /* store in db, skip private keys */ - if (key[0] != '.') - udev_list_entry_set_num(entry, true); + udev_device_add_property(dev, key, val); } } return 0; @@ -892,8 +904,10 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, break; case TK_M_ENV: case TK_M_ATTR: + case TK_M_SYSCTL: case TK_M_ATTRS: case TK_A_ATTR: + case TK_A_SYSCTL: case TK_A_ENV: case TK_A_SECLABEL: attr = data; @@ -1028,11 +1042,11 @@ static int add_rule(struct udev_rules *rules, char *line, const char *filename, unsigned int filename_off, unsigned int lineno) { char *linepos; const char *attr; - struct rule_tmp rule_tmp; + struct rule_tmp rule_tmp = { + .rules = rules, + .rule.type = TK_RULE, + }; - memzero(&rule_tmp, sizeof(struct rule_tmp)); - rule_tmp.rules = rules; - rule_tmp.rule.type = TK_RULE; /* the offset in the rule is limited to unsigned short */ if (filename_off < USHRT_MAX) rule_tmp.rule.rule.filename_off = filename_off; @@ -1053,15 +1067,14 @@ static int add_rule(struct udev_rules *rules, char *line, /* If we aren't at the end of the line, this is a parsing error. * Make a best effort to describe where the problem is. */ - if (*linepos != '\n') { - char buf[2] = {linepos[1]}; + if (!strchr(NEWLINE, *linepos)) { + char buf[2] = {*linepos}; _cleanup_free_ char *tmp; tmp = cescape(buf); - log_error("invalid key/value pair in file %s on line %u," - "starting at character %tu ('%s')\n", + log_error("invalid key/value pair in file %s on line %u, starting at character %tu ('%s')", filename, lineno, linepos - line + 1, tmp); - if (linepos[1] == '#') + if (*linepos == '#') log_error("hint: comments can only start at beginning of line"); } break; @@ -1131,11 +1144,27 @@ static int add_rule(struct udev_rules *rules, char *line, log_error("invalid ATTR operation"); goto invalid; } - if (op < OP_MATCH_MAX) { + if (op < OP_MATCH_MAX) rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr); - } else { + else rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr); + continue; + } + + if (startswith(key, "SYSCTL{")) { + attr = get_key_attribute(rules->udev, key + strlen("SYSCTL")); + if (attr == NULL) { + log_error("error parsing SYSCTL attribute"); + goto invalid; } + if (op == OP_REMOVE) { + log_error("invalid SYSCTL operation"); + goto invalid; + } + if (op < OP_MATCH_MAX) + rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr); + else + rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr); continue; } @@ -1562,7 +1591,7 @@ invalid: } static int parse_file(struct udev_rules *rules, const char *filename) { - FILE *f; + _cleanup_fclose_ FILE *f = NULL; unsigned int first_token; unsigned int filename_off; char line[UTIL_LINE_SIZE]; @@ -1620,7 +1649,6 @@ static int parse_file(struct udev_rules *rules, const char *filename) { } add_rule(rules, key, filename, filename_off, line_nr); } - fclose(f); /* link GOTOs to LABEL rules in this file to be able to fast-forward */ for (i = first_token+1; i < rules->token_cur; i++) { @@ -1673,7 +1701,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) { r = conf_files_list_strv(&files, ".rules", NULL, rules_dirs); if (r < 0) { - log_error("failed to enumerate rules files: %s", strerror(-r)); + log_error_errno(r, "failed to enumerate rules files: %m"); return udev_rules_unref(rules); } @@ -1864,6 +1892,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec, + struct udev_list *properties_list, const sigset_t *sigmask) { struct token *cur; struct token *rule; @@ -1929,7 +1958,18 @@ int udev_rules_apply_to_event(struct udev_rules *rules, const char *value; value = udev_device_get_property_value(event->dev, key_name); - if (value == NULL) + + /* check global properties */ + if (!value && properties_list) { + struct udev_list_entry *list_entry; + + list_entry = udev_list_get_entry(properties_list); + list_entry = udev_list_entry_get_by_name(list_entry, key_name); + if (list_entry != NULL) + value = udev_list_entry_get_value(list_entry); + } + + if (!value) value = ""; if (match_key(rules, cur, value)) goto nomatch; @@ -1971,6 +2011,23 @@ int udev_rules_apply_to_event(struct udev_rules *rules, if (match_attr(rules, event->dev, event, cur) != 0) goto nomatch; break; + case TK_M_SYSCTL: { + char filename[UTIL_PATH_SIZE]; + _cleanup_free_ char *value = NULL; + size_t len; + + udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename)); + sysctl_normalize(filename); + if (sysctl_read(filename, &value) < 0) + goto nomatch; + + len = strlen(value); + while (len > 0 && isspace(value[--len])) + value[len] = '\0'; + if (match_key(rules, cur, value) != 0) + goto nomatch; + break; + } case TK_M_KERNELS: case TK_M_SUBSYSTEMS: case TK_M_DRIVERS: @@ -2154,12 +2211,9 @@ int udev_rules_apply_to_event(struct udev_rules *rules, const char *value; value = udev_device_get_property_value(event->dev_db, key); - if (value != NULL) { - struct udev_list_entry *entry; - - entry = udev_device_add_property(event->dev, key, value); - udev_list_entry_set_num(entry, true); - } else { + if (value != NULL) + udev_device_add_property(event->dev, key, value); + else { if (cur->key.op != OP_NOMATCH) goto nomatch; } @@ -2179,13 +2233,10 @@ int udev_rules_apply_to_event(struct udev_rules *rules, pos = strstr(cmdline, key); if (pos != NULL) { - struct udev_list_entry *entry; - pos += strlen(key); 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_num(entry, true); + udev_device_add_property(event->dev, key, "1"); imported = true; } else if (pos[0] == '=') { const char *value; @@ -2195,8 +2246,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, while (pos[0] != '\0' && !isspace(pos[0])) pos++; pos[0] = '\0'; - entry = udev_device_add_property(event->dev, key, value); - udev_list_entry_set_num(entry, true); + udev_device_add_property(event->dev, key, value); imported = true; } } @@ -2241,6 +2291,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, break; case TK_A_OWNER: { char owner[UTIL_NAME_SIZE]; + const char *ow = owner; + int r; if (event->owner_final) break; @@ -2248,7 +2300,15 @@ int udev_rules_apply_to_event(struct udev_rules *rules, event->owner_final = true; udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner)); event->owner_set = true; - event->uid = util_lookup_user(event->udev, owner); + r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL); + if (r < 0) { + if (r == -ENOENT || r == -ESRCH) + log_error("specified user '%s' unknown", owner); + else + log_error_errno(r, "error resolving user '%s': %m", owner); + + event->uid = 0; + } log_debug("OWNER %u %s:%u", event->uid, rules_str(rules, rule->rule.filename_off), @@ -2257,6 +2317,8 @@ int udev_rules_apply_to_event(struct udev_rules *rules, } case TK_A_GROUP: { char group[UTIL_NAME_SIZE]; + const char *gr = group; + int r; if (event->group_final) break; @@ -2264,7 +2326,15 @@ int udev_rules_apply_to_event(struct udev_rules *rules, event->group_final = true; udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group)); event->group_set = true; - event->gid = util_lookup_group(event->udev, group); + r = get_group_creds(&gr, &event->gid); + if (r < 0) { + if (r == -ENOENT || r == -ESRCH) + log_error("specified group '%s' unknown", group); + else + log_error_errno(r, "error resolving group '%s': %m", group); + + event->gid = 0; + } log_debug("GROUP %u %s:%u", event->gid, rules_str(rules, rule->rule.filename_off), @@ -2349,7 +2419,6 @@ int udev_rules_apply_to_event(struct udev_rules *rules, char *value = rules_str(rules, cur->key.value_off); char value_new[UTIL_NAME_SIZE]; const char *value_old = NULL; - struct udev_list_entry *entry; if (value[0] == '\0') { if (cur->key.op == OP_ADD) @@ -2369,10 +2438,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, } else udev_event_apply_format(event, value, value_new, sizeof(value_new)); - entry = udev_device_add_property(event->dev, name, value_new); - /* store in db, skip private keys */ - if (name[0] != '.') - udev_list_entry_set_num(entry, true); + udev_device_add_property(event->dev, name, value_new); break; } case TK_A_TAG: { @@ -2491,13 +2557,28 @@ int udev_rules_apply_to_event(struct udev_rules *rules, f = fopen(attr, "we"); if (f != NULL) { if (fprintf(f, "%s", value) <= 0) - log_error("error writing ATTR{%s}: %m", attr); + log_error_errno(errno, "error writing ATTR{%s}: %m", attr); fclose(f); } else { - log_error("error opening ATTR{%s} for writing: %m", attr); + log_error_errno(errno, "error opening ATTR{%s} for writing: %m", attr); } break; } + case TK_A_SYSCTL: { + char filename[UTIL_PATH_SIZE]; + char value[UTIL_NAME_SIZE]; + int r; + + udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename)); + sysctl_normalize(filename); + udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value)); + log_debug("SYSCTL '%s' writing '%s' %s:%u", filename, value, + rules_str(rules, rule->rule.filename_off), rule->rule.filename_line); + r = sysctl_write(filename, value); + if (r < 0) + log_error("error writing SYSCTL{%s}='%s': %s", filename, value, strerror(-r)); + break; + } case TK_A_RUN_BUILTIN: case TK_A_RUN_PROGRAM: { struct udev_list_entry *entry; @@ -2608,19 +2689,17 @@ int udev_rules_apply_static_dev_perms(struct udev_rules *rules) { strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL); r = mkdir_p(tags_dir, 0755); - if (r < 0) { - log_error("failed to create %s: %s", tags_dir, strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "failed to create %s: %m", tags_dir); unescaped_filename = xescape(rules_str(rules, cur->key.value_off), "/."); strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL); r = symlink(device_node, tag_symlink); - if (r < 0 && errno != EEXIST) { - log_error("failed to create symlink %s -> %s: %m", tag_symlink, device_node); - return -errno; - } else + if (r < 0 && errno != EEXIST) + return log_error_errno(errno, "failed to create symlink %s -> %s: %m", + tag_symlink, device_node); + else r = 0; } }