1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-03-08 20:58:20 +03:00

Merge pull request #11746 from yuwata/udev-rules-cleanup

udev-rules: several cleanups for udev-rules.c
This commit is contained in:
Lennart Poettering 2019-02-18 13:05:34 +01:00 committed by GitHub
commit 1ff3e129ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 92 deletions

View File

@ -63,19 +63,19 @@ struct UdevRules {
/* every key in the rules file becomes a token */
struct token *tokens;
unsigned token_cur;
unsigned token_max;
size_t token_cur;
size_t token_max;
/* all key strings are copied and de-duplicated in a single continuous string buffer */
struct strbuf *strbuf;
/* during rule parsing, uid/gid lookup results are cached */
struct uid_gid *uids;
unsigned uids_cur;
unsigned uids_max;
size_t uids_cur;
size_t uids_max;
struct uid_gid *gids;
unsigned gids_cur;
unsigned gids_max;
size_t gids_cur;
size_t gids_max;
};
static char *rules_str(UdevRules *rules, unsigned off) {
@ -219,7 +219,7 @@ struct rule_tmp {
UdevRules *rules;
struct token rule;
struct token token[MAX_TK];
unsigned token_cur;
size_t token_cur;
};
#if ENABLE_DEBUG_UDEV
@ -430,9 +430,9 @@ static void dump_token(UdevRules *rules, struct token *token) {
}
static void dump_rules(UdevRules *rules) {
unsigned i;
size_t i;
log_debug("Dumping %u (%zu bytes) tokens, %zu (%zu bytes) strings",
log_debug("Dumping %zu (%zu bytes) tokens, %zu (%zu bytes) strings",
rules->token_cur,
rules->token_cur * sizeof(struct token),
rules->strbuf->nodes_count,
@ -447,21 +447,9 @@ static void dump_rules(UdevRules *rules) {}
static int add_token(UdevRules *rules, struct token *token) {
/* grow buffer if needed */
if (rules->token_cur+1 >= rules->token_max) {
struct token *tokens;
unsigned add;
if (!GREEDY_REALLOC(rules->tokens, rules->token_max, rules->token_cur + 1))
return -ENOMEM;
/* double the buffer size */
add = rules->token_max;
if (add < 8)
add = 8;
tokens = reallocarray(rules->tokens, rules->token_max + add, sizeof(struct token));
if (!tokens)
return -ENOMEM;
rules->tokens = tokens;
rules->token_max += add;
}
memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
rules->token_cur++;
return 0;
@ -475,9 +463,9 @@ static void log_unknown_owner(sd_device *dev, int error, const char *entity, con
}
static uid_t add_uid(UdevRules *rules, const char *owner) {
unsigned i;
uid_t uid = 0;
unsigned off;
size_t i;
int r;
/* lookup, if we know it already */
@ -491,21 +479,9 @@ static uid_t add_uid(UdevRules *rules, const char *owner) {
log_unknown_owner(NULL, r, "user", owner);
/* grow buffer if needed */
if (rules->uids_cur+1 >= rules->uids_max) {
struct uid_gid *uids;
unsigned add;
if (!GREEDY_REALLOC(rules->uids, rules->uids_max, rules->uids_cur + 1))
return -ENOMEM;
/* double the buffer size */
add = rules->uids_max;
if (add < 1)
add = 8;
uids = reallocarray(rules->uids, rules->uids_max + add, sizeof(struct uid_gid));
if (!uids)
return uid;
rules->uids = uids;
rules->uids_max += add;
}
rules->uids[rules->uids_cur].uid = uid;
off = rules_add_string(rules, owner);
if (off <= 0)
@ -516,9 +492,9 @@ static uid_t add_uid(UdevRules *rules, const char *owner) {
}
static gid_t add_gid(UdevRules *rules, const char *group) {
unsigned i;
gid_t gid = 0;
unsigned off;
size_t i;
int r;
/* lookup, if we know it already */
@ -532,21 +508,9 @@ static gid_t add_gid(UdevRules *rules, const char *group) {
log_unknown_owner(NULL, r, "group", group);
/* grow buffer if needed */
if (rules->gids_cur+1 >= rules->gids_max) {
struct uid_gid *gids;
unsigned add;
if (!GREEDY_REALLOC(rules->gids, rules->gids_max, rules->gids_cur + 1))
return -ENOMEM;
/* double the buffer size */
add = rules->gids_max;
if (add < 1)
add = 8;
gids = reallocarray(rules->gids, rules->gids_max + add, sizeof(struct uid_gid));
if (!gids)
return gid;
rules->gids = gids;
rules->gids_max += add;
}
rules->gids[rules->gids_cur].gid = gid;
off = rules_add_string(rules, group);
if (off <= 0)
@ -712,7 +676,7 @@ static void attr_subst_subdir(char *attr, size_t len) {
static int get_key(char **line, char **key, enum operation_type *op, char **value) {
char *linepos;
char *temp;
unsigned i, j;
size_t i, j;
linepos = *line;
if (!linepos || linepos[0] == '\0')
@ -973,15 +937,15 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
}
static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) {
unsigned i;
unsigned start = 0;
unsigned end = rule_tmp->token_cur;
size_t i;
size_t start = 0;
size_t end = rule_tmp->token_cur;
int r;
for (i = 0; i < rule_tmp->token_cur; i++) {
enum token_type next_val = TK_UNSET;
unsigned next_idx = 0;
unsigned j;
size_t next_idx = 0;
size_t j;
/* find smallest value */
for (j = start; j < end; j++) {
@ -1013,7 +977,7 @@ static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) {
#define LOG_RULE_WARNING(fmt, ...) LOG_RULE_FULL(LOG_WARNING, fmt, ##__VA_ARGS__)
#define LOG_RULE_DEBUG(fmt, ...) LOG_RULE_FULL(LOG_DEBUG, fmt, ##__VA_ARGS__)
#define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; }
#define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur);
#define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %zu items", rule_tmp.token_cur);
static void add_rule(UdevRules *rules, char *line,
const char *filename, unsigned filename_off, unsigned lineno) {
@ -1370,13 +1334,11 @@ static void add_rule(UdevRules *rules, char *line,
} else if (streq(key, "OWNER")) {
uid_t uid;
char *endptr;
if (op == OP_REMOVE)
LOG_AND_RETURN("Invalid %s operation", key);
uid = strtoul(value, &endptr, 10);
if (endptr[0] == '\0')
if (parse_uid(value, &uid) >= 0)
r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && !strchr("$%", value[0])) {
uid = add_uid(rules, value);
@ -1394,13 +1356,11 @@ static void add_rule(UdevRules *rules, char *line,
} else if (streq(key, "GROUP")) {
gid_t gid;
char *endptr;
if (op == OP_REMOVE)
LOG_AND_RETURN("Invalid %s operation", key);
gid = strtoul(value, &endptr, 10);
if (endptr[0] == '\0')
if (parse_gid(value, &gid) >= 0)
r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
else if ((rules->resolve_name_timing == RESOLVE_NAME_EARLY) && !strchr("$%", value[0])) {
gid = add_gid(rules, value);
@ -1499,12 +1459,12 @@ static void add_rule(UdevRules *rules, char *line,
}
static int parse_file(UdevRules *rules, const char *filename) {
_cleanup_free_ char *continuation = NULL;
_cleanup_fclose_ FILE *f = NULL;
unsigned first_token;
bool ignore_line = false;
size_t first_token, i;
unsigned filename_off;
char line[UTIL_LINE_SIZE];
int line_nr = 0;
unsigned i;
int line_nr = 0, r;
f = fopen(filename, "re");
if (!f) {
@ -1523,46 +1483,68 @@ static int parse_file(UdevRules *rules, const char *filename) {
first_token = rules->token_cur;
filename_off = rules_add_string(rules, filename);
while (fgets(line, sizeof(line), f)) {
char *key;
for (;;) {
_cleanup_free_ char *buf = NULL;
size_t len;
char *line;
r = read_line(f, UTIL_LINE_SIZE, &buf);
if (r < 0)
return r;
if (r == 0)
break;
/* skip whitespace */
line_nr++;
key = line;
while (isspace(key[0]))
key++;
line = buf + strspn(buf, WHITESPACE);
/* comment */
if (key[0] == '#')
if (line[0] == '#')
continue;
len = strlen(line);
if (len < 3)
continue;
/* continue reading if backslash+newline is found */
while (line[len-2] == '\\') {
if (!fgets(&line[len-2], (sizeof(line)-len)+2, f))
break;
if (strlen(&line[len-2]) < 2)
break;
line_nr++;
len = strlen(line);
if (continuation && !ignore_line) {
if (strlen(continuation) + len >= UTIL_LINE_SIZE)
ignore_line = true;
if (!strextend(&continuation, line, NULL))
return log_oom();
if (!ignore_line) {
line = continuation;
len = strlen(line);
}
}
if (len+1 >= sizeof(line)) {
log_error("Line too long '%s':%u, ignored", filename, line_nr);
if (line[len - 1] == '\\') {
if (ignore_line)
continue;
line[len - 1] = '\0';
if (!continuation) {
continuation = strdup(line);
if (!continuation)
return log_oom();
}
continue;
}
add_rule(rules, key, filename, filename_off, line_nr);
if (ignore_line)
log_error("Line too long '%s':%u, ignored", filename, line_nr);
else
add_rule(rules, line, filename, filename_off, line_nr);
continuation = mfree(continuation);
ignore_line = false;
}
/* link GOTOs to LABEL rules in this file to be able to fast-forward */
for (i = first_token+1; i < rules->token_cur; i++) {
if (rules->tokens[i].type == TK_A_GOTO) {
char *label = rules_str(rules, rules->tokens[i].key.value_off);
unsigned j;
size_t j;
for (j = i+1; j < rules->token_cur; j++) {
if (rules->tokens[j].type != TK_RULE)
@ -1598,7 +1580,7 @@ int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing)
};
/* init token array and string buffer */
rules->tokens = malloc_multiply(PREALLOC_TOKEN, sizeof(struct token));
rules->tokens = new(struct token, PREALLOC_TOKEN);
if (!rules->tokens)
return -ENOMEM;
rules->token_max = PREALLOC_TOKEN;
@ -1625,7 +1607,7 @@ int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing)
struct token end_token = { .type = TK_END };
add_token(rules, &end_token);
log_debug("Rules contain %zu bytes tokens (%u * %zu bytes), %zu bytes strings",
log_debug("Rules contain %zu bytes tokens (%zu * %zu bytes), %zu bytes strings",
rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->strbuf->len);
/* cleanup temporary strbuf data */

View File

@ -39,6 +39,11 @@ for (my $i = 1; $i <= 10000; ++$i) {
$rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
}
my $rules_10k_tags_continuation = "";
for (my $i = 1; $i <= 10000; ++$i) {
$rules_10k_tags_continuation .= 'KERNEL=="sda", TAG+="test' . $i . "\"\\\n";
}
my @tests = (
{
desc => "no rules",
@ -1444,6 +1449,16 @@ EOF
exp_name => "found",
rules => $rules_10k_tags . <<EOF
TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
EOF
},
{
desc => "don't crash with lots of tags with continuation",
devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
exp_name => "found",
not_exp_name => "bad" ,
rules => $rules_10k_tags_continuation . <<EOF
TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
KERNEL=="sda", SYMLINK+="found"
EOF
},
);