X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev%2Fudev-rules.c;h=092ddcdc25360cf30f2d591715736748ebec3533;hp=663a6d4f047ec8a22d0e9341bdc477b3a0f56072;hb=081be002eae9bc7fc03dbfd7b99b4d28a7c98f9d;hpb=2236ddae2dc1c7d7b380452341b3beefeb471bd9 diff --git a/udev/udev-rules.c b/udev/udev-rules.c index 663a6d4f0..092ddcdc2 100644 --- a/udev/udev-rules.c +++ b/udev/udev-rules.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Kay Sievers + * Copyright (C) 2003-2009 Kay Sievers * Copyright (C) 2008 Alan Jenkins * * This program is free software: you can redistribute it and/or modify @@ -27,6 +27,7 @@ #include #include #include +#include #include "udev.h" @@ -103,7 +104,13 @@ enum string_glob_type { GL_SPLIT, /* multi-value A|B */ GL_SPLIT_GLOB, /* multi-value with glob A*|B* */ GL_SOMETHING, /* commonly used "?*" */ - GL_FORMAT, +}; + +enum string_subst_type { + SB_UNSET, + SB_NONE, + SB_FORMAT, + SB_SUBSYS, }; /* tokens of a rule are sorted/handled in this order */ @@ -157,7 +164,6 @@ enum token_type { TK_A_ATTR, /* val, attr */ TK_A_RUN, /* val, bool */ TK_A_GOTO, /* size_t */ - TK_A_LAST_RULE, TK_END, }; @@ -167,22 +173,24 @@ struct token { union { unsigned char type; /* same as in rule and key */ struct { - unsigned char type; - unsigned char flags; + enum token_type type:8; + unsigned int flags:8; unsigned short token_count; unsigned int label_off; unsigned short filename_off; unsigned short filename_line; } rule; struct { - unsigned char type; - unsigned char flags; - unsigned char op; - unsigned char glob; + enum token_type type:8; + enum operation_type op:8; + enum string_glob_type glob:8; + enum string_subst_type subst:4; + enum string_subst_type attrsubst:4; unsigned int value_off; union { unsigned int attr_off; - int ignore_error; + int devlink_unique; + int fail_on_error; unsigned int rule_goto; mode_t mode; uid_t uid; @@ -204,7 +212,7 @@ struct rule_tmp { unsigned int token_cur; }; -#ifdef DEBUG +#ifdef ENABLE_DEBUG static const char *operation_str(enum operation_type type) { static const char *operation_strs[] = { @@ -230,7 +238,6 @@ static const char *string_glob_str(enum string_glob_type type) [GL_SPLIT] = "split", [GL_SPLIT_GLOB] = "split-glob", [GL_SOMETHING] = "split-glob", - [GL_FORMAT] = "format", }; return string_glob_strs[type]; @@ -264,7 +271,7 @@ static const char *token_str(enum token_type type) [TK_M_PROGRAM] = "M PROGRAM", [TK_M_IMPORT_FILE] = "M IMPORT_FILE", [TK_M_IMPORT_PROG] = "M IMPORT_PROG", - [TK_M_IMPORT_PARENT] = "M MPORT_PARENT", + [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT", [TK_M_RESULT] = "M RESULT", [TK_M_MAX] = "M MAX", @@ -288,7 +295,6 @@ static const char *token_str(enum token_type type) [TK_A_ATTR] = "A ATTR", [TK_A_RUN] = "A RUN", [TK_A_GOTO] = "A GOTO", - [TK_A_LAST_RULE] = "A LAST_RULE", [TK_END] = "END", }; @@ -354,7 +360,6 @@ static void dump_token(struct udev_rules *rules, struct token *token) case TK_A_IGNORE_DEVICE: case TK_A_STRING_ESCAPE_NONE: case TK_A_STRING_ESCAPE_REPLACE: - case TK_A_LAST_RULE: case TK_A_IGNORE_REMOVE: dbg(rules->udev, "%s\n", token_str(type)); break; @@ -415,7 +420,7 @@ static inline const char *operation_str(enum operation_type type) { return NULL; static inline const char *token_str(enum token_type type) { return NULL; } static inline void dump_token(struct udev_rules *rules, struct token *token) {} static inline void dump_rules(struct udev_rules *rules) {} -#endif /* DEBUG */ +#endif /* ENABLE_DEBUG */ static int add_new_string(struct udev_rules *rules, const char *str, size_t bytes) { @@ -706,15 +711,15 @@ static int import_property_from_string(struct udev_device *dev, char *line) info(udev, "updating devpath from '%s' to '%s'\n", udev_device_get_devpath(dev), val); - util_strlcpy(syspath, udev_get_sys_path(udev), sizeof(syspath)); - util_strlcat(syspath, val, sizeof(syspath)); + util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), val, NULL); udev_device_set_syspath(dev, syspath); } else { struct udev_list_entry *entry; entry = udev_device_add_property(dev, key, val); - /* store in db */ - udev_list_entry_set_flag(entry, 1); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_flag(entry, 1); } return 0; } @@ -737,12 +742,12 @@ static int import_program_into_properties(struct udev_device *dev, const char *p { struct udev *udev = udev_device_get_udev(dev); char **envp; - char result[2048]; + char result[4096]; size_t reslen; char *line; envp = udev_device_get_properties_envp(dev); - if (util_run_program(udev, program, envp, result, sizeof(result), &reslen) != 0) + if (util_run_program(udev, program, envp, result, sizeof(result), &reslen, NULL) != 0) return -1; line = result; @@ -780,8 +785,9 @@ static int import_parent_into_properties(struct udev_device *dev, const char *fi dbg(udev, "import key '%s=%s'\n", key, val); entry = udev_device_add_property(dev, key, val); - /* store in db */ - udev_list_entry_set_flag(entry, 1); + /* store in db, skip private keys */ + if (key[0] != '.') + udev_list_entry_set_flag(entry, 1); } } return 0; @@ -799,17 +805,16 @@ static int wait_for_file(struct udev_device *dev, const char *file, int timeout) /* a relative path is a device attribute */ devicepath[0] = '\0'; if (file[0] != '/') { - util_strlcpy(devicepath, udev_get_sys_path(udev), sizeof(devicepath)); - util_strlcat(devicepath, udev_device_get_devpath(dev), sizeof(devicepath)); - - util_strlcpy(filepath, devicepath, sizeof(filepath)); - util_strlcat(filepath, "/", sizeof(filepath)); - util_strlcat(filepath, file, sizeof(filepath)); + util_strscpyl(devicepath, sizeof(devicepath), + udev_get_sys_path(udev), udev_device_get_devpath(dev), NULL); + util_strscpyl(filepath, sizeof(filepath), devicepath, "/", file, NULL); file = filepath; } dbg(udev, "will wait %i sec for '%s'\n", timeout, file); while (--loop) { + const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND }; + /* lookup file */ if (stat(file, &stats) == 0) { info(udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1); @@ -821,7 +826,7 @@ static int wait_for_file(struct udev_device *dev, const char *file, int timeout) return -2; } info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND); - usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND); + nanosleep(&duration, NULL); } info(udev, "waiting for '%s' failed\n", file); return -1; @@ -829,17 +834,21 @@ static int wait_for_file(struct udev_device *dev, const char *file, int timeout) static int attr_subst_subdir(char *attr, size_t len) { - char *pos; int found = 0; - pos = strstr(attr, "/*/"); - if (pos != NULL) { - char str[UTIL_PATH_SIZE]; + if (strstr(attr, "/*/")) { + char *pos; + char dirname[UTIL_PATH_SIZE]; + const char *tail; DIR *dir; - pos[1] = '\0'; - util_strlcpy(str, &pos[2], sizeof(str)); - dir = opendir(attr); + util_strscpy(dirname, sizeof(dirname), attr); + pos = strstr(dirname, "/*/"); + if (pos == NULL) + return -1; + pos[0] = '\0'; + tail = &pos[2]; + dir = opendir(dirname); if (dir != NULL) { struct dirent *dent; @@ -848,18 +857,14 @@ static int attr_subst_subdir(char *attr, size_t len) if (dent->d_name[0] == '.') continue; - util_strlcat(attr, dent->d_name, len); - util_strlcat(attr, str, len); + util_strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL); if (stat(attr, &stats) == 0) { found = 1; break; } - pos[1] = '\0'; } closedir(dir); } - if (!found) - util_strlcat(attr, str, len); } return found; @@ -871,7 +876,7 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty char *temp; linepos = *line; - if (linepos == NULL && linepos[0] == '\0') + if (linepos == NULL || linepos[0] == '\0') return -1; /* skip whitespace */ @@ -979,8 +984,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, const char *value, const void *data) { struct token *token = &rule_tmp->token[rule_tmp->token_cur]; - const char *attr = data; - enum string_glob_type glob; + const char *attr = NULL; memset(token, 0x00, sizeof(struct token)); @@ -1005,7 +1009,6 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_A_GROUP: case TK_A_MODE: case TK_A_NAME: - case TK_A_DEVLINK: case TK_A_GOTO: token->key.value_off = add_string(rule_tmp->rules, value); break; @@ -1014,9 +1017,14 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_M_ATTRS: case TK_A_ATTR: case TK_A_ENV: + attr = data; token->key.value_off = add_string(rule_tmp->rules, value); token->key.attr_off = add_string(rule_tmp->rules, attr); break; + case TK_A_DEVLINK: + token->key.value_off = add_string(rule_tmp->rules, value); + token->key.devlink_unique = *(int *)data; + break; case TK_M_TEST: token->key.value_off = add_string(rule_tmp->rules, value); if (data != NULL) @@ -1026,11 +1034,10 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, case TK_A_STRING_ESCAPE_NONE: case TK_A_STRING_ESCAPE_REPLACE: case TK_A_IGNORE_REMOVE: - case TK_A_LAST_RULE: break; case TK_A_RUN: token->key.value_off = add_string(rule_tmp->rules, value); - token->key.ignore_error = *(int *)data; + token->key.fail_on_error = *(int *)data; break; case TK_A_INOTIFY_WATCH: case TK_A_NUM_FAKE_PART: @@ -1059,36 +1066,51 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type, return -1; } - glob = GL_PLAIN; - if (value != NULL) { - if (type < TK_M_MAX) { - /* check if we need to split or call fnmatch() while matching rules */ - int has_split; - int has_glob; - - has_split = (strchr(value, '|') != NULL); - has_glob = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || - strchr(value, '[') != NULL || strchr(value, ']') != NULL); - if (has_split && has_glob) { - glob = GL_SPLIT_GLOB; - } else if (has_split) { - glob = GL_SPLIT; - } else if (has_glob) { - if (strcmp(value, "?*") == 0) - glob = GL_SOMETHING; - else - glob = GL_GLOB; - } + if (value != NULL && type < TK_M_MAX) { + /* check if we need to split or call fnmatch() while matching rules */ + enum string_glob_type glob; + int has_split; + int has_glob; + + has_split = (strchr(value, '|') != NULL); + has_glob = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || strchr(value, '[') != NULL); + if (has_split && has_glob) { + glob = GL_SPLIT_GLOB; + } else if (has_split) { + glob = GL_SPLIT; + } else if (has_glob) { + if (strcmp(value, "?*") == 0) + glob = GL_SOMETHING; + else + glob = GL_GLOB; } else { - /* check if we need to substitute format strings for matching rules */ - if (strchr(value, '%') != NULL || strchr(value, '$') != NULL) - glob = GL_FORMAT; + glob = GL_PLAIN; } + token->key.glob = glob; + } + + if (value != NULL && type > TK_M_MAX) { + /* check if assigned value has substitution chars */ + if (value[0] == '[') + token->key.subst = SB_SUBSYS; + else if (strchr(value, '%') != NULL || strchr(value, '$') != NULL) + token->key.subst = SB_FORMAT; + else + token->key.subst = SB_NONE; + } + + if (attr != NULL) { + /* check if property/attribut name has substitution chars */ + if (attr[0] == '[') + token->key.attrsubst = SB_SUBSYS; + else if (strchr(attr, '%') != NULL || strchr(attr, '$') != NULL) + token->key.attrsubst = SB_FORMAT; + else + token->key.attrsubst = SB_NONE; } token->key.type = type; token->key.op = op; - token->key.glob = glob; rule_tmp->token_cur++; if (rule_tmp->token_cur >= ARRAY_SIZE(rule_tmp->token)) { err(rule_tmp->rules->udev, "temporary rule array too small\n"); @@ -1105,7 +1127,7 @@ static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp) for (i = 0; i < rule_tmp->token_cur; i++) { enum token_type next_val = TK_UNSET; - unsigned int next_idx; + unsigned int next_idx = 0; unsigned int j; /* find smallest value */ @@ -1137,8 +1159,6 @@ static int add_rule(struct udev_rules *rules, char *line, { char *linepos; char *attr; - int physdev = 0; - int waitfor = 0; struct rule_tmp rule_tmp; memset(&rule_tmp, 0x00, sizeof(struct rule_tmp)); @@ -1156,7 +1176,7 @@ static int add_rule(struct udev_rules *rules, char *line, if (get_key(rules->udev, &linepos, &key, &op, &value) != 0) break; - if (strcasecmp(key, "ACTION") == 0) { + if (strcmp(key, "ACTION") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid ACTION operation\n"); goto invalid; @@ -1165,7 +1185,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "DEVPATH") == 0) { + if (strcmp(key, "DEVPATH") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid DEVPATH operation\n"); goto invalid; @@ -1174,7 +1194,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "KERNEL") == 0) { + if (strcmp(key, "KERNEL") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid KERNEL operation\n"); goto invalid; @@ -1183,7 +1203,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "SUBSYSTEM") == 0) { + if (strcmp(key, "SUBSYSTEM") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid SUBSYSTEM operation\n"); goto invalid; @@ -1201,7 +1221,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "DRIVER") == 0) { + if (strcmp(key, "DRIVER") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid DRIVER operation\n"); goto invalid; @@ -1210,7 +1230,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strncasecmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) { + if (strncmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) { attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1); if (attr == NULL) { err(rules->udev, "error parsing ATTR attribute\n"); @@ -1224,8 +1244,8 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "KERNELS") == 0 || - strcasecmp(key, "ID") == 0) { + if (strcmp(key, "KERNELS") == 0 || + strcmp(key, "ID") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid KERNELS operation\n"); goto invalid; @@ -1234,8 +1254,8 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "SUBSYSTEMS") == 0 || - strcasecmp(key, "BUS") == 0) { + if (strcmp(key, "SUBSYSTEMS") == 0 || + strcmp(key, "BUS") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid SUBSYSTEMS operation\n"); goto invalid; @@ -1244,7 +1264,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "DRIVERS") == 0) { + if (strcmp(key, "DRIVERS") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid DRIVERS operation\n"); goto invalid; @@ -1253,8 +1273,8 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strncasecmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 || - strncasecmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) { + if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 || + strncmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid ATTRS operation\n"); goto invalid; @@ -1274,14 +1294,12 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strncasecmp(key, "ENV{", sizeof("ENV{")-1) == 0) { + if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) { attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1); if (attr == NULL) { err(rules->udev, "error parsing ENV attribute\n"); goto invalid; } - if (strncmp(attr, "PHYSDEV", 7) == 0) - physdev = 1; if (op < OP_MATCH_MAX) { if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0) goto invalid; @@ -1292,12 +1310,12 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "PROGRAM") == 0) { + if (strcmp(key, "PROGRAM") == 0) { rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL); continue; } - if (strcasecmp(key, "RESULT") == 0) { + if (strcmp(key, "RESULT") == 0) { if (op > OP_MATCH_MAX) { err(rules->udev, "invalid RESULT operation\n"); goto invalid; @@ -1306,7 +1324,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strncasecmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) { + if (strncmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) { attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1); if (attr != NULL && strstr(attr, "program")) { dbg(rules->udev, "IMPORT will be executed\n"); @@ -1323,22 +1341,16 @@ static int add_rule(struct udev_rules *rules, char *line, char *pos; struct stat statbuf; - util_strlcpy(file, value, sizeof(file)); + /* allow programs in /lib/udev called without the path */ + if (value[0] != '/') + util_strscpyl(file, sizeof(file), LIBEXECDIR "/", value, NULL); + else + util_strscpy(file, sizeof(file), value); pos = strchr(file, ' '); if (pos) pos[0] = '\0'; - - /* allow programs in /lib/udev called without the path */ - if (strchr(file, '/') == NULL) { - util_strlcpy(file, UDEV_PREFIX "/lib/udev/", sizeof(file)); - util_strlcat(file, value, sizeof(file)); - pos = strchr(file, ' '); - if (pos) - pos[0] = '\0'; - } - dbg(rules->udev, "IMPORT auto mode for '%s'\n", file); - if (!lstat(file, &statbuf) && (statbuf.st_mode & S_IXUSR)) { + if (stat(file, &statbuf) == 0 && (statbuf.st_mode & S_IXUSR)) { dbg(rules->udev, "IMPORT will be executed (autotype)\n"); rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL); } else { @@ -1349,7 +1361,7 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strncasecmp(key, "TEST", sizeof("TEST")-1) == 0) { + if (strncmp(key, "TEST", sizeof("TEST")-1) == 0) { mode_t mode = 0; if (op > OP_MATCH_MAX) { @@ -1366,38 +1378,40 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strncasecmp(key, "RUN", sizeof("RUN")-1) == 0) { + if (strncmp(key, "RUN", sizeof("RUN")-1) == 0) { int flag = 0; attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1); - if (attr != NULL && strstr(attr, "ignore_error")) + if (attr != NULL && strstr(attr, "fail_event_on_error")) flag = 1; rule_add_key(&rule_tmp, TK_A_RUN, op, value, &flag); continue; } - if (strcasecmp(key, "WAIT_FOR") == 0 || strcasecmp(key, "WAIT_FOR_SYSFS") == 0) { + if (strcmp(key, "WAIT_FOR") == 0 || strcmp(key, "WAIT_FOR_SYSFS") == 0) { rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL); - waitfor = 1; continue; } - if (strcasecmp(key, "LABEL") == 0) { + if (strcmp(key, "LABEL") == 0) { rule_tmp.rule.rule.label_off = add_string(rules, value); continue; } - if (strcasecmp(key, "GOTO") == 0) { + if (strcmp(key, "GOTO") == 0) { rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL); continue; } - if (strncasecmp(key, "NAME", sizeof("NAME")-1) == 0) { + if (strncmp(key, "NAME", sizeof("NAME")-1) == 0) { 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); rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL); attr = get_key_attribute(rules->udev, key + sizeof("NAME")-1); if (attr != NULL) { @@ -1417,16 +1431,22 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "SYMLINK") == 0) { - if (op < OP_MATCH_MAX) + if (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) { + if (op < OP_MATCH_MAX) { rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL); - else - rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL); + } else { + int flag = 0; + + attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1); + if (attr != NULL && strstr(attr, "unique") != NULL) + flag = 1; + rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag); + } rule_tmp.rule.rule.flags = 1; continue; } - if (strcasecmp(key, "OWNER") == 0) { + if (strcmp(key, "OWNER") == 0) { uid_t uid; char *endptr; @@ -1436,14 +1456,14 @@ static int add_rule(struct udev_rules *rules, char *line, } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { uid = add_uid(rules, value); rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid); - } else if (rules->resolve_names == 0) { + } else if (rules->resolve_names >= 0) { rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL); } rule_tmp.rule.rule.flags = 1; continue; } - if (strcasecmp(key, "GROUP") == 0) { + if (strcmp(key, "GROUP") == 0) { gid_t gid; char *endptr; @@ -1453,14 +1473,14 @@ static int add_rule(struct udev_rules *rules, char *line, } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) { gid = add_gid(rules, value); rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid); - } else if (rules->resolve_names == 0) { + } else if (rules->resolve_names >= 0) { rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL); } rule_tmp.rule.rule.flags = 1; continue; } - if (strcasecmp(key, "MODE") == 0) { + if (strcmp(key, "MODE") == 0) { mode_t mode; char *endptr; @@ -1473,13 +1493,9 @@ static int add_rule(struct udev_rules *rules, char *line, continue; } - if (strcasecmp(key, "OPTIONS") == 0) { + if (strcmp(key, "OPTIONS") == 0) { const char *pos; - if (strstr(value, "last_rule") != NULL) { - dbg(rules->udev, "last rule to be applied\n"); - rule_add_key(&rule_tmp, TK_A_LAST_RULE, 0, NULL, NULL); - } if (strstr(value, "ignore_device") != NULL) { dbg(rules->udev, "device should be ignored\n"); rule_add_key(&rule_tmp, TK_A_IGNORE_DEVICE, 0, NULL, NULL); @@ -1500,7 +1516,7 @@ static int add_rule(struct udev_rules *rules, char *line, int tout = atoi(&pos[strlen("event_timeout=")]); rule_add_key(&rule_tmp, TK_A_EVENT_TIMEOUT, 0, NULL, &tout); - dbg(rules->udev, "event timout=%i\n", tout); + dbg(rules->udev, "event timeout=%i\n", tout); } pos = strstr(value, "string_escape="); if (pos != NULL) { @@ -1536,10 +1552,6 @@ static int add_rule(struct udev_rules *rules, char *line, err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno); } - if (physdev && !waitfor) - err(rules->udev, "PHYSDEV* values are deprecated and not available on recent kernels, " - "please fix it in %s:%u\n", filename, lineno); - /* add rule token */ rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur; if (add_token(rules, &rule_tmp.rule) != 0) @@ -1571,7 +1583,7 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s first_token = rules->token_cur; - while(fgets(line, sizeof(line), f) != NULL) { + while (fgets(line, sizeof(line), f) != NULL) { char *key; size_t len; @@ -1593,6 +1605,8 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s while (line[len-2] == '\\') { if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL) break; + if (strlen(&line[len-2]) < 2) + break; line_nr++; len = strlen(line); } @@ -1619,6 +1633,7 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s if (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0) continue; rules->tokens[i].key.rule_goto = j; + break; } if (rules->tokens[i].key.rule_goto == 0) err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename); @@ -1659,10 +1674,8 @@ static int add_matching_files(struct udev *udev, struct udev_list_node *file_lis if (strcmp(ext, suffix) != 0) continue; } - dbg(udev, "put file '%s/%s' into list\n", dirname, dent->d_name); - - snprintf(filename, sizeof(filename), "%s/%s", dirname, dent->d_name); - filename[sizeof(filename)-1] = '\0'; + 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); } @@ -1722,19 +1735,12 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules"); /* read dynamic/temporary rules */ - util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename)); - util_strlcat(filename, "/.udev/rules.d", sizeof(filename)); - if (stat(filename, &statbuf) != 0) { - util_create_path(udev, filename); - udev_selinux_setfscreatecon(udev, filename, S_IFDIR|0755); - mkdir(filename, 0755); - udev_selinux_resetfscreatecon(udev); - } + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(udev), "/.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, UDEV_PREFIX "/lib/udev/rules.d", ".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)) { @@ -1793,7 +1799,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names) if (stat(filename, &statbuf) == 0 && statbuf.st_size > 0) parse_file(rules, filename, filename_off); else - info(udev, "can not read '%s'\n", filename); + err(udev, "can not read '%s'\n", filename); udev_list_entry_delete(file_loop); } @@ -1903,7 +1909,7 @@ static int match_key(struct udev_rules *rules, struct token *token, const char * { char value[UTIL_PATH_SIZE]; - util_strlcpy(value, &rules->buf[token->key.value_off], sizeof(value)); + util_strscpy(value, sizeof(value), &rules->buf[token->key.value_off]); key_value = value; while (key_value != NULL) { pos = strchr(key_value, '|'); @@ -1922,7 +1928,6 @@ static int match_key(struct udev_rules *rules, struct token *token, const char * case GL_SOMETHING: match = (val[0] != '\0'); break; - case GL_FORMAT: case GL_UNSET: return -1; } @@ -1941,35 +1946,51 @@ static int match_key(struct udev_rules *rules, struct token *token, const char * static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur) { - const char *key_name = &rules->buf[cur->key.attr_off]; - const char *key_value = &rules->buf[cur->key.value_off]; - char value[UTIL_NAME_SIZE]; + const char *name; + char nbuf[UTIL_NAME_SIZE]; + const char *value; + char vbuf[UTIL_NAME_SIZE]; size_t len; - value[0] = '\0'; - if (key_name[0] == '[') { - char attr[UTIL_PATH_SIZE]; - - util_strlcpy(attr, key_name, sizeof(attr)); - util_resolve_subsys_kernel(event->udev, attr, value, sizeof(value), 1); - } - if (value[0] == '\0') { - const char *val; - - val = udev_device_get_sysattr_value(dev, key_name); - if (val == NULL) + name = &rules->buf[cur->key.attr_off]; + switch (cur->key.attrsubst) { + case SB_FORMAT: + udev_event_apply_format(event, name, nbuf, sizeof(nbuf)); + name = nbuf; + /* fall through */ + case SB_NONE: + value = udev_device_get_sysattr_value(dev, name); + if (value == NULL) + return -1; + break; + case SB_SUBSYS: + if (util_resolve_subsys_kernel(event->udev, name, vbuf, sizeof(vbuf), 1) != 0) return -1; - util_strlcpy(value, val, sizeof(value)); + value = vbuf; + break; + default: + return -1; } - /* strip trailing whitespace of value, if not asked to match for it */ - len = strlen(key_value); - if (len > 0 && !isspace(key_value[len-1])) { - len = strlen(value); - while (len > 0 && isspace(value[--len])) - value[len] = '\0'; - dbg(rules->udev, "removed trailing whitespace from '%s'\n", value); + /* remove trailing whitespace, if not asked to match for it */ + len = strlen(value); + if (len > 0 && isspace(value[len-1])) { + const char *key_value; + size_t klen; + + key_value = &rules->buf[cur->key.value_off]; + klen = strlen(key_value); + if (klen > 0 && !isspace(key_value[klen-1])) { + if (value != vbuf) { + util_strscpy(vbuf, sizeof(vbuf), value); + value = vbuf; + } + while (len > 0 && isspace(vbuf[--len])) + vbuf[len] = '\0'; + dbg(rules->udev, "removed trailing whitespace from '%s'\n", value); + } } + return match_key(rules, cur, value); } @@ -2070,8 +2091,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event char filename[UTIL_PATH_SIZE]; int found; - util_strlcpy(filename, &rules->buf[cur->key.value_off], sizeof(filename)); - udev_event_apply_format(event, filename, sizeof(filename)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename)); found = (wait_for_file(event->dev, filename, 10) == 0); if (!found && (cur->key.op != OP_NOMATCH)) goto nomatch; @@ -2143,18 +2163,16 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event struct stat statbuf; int match; - util_strlcpy(filename, &rules->buf[cur->key.value_off], sizeof(filename)); - udev_event_apply_format(event, filename, sizeof(filename)); - if (util_resolve_subsys_kernel(event->udev, NULL, filename, sizeof(filename), 0) != 0) + udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename)); + if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) { if (filename[0] != '/') { char tmp[UTIL_PATH_SIZE]; - util_strlcpy(tmp, udev_device_get_syspath(event->dev), sizeof(tmp)); - util_strlcat(tmp, "/", sizeof(tmp)); - util_strlcat(tmp, filename, sizeof(tmp)); - util_strlcpy(filename, tmp, sizeof(filename)); + util_strscpy(tmp, sizeof(tmp), filename); + util_strscpyl(filename, sizeof(filename), + udev_device_get_syspath(event->dev), "/", tmp, NULL); } - + } attr_subst_subdir(filename, sizeof(filename)); match = (stat(filename, &statbuf) == 0); @@ -2178,14 +2196,13 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event free(event->program_result); event->program_result = NULL; - util_strlcpy(program, &rules->buf[cur->key.value_off], sizeof(program)); - udev_event_apply_format(event, program, sizeof(program)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], program, sizeof(program)); envp = udev_device_get_properties_envp(event->dev); info(event->udev, "PROGRAM '%s' %s:%u\n", program, &rules->buf[rule->rule.filename_off], rule->rule.filename_line); - if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL) != 0) { + if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL, NULL) != 0) { if (cur->key.op != OP_NOMATCH) goto nomatch; } else { @@ -2208,8 +2225,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event { char import[UTIL_PATH_SIZE]; - util_strlcpy(import, &rules->buf[cur->key.value_off], sizeof(import)); - udev_event_apply_format(event, import, sizeof(import)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import)); if (import_file_into_properties(event->dev, import) != 0) if (cur->key.op != OP_NOMATCH) goto nomatch; @@ -2219,8 +2235,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event { char import[UTIL_PATH_SIZE]; - util_strlcpy(import, &rules->buf[cur->key.value_off], sizeof(import)); - udev_event_apply_format(event, import, sizeof(import)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import)); info(event->udev, "IMPORT '%s' %s:%u\n", import, &rules->buf[rule->rule.filename_off], @@ -2234,8 +2249,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event { char import[UTIL_PATH_SIZE]; - util_strlcpy(import, &rules->buf[cur->key.value_off], sizeof(import)); - udev_event_apply_format(event, import, sizeof(import)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import)); if (import_parent_into_properties(event->dev, import) != 0) if (cur->key.op != OP_NOMATCH) goto nomatch; @@ -2277,8 +2291,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event break; if (cur->key.op == OP_ASSIGN_FINAL) event->owner_final = 1; - util_strlcpy(owner, &rules->buf[cur->key.value_off], sizeof(owner)); - udev_event_apply_format(event, owner, sizeof(owner)); + 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", event->uid, @@ -2294,8 +2307,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event break; if (cur->key.op == OP_ASSIGN_FINAL) event->group_final = 1; - util_strlcpy(group, &rules->buf[cur->key.value_off], sizeof(group)); - udev_event_apply_format(event, group, sizeof(group)); + 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", event->gid, @@ -2312,8 +2324,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 = 1; - util_strlcpy(mode, &rules->buf[cur->key.value_off], sizeof(mode)); - udev_event_apply_format(event, mode, sizeof(mode)); + 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); @@ -2367,11 +2378,11 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event char temp_value[UTIL_NAME_SIZE]; struct udev_list_entry *entry; - util_strlcpy(temp_value, value, sizeof(temp_value)); - udev_event_apply_format(event, temp_value, sizeof(temp_value)); + udev_event_apply_format(event, value, temp_value, sizeof(temp_value)); entry = udev_device_add_property(event->dev, name, temp_value); - /* store in db */ - udev_list_entry_set_flag(entry, 1); + /* store in db, skip private keys */ + if (name[0] != '.') + udev_list_entry_set_flag(entry, 1); } else { udev_device_add_property(event->dev, name, NULL); } @@ -2387,8 +2398,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event break; if (cur->key.op == OP_ASSIGN_FINAL) event->name_final = 1; - util_strlcpy(name_str, name, sizeof(name_str)); - udev_event_apply_format(event, name_str, sizeof(name_str)); + 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, "/"); if (count > 0) @@ -2419,8 +2429,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event udev_device_cleanup_devlinks_list(event->dev); /* allow multiple symlinks separated by spaces */ - util_strlcpy(temp, &rules->buf[cur->key.value_off], sizeof(temp)); - udev_event_apply_format(event, temp, sizeof(temp)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], temp, sizeof(temp)); if (esc == ESCAPE_UNSET) count = udev_util_replace_chars(temp, "/ "); else if (esc == ESCAPE_REPLACE) @@ -2432,30 +2441,22 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event while (isspace(pos[0])) pos++; next = strchr(pos, ' '); - while (next) { + while (next != NULL) { next[0] = '\0'; - info(event->udev, "LINK '%s' %s:%u\n", - pos, - &rules->buf[rule->rule.filename_off], - rule->rule.filename_line); - util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename)); - util_strlcat(filename, "/", sizeof(filename)); - util_strlcat(filename, pos, sizeof(filename)); - udev_device_add_devlink(event->dev, filename); + info(event->udev, "LINK '%s' %s:%u\n", pos, + &rules->buf[rule->rule.filename_off], rule->rule.filename_line); + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL); + udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique); while (isspace(next[1])) next++; pos = &next[1]; next = strchr(pos, ' '); } if (pos[0] != '\0') { - info(event->udev, "LINK '%s' %s:%u\n", - pos, - &rules->buf[rule->rule.filename_off], - rule->rule.filename_line); - util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename)); - util_strlcat(filename, "/", sizeof(filename)); - util_strlcat(filename, pos, sizeof(filename)); - udev_device_add_devlink(event->dev, filename); + info(event->udev, "LINK '%s' %s:%u\n", pos, + &rules->buf[rule->rule.filename_off], rule->rule.filename_line); + util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL); + udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique); } } break; @@ -2472,17 +2473,11 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event char value[UTIL_NAME_SIZE]; FILE *f; - util_strlcpy(attr, key_name, sizeof(attr)); - if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) { - util_strlcpy(attr, udev_device_get_syspath(event->dev), sizeof(attr)); - util_strlcat(attr, "/", sizeof(attr)); - util_strlcat(attr, key_name, sizeof(attr)); - } - + if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) + util_strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL); attr_subst_subdir(attr, sizeof(attr)); - util_strlcpy(value, &rules->buf[cur->key.value_off], sizeof(value)); - udev_event_apply_format(event, value, sizeof(value)); + udev_event_apply_format(event, &rules->buf[cur->key.value_off], value, sizeof(value)); info(event->udev, "ATTR '%s' writing '%s' %s:%u\n", attr, value, &rules->buf[rule->rule.filename_off], rule->rule.filename_line); @@ -2508,14 +2503,15 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event rule->rule.filename_line); list_entry = udev_list_entry_add(event->udev, &event->run_list, &rules->buf[cur->key.value_off], NULL, 1, 0); - if (cur->key.ignore_error) + if (cur->key.fail_on_error) udev_list_entry_set_flag(list_entry, 1); break; } case TK_A_GOTO: + if (cur->key.rule_goto == 0) + break; cur = &rules->tokens[cur->key.rule_goto]; continue; - case TK_A_LAST_RULE: case TK_END: return 0;