]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-rules.c
Merge pull request #11827 from keszybz/pkgconfig-variables
[thirdparty/systemd.git] / src / udev / udev-rules.c
1 /* SPDX-License-Identifier: GPL-2.0+ */
2
3 #include <ctype.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <fnmatch.h>
7 #include <limits.h>
8 #include <stdbool.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <time.h>
14 #include <unistd.h>
15
16 #include "alloc-util.h"
17 #include "conf-files.h"
18 #include "def.h"
19 #include "device-private.h"
20 #include "device-util.h"
21 #include "dirent-util.h"
22 #include "escape.h"
23 #include "fd-util.h"
24 #include "fileio.h"
25 #include "fs-util.h"
26 #include "glob-util.h"
27 #include "libudev-util.h"
28 #include "mkdir.h"
29 #include "parse-util.h"
30 #include "path-util.h"
31 #include "proc-cmdline.h"
32 #include "stat-util.h"
33 #include "stdio-util.h"
34 #include "strbuf.h"
35 #include "string-util.h"
36 #include "strv.h"
37 #include "strxcpyx.h"
38 #include "sysctl-util.h"
39 #include "udev-builtin.h"
40 #include "udev.h"
41 #include "user-util.h"
42 #include "util.h"
43
44 #define PREALLOC_TOKEN 2048
45 #define RULES_DIRS (const char* const*) CONF_PATHS_STRV("udev/rules.d")
46
47 struct uid_gid {
48 unsigned name_off;
49 union {
50 uid_t uid;
51 gid_t gid;
52 };
53 };
54
55 struct UdevRules {
56 usec_t dirs_ts_usec;
57 ResolveNameTiming resolve_name_timing;
58
59 /* every key in the rules file becomes a token */
60 struct token *tokens;
61 size_t token_cur;
62 size_t token_max;
63
64 /* all key strings are copied and de-duplicated in a single continuous string buffer */
65 struct strbuf *strbuf;
66
67 /* during rule parsing, uid/gid lookup results are cached */
68 struct uid_gid *uids;
69 size_t uids_cur;
70 size_t uids_max;
71 struct uid_gid *gids;
72 size_t gids_cur;
73 size_t gids_max;
74 };
75
76 static char *rules_str(UdevRules *rules, unsigned off) {
77 return rules->strbuf->buf + off;
78 }
79
80 static unsigned rules_add_string(UdevRules *rules, const char *s) {
81 return strbuf_add_string(rules->strbuf, s, strlen(s));
82 }
83
84 /* KEY=="", KEY!="", KEY+="", KEY-="", KEY="", KEY:="" */
85 enum operation_type {
86 OP_UNSET,
87
88 OP_MATCH,
89 OP_NOMATCH,
90 OP_MATCH_MAX,
91
92 OP_ADD,
93 OP_REMOVE,
94 OP_ASSIGN,
95 OP_ASSIGN_FINAL,
96 };
97
98 enum string_glob_type {
99 GL_UNSET,
100 GL_PLAIN, /* no special chars */
101 GL_GLOB, /* shell globs ?,*,[] */
102 GL_SPLIT, /* multi-value A|B */
103 GL_SPLIT_GLOB, /* multi-value with glob A*|B* */
104 GL_SOMETHING, /* commonly used "?*" */
105 };
106
107 enum string_subst_type {
108 SB_UNSET,
109 SB_NONE,
110 SB_FORMAT,
111 SB_SUBSYS,
112 };
113
114 /* tokens of a rule are sorted/handled in this order */
115 enum token_type {
116 TK_UNSET,
117 TK_RULE,
118
119 TK_M_ACTION, /* val */
120 TK_M_DEVPATH, /* val */
121 TK_M_KERNEL, /* val */
122 TK_M_DEVLINK, /* val */
123 TK_M_NAME, /* val */
124 TK_M_ENV, /* val, attr */
125 TK_M_TAG, /* val */
126 TK_M_SUBSYSTEM, /* val */
127 TK_M_DRIVER, /* val */
128 TK_M_WAITFOR, /* val */
129 TK_M_ATTR, /* val, attr */
130 TK_M_SYSCTL, /* val, attr */
131
132 TK_M_PARENTS_MIN,
133 TK_M_KERNELS, /* val */
134 TK_M_SUBSYSTEMS, /* val */
135 TK_M_DRIVERS, /* val */
136 TK_M_ATTRS, /* val, attr */
137 TK_M_TAGS, /* val */
138 TK_M_PARENTS_MAX,
139
140 TK_M_TEST, /* val, mode_t */
141 TK_M_PROGRAM, /* val */
142 TK_M_IMPORT_FILE, /* val */
143 TK_M_IMPORT_PROG, /* val */
144 TK_M_IMPORT_BUILTIN, /* val */
145 TK_M_IMPORT_DB, /* val */
146 TK_M_IMPORT_CMDLINE, /* val */
147 TK_M_IMPORT_PARENT, /* val */
148 TK_M_RESULT, /* val */
149 TK_M_MAX,
150
151 TK_A_STRING_ESCAPE_NONE,
152 TK_A_STRING_ESCAPE_REPLACE,
153 TK_A_DB_PERSIST,
154 TK_A_INOTIFY_WATCH, /* int */
155 TK_A_DEVLINK_PRIO, /* int */
156 TK_A_OWNER, /* val */
157 TK_A_GROUP, /* val */
158 TK_A_MODE, /* val */
159 TK_A_OWNER_ID, /* uid_t */
160 TK_A_GROUP_ID, /* gid_t */
161 TK_A_MODE_ID, /* mode_t */
162 TK_A_TAG, /* val */
163 TK_A_STATIC_NODE, /* val */
164 TK_A_SECLABEL, /* val, attr */
165 TK_A_ENV, /* val, attr */
166 TK_A_NAME, /* val */
167 TK_A_DEVLINK, /* val */
168 TK_A_ATTR, /* val, attr */
169 TK_A_SYSCTL, /* val, attr */
170 TK_A_RUN_BUILTIN, /* val, bool */
171 TK_A_RUN_PROGRAM, /* val, bool */
172 TK_A_GOTO, /* size_t */
173
174 TK_END,
175 };
176
177 /* we try to pack stuff in a way that we take only 12 bytes per token */
178 struct token {
179 union {
180 unsigned char type; /* same in rule and key */
181 struct {
182 enum token_type type:8;
183 bool can_set_name:1;
184 bool has_static_node:1;
185 unsigned unused:6;
186 unsigned short token_count;
187 unsigned label_off;
188 unsigned short filename_off;
189 unsigned short filename_line;
190 } rule;
191 struct {
192 enum token_type type:8;
193 enum operation_type op:8;
194 enum string_glob_type glob:8;
195 enum string_subst_type subst:4;
196 enum string_subst_type attrsubst:4;
197 unsigned value_off;
198 union {
199 unsigned attr_off;
200 unsigned rule_goto;
201 mode_t mode;
202 uid_t uid;
203 gid_t gid;
204 int devlink_prio;
205 int watch;
206 enum udev_builtin_cmd builtin_cmd;
207 };
208 } key;
209 };
210 };
211
212 #define MAX_TK 64
213 struct rule_tmp {
214 UdevRules *rules;
215 struct token rule;
216 struct token token[MAX_TK];
217 size_t token_cur;
218 };
219
220 #if ENABLE_DEBUG_UDEV
221 static const char *operation_str(enum operation_type type) {
222 static const char *operation_strs[] = {
223 [OP_UNSET] = "UNSET",
224 [OP_MATCH] = "match",
225 [OP_NOMATCH] = "nomatch",
226 [OP_MATCH_MAX] = "MATCH_MAX",
227
228 [OP_ADD] = "add",
229 [OP_REMOVE] = "remove",
230 [OP_ASSIGN] = "assign",
231 [OP_ASSIGN_FINAL] = "assign-final",
232 };
233
234 return operation_strs[type];
235 }
236
237 static const char *string_glob_str(enum string_glob_type type) {
238 static const char *string_glob_strs[] = {
239 [GL_UNSET] = "UNSET",
240 [GL_PLAIN] = "plain",
241 [GL_GLOB] = "glob",
242 [GL_SPLIT] = "split",
243 [GL_SPLIT_GLOB] = "split-glob",
244 [GL_SOMETHING] = "split-glob",
245 };
246
247 return string_glob_strs[type];
248 }
249
250 static const char *token_str(enum token_type type) {
251 static const char *token_strs[] = {
252 [TK_UNSET] = "UNSET",
253 [TK_RULE] = "RULE",
254
255 [TK_M_ACTION] = "M ACTION",
256 [TK_M_DEVPATH] = "M DEVPATH",
257 [TK_M_KERNEL] = "M KERNEL",
258 [TK_M_DEVLINK] = "M DEVLINK",
259 [TK_M_NAME] = "M NAME",
260 [TK_M_ENV] = "M ENV",
261 [TK_M_TAG] = "M TAG",
262 [TK_M_SUBSYSTEM] = "M SUBSYSTEM",
263 [TK_M_DRIVER] = "M DRIVER",
264 [TK_M_WAITFOR] = "M WAITFOR",
265 [TK_M_ATTR] = "M ATTR",
266 [TK_M_SYSCTL] = "M SYSCTL",
267
268 [TK_M_PARENTS_MIN] = "M PARENTS_MIN",
269 [TK_M_KERNELS] = "M KERNELS",
270 [TK_M_SUBSYSTEMS] = "M SUBSYSTEMS",
271 [TK_M_DRIVERS] = "M DRIVERS",
272 [TK_M_ATTRS] = "M ATTRS",
273 [TK_M_TAGS] = "M TAGS",
274 [TK_M_PARENTS_MAX] = "M PARENTS_MAX",
275
276 [TK_M_TEST] = "M TEST",
277 [TK_M_PROGRAM] = "M PROGRAM",
278 [TK_M_IMPORT_FILE] = "M IMPORT_FILE",
279 [TK_M_IMPORT_PROG] = "M IMPORT_PROG",
280 [TK_M_IMPORT_BUILTIN] = "M IMPORT_BUILTIN",
281 [TK_M_IMPORT_DB] = "M IMPORT_DB",
282 [TK_M_IMPORT_CMDLINE] = "M IMPORT_CMDLINE",
283 [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT",
284 [TK_M_RESULT] = "M RESULT",
285 [TK_M_MAX] = "M MAX",
286
287 [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE",
288 [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE",
289 [TK_A_DB_PERSIST] = "A DB_PERSIST",
290 [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH",
291 [TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO",
292 [TK_A_OWNER] = "A OWNER",
293 [TK_A_GROUP] = "A GROUP",
294 [TK_A_MODE] = "A MODE",
295 [TK_A_OWNER_ID] = "A OWNER_ID",
296 [TK_A_GROUP_ID] = "A GROUP_ID",
297 [TK_A_STATIC_NODE] = "A STATIC_NODE",
298 [TK_A_SECLABEL] = "A SECLABEL",
299 [TK_A_MODE_ID] = "A MODE_ID",
300 [TK_A_ENV] = "A ENV",
301 [TK_A_TAG] = "A ENV",
302 [TK_A_NAME] = "A NAME",
303 [TK_A_DEVLINK] = "A DEVLINK",
304 [TK_A_ATTR] = "A ATTR",
305 [TK_A_SYSCTL] = "A SYSCTL",
306 [TK_A_RUN_BUILTIN] = "A RUN_BUILTIN",
307 [TK_A_RUN_PROGRAM] = "A RUN_PROGRAM",
308 [TK_A_GOTO] = "A GOTO",
309
310 [TK_END] = "END",
311 };
312
313 return token_strs[type];
314 }
315
316 static void dump_token(UdevRules *rules, struct token *token) {
317 enum token_type type = token->type;
318 enum operation_type op = token->key.op;
319 enum string_glob_type glob = token->key.glob;
320 const char *value = rules_str(rules, token->key.value_off);
321 const char *attr = &rules->strbuf->buf[token->key.attr_off];
322
323 switch (type) {
324 case TK_RULE:
325 {
326 const char *tks_ptr = (char *)rules->tokens;
327 const char *tk_ptr = (char *)token;
328 unsigned idx = (tk_ptr - tks_ptr) / sizeof(struct token);
329
330 log_debug("* RULE %s:%u, token: %u, count: %u, label: '%s'",
331 &rules->strbuf->buf[token->rule.filename_off], token->rule.filename_line,
332 idx, token->rule.token_count,
333 &rules->strbuf->buf[token->rule.label_off]);
334 break;
335 }
336 case TK_M_ACTION:
337 case TK_M_DEVPATH:
338 case TK_M_KERNEL:
339 case TK_M_SUBSYSTEM:
340 case TK_M_DRIVER:
341 case TK_M_WAITFOR:
342 case TK_M_DEVLINK:
343 case TK_M_NAME:
344 case TK_M_KERNELS:
345 case TK_M_SUBSYSTEMS:
346 case TK_M_DRIVERS:
347 case TK_M_TAGS:
348 case TK_M_PROGRAM:
349 case TK_M_IMPORT_FILE:
350 case TK_M_IMPORT_PROG:
351 case TK_M_IMPORT_DB:
352 case TK_M_IMPORT_CMDLINE:
353 case TK_M_IMPORT_PARENT:
354 case TK_M_RESULT:
355 case TK_A_NAME:
356 case TK_A_DEVLINK:
357 case TK_A_OWNER:
358 case TK_A_GROUP:
359 case TK_A_MODE:
360 case TK_A_RUN_BUILTIN:
361 case TK_A_RUN_PROGRAM:
362 log_debug("%s %s '%s'(%s)",
363 token_str(type), operation_str(op), value, string_glob_str(glob));
364 break;
365 case TK_M_IMPORT_BUILTIN:
366 log_debug("%s %i '%s'", token_str(type), token->key.builtin_cmd, value);
367 break;
368 case TK_M_ATTR:
369 case TK_M_SYSCTL:
370 case TK_M_ATTRS:
371 case TK_M_ENV:
372 case TK_A_ATTR:
373 case TK_A_SYSCTL:
374 case TK_A_ENV:
375 log_debug("%s %s '%s' '%s'(%s)",
376 token_str(type), operation_str(op), attr, value, string_glob_str(glob));
377 break;
378 case TK_M_TAG:
379 case TK_A_TAG:
380 log_debug("%s %s '%s'", token_str(type), operation_str(op), value);
381 break;
382 case TK_A_STRING_ESCAPE_NONE:
383 case TK_A_STRING_ESCAPE_REPLACE:
384 case TK_A_DB_PERSIST:
385 log_debug("%s", token_str(type));
386 break;
387 case TK_M_TEST:
388 log_debug("%s %s '%s'(%s) %#o",
389 token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
390 break;
391 case TK_A_INOTIFY_WATCH:
392 log_debug("%s %u", token_str(type), token->key.watch);
393 break;
394 case TK_A_DEVLINK_PRIO:
395 log_debug("%s %u", token_str(type), token->key.devlink_prio);
396 break;
397 case TK_A_OWNER_ID:
398 log_debug("%s %s %u", token_str(type), operation_str(op), token->key.uid);
399 break;
400 case TK_A_GROUP_ID:
401 log_debug("%s %s %u", token_str(type), operation_str(op), token->key.gid);
402 break;
403 case TK_A_MODE_ID:
404 log_debug("%s %s %#o", token_str(type), operation_str(op), token->key.mode);
405 break;
406 case TK_A_STATIC_NODE:
407 log_debug("%s '%s'", token_str(type), value);
408 break;
409 case TK_A_SECLABEL:
410 log_debug("%s %s '%s' '%s'", token_str(type), operation_str(op), attr, value);
411 break;
412 case TK_A_GOTO:
413 log_debug("%s '%s' %u", token_str(type), value, token->key.rule_goto);
414 break;
415 case TK_END:
416 log_debug("* %s", token_str(type));
417 break;
418 case TK_M_PARENTS_MIN:
419 case TK_M_PARENTS_MAX:
420 case TK_M_MAX:
421 case TK_UNSET:
422 log_debug("Unknown token type %u", type);
423 break;
424 }
425 }
426
427 static void dump_rules(UdevRules *rules) {
428 size_t i;
429
430 log_debug("Dumping %zu (%zu bytes) tokens, %zu (%zu bytes) strings",
431 rules->token_cur,
432 rules->token_cur * sizeof(struct token),
433 rules->strbuf->nodes_count,
434 rules->strbuf->len);
435 for (i = 0; i < rules->token_cur; i++)
436 dump_token(rules, &rules->tokens[i]);
437 }
438 #else
439 static void dump_token(UdevRules *rules, struct token *token) {}
440 static void dump_rules(UdevRules *rules) {}
441 #endif /* ENABLE_DEBUG_UDEV */
442
443 static int add_token(UdevRules *rules, struct token *token) {
444 /* grow buffer if needed */
445 if (!GREEDY_REALLOC(rules->tokens, rules->token_max, rules->token_cur + 1))
446 return -ENOMEM;
447
448 memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
449 rules->token_cur++;
450 return 0;
451 }
452
453 static void log_unknown_owner(sd_device *dev, int error, const char *entity, const char *owner) {
454 if (IN_SET(abs(error), ENOENT, ESRCH))
455 log_device_error(dev, "Specified %s '%s' unknown", entity, owner);
456 else
457 log_device_error_errno(dev, error, "Failed to resolve %s '%s': %m", entity, owner);
458 }
459
460 static uid_t add_uid(UdevRules *rules, const char *owner) {
461 uid_t uid = 0;
462 unsigned off;
463 size_t i;
464 int r;
465
466 /* lookup, if we know it already */
467 for (i = 0; i < rules->uids_cur; i++) {
468 off = rules->uids[i].name_off;
469 if (streq(rules_str(rules, off), owner))
470 return rules->uids[i].uid;
471 }
472 r = get_user_creds(&owner, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
473 if (r < 0)
474 log_unknown_owner(NULL, r, "user", owner);
475
476 /* grow buffer if needed */
477 if (!GREEDY_REALLOC(rules->uids, rules->uids_max, rules->uids_cur + 1))
478 return -ENOMEM;
479
480 rules->uids[rules->uids_cur].uid = uid;
481 off = rules_add_string(rules, owner);
482 if (off <= 0)
483 return uid;
484 rules->uids[rules->uids_cur].name_off = off;
485 rules->uids_cur++;
486 return uid;
487 }
488
489 static gid_t add_gid(UdevRules *rules, const char *group) {
490 gid_t gid = 0;
491 unsigned off;
492 size_t i;
493 int r;
494
495 /* lookup, if we know it already */
496 for (i = 0; i < rules->gids_cur; i++) {
497 off = rules->gids[i].name_off;
498 if (streq(rules_str(rules, off), group))
499 return rules->gids[i].gid;
500 }
501 r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
502 if (r < 0)
503 log_unknown_owner(NULL, r, "group", group);
504
505 /* grow buffer if needed */
506 if (!GREEDY_REALLOC(rules->gids, rules->gids_max, rules->gids_cur + 1))
507 return -ENOMEM;
508
509 rules->gids[rules->gids_cur].gid = gid;
510 off = rules_add_string(rules, group);
511 if (off <= 0)
512 return gid;
513 rules->gids[rules->gids_cur].name_off = off;
514 rules->gids_cur++;
515 return gid;
516 }
517
518 static int import_property_from_string(sd_device *dev, char *line) {
519 char *key;
520 char *val;
521 size_t len;
522
523 /* find key */
524 key = line;
525 while (isspace(key[0]))
526 key++;
527
528 /* comment or empty line */
529 if (IN_SET(key[0], '#', '\0'))
530 return 0;
531
532 /* split key/value */
533 val = strchr(key, '=');
534 if (!val)
535 return -EINVAL;
536 val[0] = '\0';
537 val++;
538
539 /* find value */
540 while (isspace(val[0]))
541 val++;
542
543 /* terminate key */
544 len = strlen(key);
545 if (len == 0)
546 return -EINVAL;
547 while (isspace(key[len-1]))
548 len--;
549 key[len] = '\0';
550
551 /* terminate value */
552 len = strlen(val);
553 if (len == 0)
554 return -EINVAL;
555 while (isspace(val[len-1]))
556 len--;
557 val[len] = '\0';
558
559 if (len == 0)
560 return -EINVAL;
561
562 /* unquote */
563 if (IN_SET(val[0], '"', '\'')) {
564 if (len == 1 || val[len-1] != val[0])
565 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
566 "Inconsistent quoting: '%s', skip",
567 line);
568 val[len-1] = '\0';
569 val++;
570 }
571
572 return device_add_property(dev, key, val);
573 }
574
575 static int import_file_into_properties(sd_device *dev, const char *filename) {
576 _cleanup_fclose_ FILE *f = NULL;
577 int r;
578
579 f = fopen(filename, "re");
580 if (!f)
581 return -errno;
582
583 for (;;) {
584 _cleanup_free_ char *line = NULL;
585
586 r = read_line(f, LONG_LINE_MAX, &line);
587 if (r < 0)
588 return r;
589 if (r == 0)
590 break;
591
592 (void) import_property_from_string(dev, line);
593 }
594
595 return 0;
596 }
597
598 static int import_program_into_properties(UdevEvent *event,
599 usec_t timeout_usec,
600 const char *program) {
601 char result[UTIL_LINE_SIZE];
602 char *line;
603 int r;
604
605 r = udev_event_spawn(event, timeout_usec, false, program, result, sizeof result);
606 if (r < 0)
607 return r;
608 if (r > 0)
609 return -EIO;
610
611 line = result;
612 while (line) {
613 char *pos;
614
615 pos = strchr(line, '\n');
616 if (pos) {
617 pos[0] = '\0';
618 pos = &pos[1];
619 }
620 (void) import_property_from_string(event->dev, line);
621 line = pos;
622 }
623 return 0;
624 }
625
626 static int import_parent_into_properties(sd_device *dev, const char *filter) {
627 const char *key, *val;
628 sd_device *parent;
629 int r;
630
631 assert(dev);
632 assert(filter);
633
634 r = sd_device_get_parent(dev, &parent);
635 if (r < 0)
636 return r;
637
638 FOREACH_DEVICE_PROPERTY(parent, key, val)
639 if (fnmatch(filter, key, 0) == 0)
640 device_add_property(dev, key, val);
641 return 0;
642 }
643
644 static void attr_subst_subdir(char *attr, size_t len) {
645 const char *pos, *tail, *path;
646 _cleanup_closedir_ DIR *dir = NULL;
647 struct dirent *dent;
648
649 pos = strstr(attr, "/*/");
650 if (!pos)
651 return;
652
653 tail = pos + 2;
654 path = strndupa(attr, pos - attr + 1); /* include slash at end */
655 dir = opendir(path);
656 if (!dir)
657 return;
658
659 FOREACH_DIRENT_ALL(dent, dir, break)
660 if (dent->d_name[0] != '.') {
661 char n[strlen(dent->d_name) + strlen(tail) + 1];
662
663 strscpyl(n, sizeof n, dent->d_name, tail, NULL);
664 if (faccessat(dirfd(dir), n, F_OK, 0) == 0) {
665 strscpyl(attr, len, path, n, NULL);
666 break;
667 }
668 }
669 }
670
671 static int get_key(char **line, char **key, enum operation_type *op, char **value) {
672 char *linepos;
673 char *temp;
674 size_t i, j;
675
676 linepos = *line;
677 if (!linepos || linepos[0] == '\0')
678 return -EINVAL;
679
680 /* skip whitespace */
681 while (isspace(linepos[0]) || linepos[0] == ',')
682 linepos++;
683
684 /* get the key */
685 if (linepos[0] == '\0')
686 return -EINVAL;
687 *key = linepos;
688
689 for (;;) {
690 linepos++;
691 if (linepos[0] == '\0')
692 return -EINVAL;
693 if (isspace(linepos[0]))
694 break;
695 if (linepos[0] == '=')
696 break;
697 if (IN_SET(linepos[0], '+', '-', '!', ':'))
698 if (linepos[1] == '=')
699 break;
700 }
701
702 /* remember end of key */
703 temp = linepos;
704
705 /* skip whitespace after key */
706 while (isspace(linepos[0]))
707 linepos++;
708 if (linepos[0] == '\0')
709 return -EINVAL;
710
711 /* get operation type */
712 if (linepos[0] == '=' && linepos[1] == '=') {
713 *op = OP_MATCH;
714 linepos += 2;
715 } else if (linepos[0] == '!' && linepos[1] == '=') {
716 *op = OP_NOMATCH;
717 linepos += 2;
718 } else if (linepos[0] == '+' && linepos[1] == '=') {
719 *op = OP_ADD;
720 linepos += 2;
721 } else if (linepos[0] == '-' && linepos[1] == '=') {
722 *op = OP_REMOVE;
723 linepos += 2;
724 } else if (linepos[0] == '=') {
725 *op = OP_ASSIGN;
726 linepos++;
727 } else if (linepos[0] == ':' && linepos[1] == '=') {
728 *op = OP_ASSIGN_FINAL;
729 linepos += 2;
730 } else
731 return -EINVAL;
732
733 /* terminate key */
734 temp[0] = '\0';
735
736 /* skip whitespace after operator */
737 while (isspace(linepos[0]))
738 linepos++;
739 if (linepos[0] == '\0')
740 return -EINVAL;
741
742 /* get the value */
743 if (linepos[0] == '"')
744 linepos++;
745 else
746 return -EINVAL;
747 *value = linepos;
748
749 /* terminate */
750 for (i = 0, j = 0; ; i++, j++) {
751
752 if (linepos[i] == '"')
753 break;
754
755 if (linepos[i] == '\0')
756 return -EINVAL;
757
758 /* double quotes can be escaped */
759 if (linepos[i] == '\\')
760 if (linepos[i+1] == '"')
761 i++;
762
763 linepos[j] = linepos[i];
764 }
765 linepos[j] = '\0';
766
767 /* move line to next key */
768 *line = linepos + i + 1;
769 return 0;
770 }
771
772 /* extract possible KEY{attr} */
773 static const char *get_key_attribute(char *str) {
774 char *pos;
775 char *attr;
776
777 attr = strchr(str, '{');
778 if (attr) {
779 attr++;
780 pos = strchr(attr, '}');
781 if (!pos) {
782 log_error("Missing closing brace for format");
783 return NULL;
784 }
785 pos[0] = '\0';
786 return attr;
787 }
788 return NULL;
789 }
790
791 static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
792 enum operation_type op,
793 const char *value, const void *data) {
794 struct token *token = rule_tmp->token + rule_tmp->token_cur;
795 const char *attr = NULL;
796
797 if (rule_tmp->token_cur >= ELEMENTSOF(rule_tmp->token))
798 return -E2BIG;
799
800 memzero(token, sizeof(struct token));
801
802 switch (type) {
803 case TK_M_ACTION:
804 case TK_M_DEVPATH:
805 case TK_M_KERNEL:
806 case TK_M_SUBSYSTEM:
807 case TK_M_DRIVER:
808 case TK_M_WAITFOR:
809 case TK_M_DEVLINK:
810 case TK_M_NAME:
811 case TK_M_KERNELS:
812 case TK_M_SUBSYSTEMS:
813 case TK_M_DRIVERS:
814 case TK_M_TAGS:
815 case TK_M_PROGRAM:
816 case TK_M_IMPORT_FILE:
817 case TK_M_IMPORT_PROG:
818 case TK_M_IMPORT_DB:
819 case TK_M_IMPORT_CMDLINE:
820 case TK_M_IMPORT_PARENT:
821 case TK_M_RESULT:
822 case TK_A_OWNER:
823 case TK_A_GROUP:
824 case TK_A_MODE:
825 case TK_A_DEVLINK:
826 case TK_A_NAME:
827 case TK_A_GOTO:
828 case TK_M_TAG:
829 case TK_A_TAG:
830 case TK_A_STATIC_NODE:
831 token->key.value_off = rules_add_string(rule_tmp->rules, value);
832 break;
833 case TK_M_IMPORT_BUILTIN:
834 token->key.value_off = rules_add_string(rule_tmp->rules, value);
835 token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
836 break;
837 case TK_M_ENV:
838 case TK_M_ATTR:
839 case TK_M_SYSCTL:
840 case TK_M_ATTRS:
841 case TK_A_ATTR:
842 case TK_A_SYSCTL:
843 case TK_A_ENV:
844 case TK_A_SECLABEL:
845 attr = data;
846 token->key.value_off = rules_add_string(rule_tmp->rules, value);
847 token->key.attr_off = rules_add_string(rule_tmp->rules, attr);
848 break;
849 case TK_M_TEST:
850 token->key.value_off = rules_add_string(rule_tmp->rules, value);
851 if (data)
852 token->key.mode = *(mode_t *)data;
853 break;
854 case TK_A_STRING_ESCAPE_NONE:
855 case TK_A_STRING_ESCAPE_REPLACE:
856 case TK_A_DB_PERSIST:
857 break;
858 case TK_A_RUN_BUILTIN:
859 case TK_A_RUN_PROGRAM:
860 token->key.builtin_cmd = *(enum udev_builtin_cmd *)data;
861 token->key.value_off = rules_add_string(rule_tmp->rules, value);
862 break;
863 case TK_A_INOTIFY_WATCH:
864 case TK_A_DEVLINK_PRIO:
865 token->key.devlink_prio = *(int *)data;
866 break;
867 case TK_A_OWNER_ID:
868 token->key.uid = *(uid_t *)data;
869 break;
870 case TK_A_GROUP_ID:
871 token->key.gid = *(gid_t *)data;
872 break;
873 case TK_A_MODE_ID:
874 token->key.mode = *(mode_t *)data;
875 break;
876 case TK_RULE:
877 case TK_M_PARENTS_MIN:
878 case TK_M_PARENTS_MAX:
879 case TK_M_MAX:
880 case TK_END:
881 case TK_UNSET:
882 assert_not_reached("wrong type");
883 }
884
885 if (value && type < TK_M_MAX) {
886 /* check if we need to split or call fnmatch() while matching rules */
887 enum string_glob_type glob;
888 bool has_split, has_glob;
889
890 has_split = strchr(value, '|');
891 has_glob = string_is_glob(value);
892 if (has_split && has_glob)
893 glob = GL_SPLIT_GLOB;
894 else if (has_split)
895 glob = GL_SPLIT;
896 else if (has_glob) {
897 if (streq(value, "?*"))
898 glob = GL_SOMETHING;
899 else
900 glob = GL_GLOB;
901 } else
902 glob = GL_PLAIN;
903
904 token->key.glob = glob;
905 }
906
907 if (value && type > TK_M_MAX) {
908 /* check if assigned value has substitution chars */
909 if (value[0] == '[')
910 token->key.subst = SB_SUBSYS;
911 else if (strchr(value, '%') || strchr(value, '$'))
912 token->key.subst = SB_FORMAT;
913 else
914 token->key.subst = SB_NONE;
915 }
916
917 if (attr) {
918 /* check if property/attribute name has substitution chars */
919 if (attr[0] == '[')
920 token->key.attrsubst = SB_SUBSYS;
921 else if (strchr(attr, '%') || strchr(attr, '$'))
922 token->key.attrsubst = SB_FORMAT;
923 else
924 token->key.attrsubst = SB_NONE;
925 }
926
927 token->key.type = type;
928 token->key.op = op;
929 rule_tmp->token_cur++;
930
931 return 0;
932 }
933
934 static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) {
935 size_t i;
936 size_t start = 0;
937 size_t end = rule_tmp->token_cur;
938 int r;
939
940 for (i = 0; i < rule_tmp->token_cur; i++) {
941 enum token_type next_val = TK_UNSET;
942 size_t next_idx = 0;
943 size_t j;
944
945 /* find smallest value */
946 for (j = start; j < end; j++) {
947 if (rule_tmp->token[j].type == TK_UNSET)
948 continue;
949 if (next_val == TK_UNSET || rule_tmp->token[j].type < next_val) {
950 next_val = rule_tmp->token[j].type;
951 next_idx = j;
952 }
953 }
954
955 /* add token and mark done */
956 r = add_token(rules, &rule_tmp->token[next_idx]);
957 if (r < 0)
958 return r;
959 rule_tmp->token[next_idx].type = TK_UNSET;
960
961 /* shrink range */
962 if (next_idx == start)
963 start++;
964 if (next_idx+1 == end)
965 end--;
966 }
967 return 0;
968 }
969
970 #define LOG_RULE_FULL(level, fmt, ...) log_full(level, "%s:%u: " fmt, filename, lineno, ##__VA_ARGS__)
971 #define LOG_RULE_ERROR(fmt, ...) LOG_RULE_FULL(LOG_ERR, fmt, ##__VA_ARGS__)
972 #define LOG_RULE_WARNING(fmt, ...) LOG_RULE_FULL(LOG_WARNING, fmt, ##__VA_ARGS__)
973 #define LOG_RULE_DEBUG(fmt, ...) LOG_RULE_FULL(LOG_DEBUG, fmt, ##__VA_ARGS__)
974 #define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; }
975 #define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %zu items", rule_tmp.token_cur);
976
977 static void add_rule(UdevRules *rules, char *line,
978 const char *filename, unsigned filename_off, unsigned lineno) {
979 char *linepos;
980 const char *attr;
981 struct rule_tmp rule_tmp = {
982 .rules = rules,
983 .rule.type = TK_RULE,
984 };
985 int r;
986
987 /* the offset in the rule is limited to unsigned short */
988 if (filename_off < USHRT_MAX)
989 rule_tmp.rule.rule.filename_off = filename_off;
990 rule_tmp.rule.rule.filename_line = lineno;
991
992 linepos = line;
993 for (;;) {
994 char *key;
995 char *value;
996 enum operation_type op;
997
998 if (get_key(&linepos, &key, &op, &value) < 0) {
999 /* Avoid erroring on trailing whitespace. This is probably rare
1000 * so save the work for the error case instead of always trying
1001 * to strip the trailing whitespace with strstrip(). */
1002 while (isblank(*linepos))
1003 linepos++;
1004
1005 /* If we aren't at the end of the line, this is a parsing error.
1006 * Make a best effort to describe where the problem is. */
1007 if (!strchr(NEWLINE, *linepos)) {
1008 char buf[2] = {*linepos};
1009 _cleanup_free_ char *tmp;
1010
1011 tmp = cescape(buf);
1012 LOG_RULE_ERROR("Invalid key/value pair, starting at character %tu ('%s')", linepos - line + 1, tmp);
1013 if (*linepos == '#')
1014 LOG_RULE_ERROR("Hint: comments can only start at beginning of line");
1015 }
1016 break;
1017 }
1018
1019 if (streq(key, "ACTION")) {
1020 if (op > OP_MATCH_MAX)
1021 LOG_AND_RETURN("Invalid %s operation", key);
1022
1023 if (rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL) < 0)
1024 LOG_AND_RETURN_ADD_KEY;
1025
1026 } else if (streq(key, "DEVPATH")) {
1027 if (op > OP_MATCH_MAX)
1028 LOG_AND_RETURN("Invalid %s operation", key);
1029
1030 if (rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL) < 0)
1031 LOG_AND_RETURN_ADD_KEY;
1032
1033 } else if (streq(key, "KERNEL")) {
1034 if (op > OP_MATCH_MAX)
1035 LOG_AND_RETURN("Invalid %s operation", key);
1036
1037 if (rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL) < 0)
1038 LOG_AND_RETURN_ADD_KEY;
1039
1040 } else if (streq(key, "SUBSYSTEM")) {
1041 if (op > OP_MATCH_MAX)
1042 LOG_AND_RETURN("Invalid %s operation", key);
1043
1044 /* bus, class, subsystem events should all be the same */
1045 if (STR_IN_SET(value, "subsystem", "bus", "class")) {
1046 if (!streq(value, "subsystem"))
1047 LOG_RULE_WARNING("'%s' must be specified as 'subsystem'; please fix", value);
1048
1049 r = rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL);
1050 } else
1051 r = rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL);
1052 if (r < 0)
1053 LOG_AND_RETURN_ADD_KEY;
1054
1055 } else if (streq(key, "DRIVER")) {
1056 if (op > OP_MATCH_MAX)
1057 LOG_AND_RETURN("Invalid %s operation", key);
1058
1059 if (rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL) < 0)
1060 LOG_AND_RETURN_ADD_KEY;
1061
1062 } else if (startswith(key, "ATTR{")) {
1063 attr = get_key_attribute(key + STRLEN("ATTR"));
1064 if (!attr)
1065 LOG_AND_RETURN("Failed to parse %s attribute", "ATTR");
1066
1067 if (op == OP_REMOVE)
1068 LOG_AND_RETURN("Invalid %s operation", "ATTR");
1069
1070 if (op < OP_MATCH_MAX)
1071 r = rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
1072 else
1073 r = rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
1074 if (r < 0)
1075 LOG_AND_RETURN_ADD_KEY;
1076
1077 } else if (startswith(key, "SYSCTL{")) {
1078 attr = get_key_attribute(key + STRLEN("SYSCTL"));
1079 if (!attr)
1080 LOG_AND_RETURN("Failed to parse %s attribute", "ATTR");
1081
1082 if (op == OP_REMOVE)
1083 LOG_AND_RETURN("Invalid %s operation", "ATTR");
1084
1085 if (op < OP_MATCH_MAX)
1086 r = rule_add_key(&rule_tmp, TK_M_SYSCTL, op, value, attr);
1087 else
1088 r = rule_add_key(&rule_tmp, TK_A_SYSCTL, op, value, attr);
1089 if (r < 0)
1090 LOG_AND_RETURN_ADD_KEY;
1091
1092 } else if (startswith(key, "SECLABEL{")) {
1093 attr = get_key_attribute(key + STRLEN("SECLABEL"));
1094 if (!attr)
1095 LOG_AND_RETURN("Failed to parse %s attribute", "SECLABEL");
1096
1097 if (op == OP_REMOVE)
1098 LOG_AND_RETURN("Invalid %s operation", "SECLABEL");
1099
1100 if (rule_add_key(&rule_tmp, TK_A_SECLABEL, op, value, attr) < 0)
1101 LOG_AND_RETURN_ADD_KEY;
1102
1103 } else if (streq(key, "KERNELS")) {
1104 if (op > OP_MATCH_MAX)
1105 LOG_AND_RETURN("Invalid %s operation", key);
1106
1107 if (rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL) < 0)
1108 LOG_AND_RETURN_ADD_KEY;
1109
1110 } else if (streq(key, "SUBSYSTEMS")) {
1111 if (op > OP_MATCH_MAX)
1112 LOG_AND_RETURN("Invalid %s operation", key);
1113
1114 if (rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL) < 0)
1115 LOG_AND_RETURN_ADD_KEY;
1116
1117 } else if (streq(key, "DRIVERS")) {
1118 if (op > OP_MATCH_MAX)
1119 LOG_AND_RETURN("Invalid %s operation", key);
1120
1121 if (rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL) < 0)
1122 LOG_AND_RETURN_ADD_KEY;
1123
1124 } else if (startswith(key, "ATTRS{")) {
1125 if (op > OP_MATCH_MAX)
1126 LOG_AND_RETURN("Invalid %s operation", "ATTRS");
1127
1128 attr = get_key_attribute(key + STRLEN("ATTRS"));
1129 if (!attr)
1130 LOG_AND_RETURN("Failed to parse %s attribute", "ATTRS");
1131
1132 if (startswith(attr, "device/"))
1133 LOG_RULE_WARNING("'device' link may not be available in future kernels; please fix");
1134 if (strstr(attr, "../"))
1135 LOG_RULE_WARNING("Direct reference to parent sysfs directory, may break in future kernels; please fix");
1136 if (rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr) < 0)
1137 LOG_AND_RETURN_ADD_KEY;
1138
1139 } else if (streq(key, "TAGS")) {
1140 if (op > OP_MATCH_MAX)
1141 LOG_AND_RETURN("Invalid %s operation", key);
1142
1143 if (rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL) < 0)
1144 LOG_AND_RETURN_ADD_KEY;
1145
1146 } else if (startswith(key, "ENV{")) {
1147 attr = get_key_attribute(key + STRLEN("ENV"));
1148 if (!attr)
1149 LOG_AND_RETURN("Failed to parse %s attribute", "ENV");
1150
1151 if (op == OP_REMOVE)
1152 LOG_AND_RETURN("Invalid %s operation", "ENV");
1153
1154 if (op < OP_MATCH_MAX)
1155 r = rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr);
1156 else {
1157 if (STR_IN_SET(attr,
1158 "ACTION",
1159 "SUBSYSTEM",
1160 "DEVTYPE",
1161 "MAJOR",
1162 "MINOR",
1163 "DRIVER",
1164 "IFINDEX",
1165 "DEVNAME",
1166 "DEVLINKS",
1167 "DEVPATH",
1168 "TAGS"))
1169 LOG_AND_RETURN("Invalid ENV attribute, '%s' cannot be set", attr);
1170
1171 r = rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr);
1172 }
1173 if (r < 0)
1174 LOG_AND_RETURN_ADD_KEY;
1175
1176 } else if (streq(key, "TAG")) {
1177 if (op < OP_MATCH_MAX)
1178 r = rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
1179 else
1180 r = rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL);
1181 if (r < 0)
1182 LOG_AND_RETURN_ADD_KEY;
1183
1184 } else if (streq(key, "PROGRAM")) {
1185 if (op == OP_REMOVE)
1186 LOG_AND_RETURN("Invalid %s operation", key);
1187
1188 if (rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL) < 0)
1189 LOG_AND_RETURN_ADD_KEY;
1190
1191 } else if (streq(key, "RESULT")) {
1192 if (op > OP_MATCH_MAX)
1193 LOG_AND_RETURN("Invalid %s operation", key);
1194
1195 if (rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL) < 0)
1196 LOG_AND_RETURN_ADD_KEY;
1197
1198 } else if (startswith(key, "IMPORT")) {
1199 attr = get_key_attribute(key + STRLEN("IMPORT"));
1200 if (!attr) {
1201 LOG_RULE_WARNING("Ignoring IMPORT{} with missing type");
1202 continue;
1203 }
1204 if (op == OP_REMOVE)
1205 LOG_AND_RETURN("Invalid %s operation", "IMPORT");
1206
1207 if (streq(attr, "program")) {
1208 /* find known built-in command */
1209 if (value[0] != '/') {
1210 const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
1211
1212 if (cmd >= 0) {
1213 LOG_RULE_DEBUG("IMPORT found builtin '%s', replacing", value);
1214 if (rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd) < 0)
1215 LOG_AND_RETURN_ADD_KEY;
1216 continue;
1217 }
1218 }
1219 r = rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
1220 } else if (streq(attr, "builtin")) {
1221 const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
1222
1223 if (cmd < 0) {
1224 LOG_RULE_WARNING("IMPORT{builtin} '%s' unknown, ignoring", value);
1225 continue;
1226 } else
1227 r = rule_add_key(&rule_tmp, TK_M_IMPORT_BUILTIN, op, value, &cmd);
1228 } else if (streq(attr, "file"))
1229 r = rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
1230 else if (streq(attr, "db"))
1231 r = rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
1232 else if (streq(attr, "cmdline"))
1233 r = rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
1234 else if (streq(attr, "parent"))
1235 r = rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
1236 else {
1237 LOG_RULE_ERROR("Ignoring unknown %s{} type '%s'", "IMPORT", attr);
1238 continue;
1239 }
1240 if (r < 0)
1241 LOG_AND_RETURN_ADD_KEY;
1242
1243 } else if (startswith(key, "TEST")) {
1244 mode_t mode = 0;
1245
1246 if (op > OP_MATCH_MAX)
1247 LOG_AND_RETURN("Invalid %s operation", "TEST");
1248
1249 attr = get_key_attribute(key + STRLEN("TEST"));
1250 if (attr) {
1251 mode = strtol(attr, NULL, 8);
1252 r = rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode);
1253 } else
1254 r = rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL);
1255 if (r < 0)
1256 LOG_AND_RETURN_ADD_KEY;
1257
1258 } else if (startswith(key, "RUN")) {
1259 attr = get_key_attribute(key + STRLEN("RUN"));
1260 if (!attr)
1261 attr = "program";
1262 if (op == OP_REMOVE)
1263 LOG_AND_RETURN("Invalid %s operation", "RUN");
1264
1265 if (streq(attr, "builtin")) {
1266 const enum udev_builtin_cmd cmd = udev_builtin_lookup(value);
1267
1268 if (cmd < 0) {
1269 LOG_RULE_ERROR("RUN{builtin}: '%s' unknown, ignoring", value);
1270 continue;
1271 } else
1272 r = rule_add_key(&rule_tmp, TK_A_RUN_BUILTIN, op, value, &cmd);
1273 } else if (streq(attr, "program")) {
1274 const enum udev_builtin_cmd cmd = _UDEV_BUILTIN_MAX;
1275
1276 r = rule_add_key(&rule_tmp, TK_A_RUN_PROGRAM, op, value, &cmd);
1277 } else {
1278 LOG_RULE_ERROR("Ignoring unknown %s{} type '%s'", "RUN", attr);
1279 continue;
1280 }
1281 if (r < 0)
1282 LOG_AND_RETURN_ADD_KEY;
1283
1284 } else if (streq(key, "LABEL")) {
1285 if (op == OP_REMOVE)
1286 LOG_AND_RETURN("Invalid %s operation", key);
1287
1288 rule_tmp.rule.rule.label_off = rules_add_string(rules, value);
1289
1290 } else if (streq(key, "GOTO")) {
1291 if (op == OP_REMOVE)
1292 LOG_AND_RETURN("Invalid %s operation", key);
1293
1294 if (rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL) < 0)
1295 LOG_AND_RETURN_ADD_KEY;
1296
1297 } else if (startswith(key, "NAME")) {
1298 if (op == OP_REMOVE)
1299 LOG_AND_RETURN("Invalid %s operation", key);
1300
1301 if (op < OP_MATCH_MAX)
1302 r = rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
1303 else {
1304 if (streq(value, "%k")) {
1305 LOG_RULE_WARNING("NAME=\"%%k\" is ignored, because it breaks kernel supplied names; please remove");
1306 continue;
1307 }
1308 if (isempty(value)) {
1309 LOG_RULE_DEBUG("NAME=\"\" is ignored, because udev will not delete any device nodes; please remove");
1310 continue;
1311 }
1312 r = rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL);
1313 }
1314 if (r < 0)
1315 LOG_AND_RETURN_ADD_KEY;
1316 rule_tmp.rule.rule.can_set_name = true;
1317
1318 } else if (streq(key, "SYMLINK")) {
1319 if (op == OP_REMOVE)
1320 LOG_AND_RETURN("Invalid %s operation", key);
1321
1322 if (op < OP_MATCH_MAX)
1323 r = rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
1324 else
1325 r = rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL);
1326 if (r < 0)
1327 LOG_AND_RETURN_ADD_KEY;
1328 rule_tmp.rule.rule.can_set_name = true;
1329
1330 } else if (streq(key, "OWNER")) {
1331 uid_t uid;
1332
1333 if (op == OP_REMOVE)
1334 LOG_AND_RETURN("Invalid %s operation", key);
1335
1336 if (parse_uid(value, &uid) >= 0)
1337 r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
1338 else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && !strchr("$%", value[0])) {
1339 uid = add_uid(rules, value);
1340 r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
1341 } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
1342 r = rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
1343 else {
1344 LOG_RULE_DEBUG("Resolving user name is disabled, ignoring %s=%s", key, value);
1345 continue;
1346 }
1347 if (r < 0)
1348 LOG_AND_RETURN_ADD_KEY;
1349
1350 rule_tmp.rule.rule.can_set_name = true;
1351
1352 } else if (streq(key, "GROUP")) {
1353 gid_t gid;
1354
1355 if (op == OP_REMOVE)
1356 LOG_AND_RETURN("Invalid %s operation", key);
1357
1358 if (parse_gid(value, &gid) >= 0)
1359 r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
1360 else if ((rules->resolve_name_timing == RESOLVE_NAME_EARLY) && !strchr("$%", value[0])) {
1361 gid = add_gid(rules, value);
1362 r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
1363 } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
1364 r = rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
1365 else {
1366 LOG_RULE_DEBUG("Resolving group name is disabled, ignoring %s=%s", key, value);
1367 continue;
1368 }
1369 if (r < 0)
1370 LOG_AND_RETURN_ADD_KEY;
1371
1372 rule_tmp.rule.rule.can_set_name = true;
1373
1374 } else if (streq(key, "MODE")) {
1375 mode_t mode;
1376 char *endptr;
1377
1378 if (op == OP_REMOVE)
1379 LOG_AND_RETURN("Invalid %s operation", key);
1380
1381 mode = strtol(value, &endptr, 8);
1382 if (endptr[0] == '\0')
1383 r = rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode);
1384 else
1385 r = rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL);
1386 if (r < 0)
1387 LOG_AND_RETURN_ADD_KEY;
1388
1389 rule_tmp.rule.rule.can_set_name = true;
1390
1391 } else if (streq(key, "OPTIONS")) {
1392 const char *pos;
1393
1394 if (op == OP_REMOVE)
1395 LOG_AND_RETURN("Invalid %s operation", key);
1396
1397 pos = strstr(value, "link_priority=");
1398 if (pos) {
1399 int prio = atoi(pos + STRLEN("link_priority="));
1400
1401 if (rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio) < 0)
1402 LOG_AND_RETURN_ADD_KEY;
1403 }
1404
1405 pos = strstr(value, "string_escape=");
1406 if (pos) {
1407 pos += STRLEN("string_escape=");
1408 if (startswith(pos, "none"))
1409 r = rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
1410 else if (startswith(pos, "replace"))
1411 r = rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL);
1412 else {
1413 LOG_RULE_ERROR("OPTIONS: unknown string_escape mode '%s', ignoring", pos);
1414 r = 0;
1415 }
1416 if (r < 0)
1417 LOG_AND_RETURN_ADD_KEY;
1418 }
1419
1420 pos = strstr(value, "db_persist");
1421 if (pos)
1422 if (rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL) < 0)
1423 LOG_AND_RETURN_ADD_KEY;
1424
1425 pos = strstr(value, "nowatch");
1426 if (pos) {
1427 static const int zero = 0;
1428 if (rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &zero) < 0)
1429 LOG_AND_RETURN_ADD_KEY;
1430 } else {
1431 static const int one = 1;
1432 pos = strstr(value, "watch");
1433 if (pos)
1434 if (rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &one) < 0)
1435 LOG_AND_RETURN_ADD_KEY;
1436 }
1437
1438 pos = strstr(value, "static_node=");
1439 if (pos) {
1440 pos += STRLEN("static_node=");
1441 if (rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, pos, NULL) < 0)
1442 LOG_AND_RETURN_ADD_KEY;
1443 rule_tmp.rule.rule.has_static_node = true;
1444 }
1445
1446 } else
1447 LOG_AND_RETURN("Unknown key '%s'", key);
1448 }
1449
1450 /* add rule token and sort tokens */
1451 rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur;
1452 if (add_token(rules, &rule_tmp.rule) < 0 || sort_token(rules, &rule_tmp) < 0)
1453 LOG_RULE_ERROR("Failed to add rule token");
1454 }
1455
1456 static int parse_file(UdevRules *rules, const char *filename) {
1457 _cleanup_free_ char *continuation = NULL;
1458 _cleanup_fclose_ FILE *f = NULL;
1459 bool ignore_line = false;
1460 size_t first_token, i;
1461 unsigned filename_off;
1462 int line_nr = 0, r;
1463
1464 f = fopen(filename, "re");
1465 if (!f) {
1466 if (errno == ENOENT)
1467 return 0;
1468
1469 return -errno;
1470 }
1471
1472 if (null_or_empty_fd(fileno(f))) {
1473 log_debug("Skipping empty file: %s", filename);
1474 return 0;
1475 } else
1476 log_debug("Reading rules file: %s", filename);
1477
1478 first_token = rules->token_cur;
1479 filename_off = rules_add_string(rules, filename);
1480
1481 for (;;) {
1482 _cleanup_free_ char *buf = NULL;
1483 size_t len;
1484 char *line;
1485
1486 r = read_line(f, UTIL_LINE_SIZE, &buf);
1487 if (r < 0)
1488 return r;
1489 if (r == 0)
1490 break;
1491
1492 line_nr++;
1493 line = buf + strspn(buf, WHITESPACE);
1494
1495 if (line[0] == '#')
1496 continue;
1497
1498 len = strlen(line);
1499
1500 if (continuation && !ignore_line) {
1501 if (strlen(continuation) + len >= UTIL_LINE_SIZE)
1502 ignore_line = true;
1503
1504 if (!strextend(&continuation, line, NULL))
1505 return log_oom();
1506
1507 if (!ignore_line) {
1508 line = continuation;
1509 len = strlen(line);
1510 }
1511 }
1512
1513 if (len > 0 && line[len - 1] == '\\') {
1514 if (ignore_line)
1515 continue;
1516
1517 line[len - 1] = '\0';
1518 if (!continuation) {
1519 continuation = strdup(line);
1520 if (!continuation)
1521 return log_oom();
1522 }
1523
1524 continue;
1525 }
1526
1527 if (ignore_line)
1528 log_error("Line too long '%s':%u, ignored", filename, line_nr);
1529 else if (len > 0)
1530 add_rule(rules, line, filename, filename_off, line_nr);
1531
1532 continuation = mfree(continuation);
1533 ignore_line = false;
1534 }
1535
1536 /* link GOTOs to LABEL rules in this file to be able to fast-forward */
1537 for (i = first_token+1; i < rules->token_cur; i++) {
1538 if (rules->tokens[i].type == TK_A_GOTO) {
1539 char *label = rules_str(rules, rules->tokens[i].key.value_off);
1540 size_t j;
1541
1542 for (j = i+1; j < rules->token_cur; j++) {
1543 if (rules->tokens[j].type != TK_RULE)
1544 continue;
1545 if (rules->tokens[j].rule.label_off == 0)
1546 continue;
1547 if (!streq(label, rules_str(rules, rules->tokens[j].rule.label_off)))
1548 continue;
1549 rules->tokens[i].key.rule_goto = j;
1550 break;
1551 }
1552 if (rules->tokens[i].key.rule_goto == 0)
1553 log_error("GOTO '%s' has no matching label in: '%s'", label, filename);
1554 }
1555 }
1556 return 0;
1557 }
1558
1559 int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing) {
1560 _cleanup_(udev_rules_freep) UdevRules *rules = NULL;
1561 _cleanup_strv_free_ char **files = NULL;
1562 char **f;
1563 int r;
1564
1565 assert(resolve_name_timing >= 0 && resolve_name_timing < _RESOLVE_NAME_TIMING_MAX);
1566
1567 rules = new(UdevRules, 1);
1568 if (!rules)
1569 return -ENOMEM;
1570
1571 *rules = (UdevRules) {
1572 .resolve_name_timing = resolve_name_timing,
1573 };
1574
1575 /* init token array and string buffer */
1576 rules->tokens = new(struct token, PREALLOC_TOKEN);
1577 if (!rules->tokens)
1578 return -ENOMEM;
1579 rules->token_max = PREALLOC_TOKEN;
1580
1581 rules->strbuf = strbuf_new();
1582 if (!rules->strbuf)
1583 return -ENOMEM;
1584
1585 udev_rules_check_timestamp(rules);
1586
1587 r = conf_files_list_strv(&files, ".rules", NULL, 0, RULES_DIRS);
1588 if (r < 0)
1589 return log_error_errno(r, "Failed to enumerate rules files: %m");
1590
1591 /*
1592 * The offset value in the rules strct is limited; add all
1593 * rules file names to the beginning of the string buffer.
1594 */
1595 STRV_FOREACH(f, files)
1596 rules_add_string(rules, *f);
1597
1598 STRV_FOREACH(f, files)
1599 parse_file(rules, *f);
1600
1601 struct token end_token = { .type = TK_END };
1602 add_token(rules, &end_token);
1603 log_debug("Rules contain %zu bytes tokens (%zu * %zu bytes), %zu bytes strings",
1604 rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->strbuf->len);
1605
1606 /* cleanup temporary strbuf data */
1607 log_debug("%zu strings (%zu bytes), %zu de-duplicated (%zu bytes), %zu trie nodes used",
1608 rules->strbuf->in_count, rules->strbuf->in_len,
1609 rules->strbuf->dedup_count, rules->strbuf->dedup_len, rules->strbuf->nodes_count);
1610 strbuf_complete(rules->strbuf);
1611
1612 /* cleanup uid/gid cache */
1613 rules->uids = mfree(rules->uids);
1614 rules->uids_cur = 0;
1615 rules->uids_max = 0;
1616 rules->gids = mfree(rules->gids);
1617 rules->gids_cur = 0;
1618 rules->gids_max = 0;
1619
1620 dump_rules(rules);
1621 *ret_rules = TAKE_PTR(rules);
1622 return 0;
1623 }
1624
1625 UdevRules *udev_rules_free(UdevRules *rules) {
1626 if (!rules)
1627 return NULL;
1628 free(rules->tokens);
1629 strbuf_cleanup(rules->strbuf);
1630 free(rules->uids);
1631 free(rules->gids);
1632 return mfree(rules);
1633 }
1634
1635 bool udev_rules_check_timestamp(UdevRules *rules) {
1636 if (!rules)
1637 return false;
1638
1639 return paths_check_timestamp(RULES_DIRS, &rules->dirs_ts_usec, true);
1640 }
1641
1642 static bool match_key(UdevRules *rules, struct token *token, const char *val) {
1643 char *key_value = rules_str(rules, token->key.value_off);
1644 char *pos;
1645 bool match = false;
1646
1647 if (!val)
1648 val = "";
1649
1650 switch (token->key.glob) {
1651 case GL_PLAIN:
1652 match = streq(key_value, val);
1653 break;
1654 case GL_GLOB:
1655 match = (fnmatch(key_value, val, 0) == 0);
1656 break;
1657 case GL_SPLIT:
1658 {
1659 const char *s;
1660 size_t len;
1661
1662 s = rules_str(rules, token->key.value_off);
1663 len = strlen(val);
1664 for (;;) {
1665 const char *next;
1666
1667 next = strchr(s, '|');
1668 if (next) {
1669 size_t matchlen = (size_t)(next - s);
1670
1671 match = (matchlen == len && strneq(s, val, matchlen));
1672 if (match)
1673 break;
1674 } else {
1675 match = streq(s, val);
1676 break;
1677 }
1678 s = &next[1];
1679 }
1680 break;
1681 }
1682 case GL_SPLIT_GLOB:
1683 {
1684 char value[UTIL_PATH_SIZE];
1685
1686 strscpy(value, sizeof(value), rules_str(rules, token->key.value_off));
1687 key_value = value;
1688 while (key_value) {
1689 pos = strchr(key_value, '|');
1690 if (pos) {
1691 pos[0] = '\0';
1692 pos = &pos[1];
1693 }
1694 match = (fnmatch(key_value, val, 0) == 0);
1695 if (match)
1696 break;
1697 key_value = pos;
1698 }
1699 break;
1700 }
1701 case GL_SOMETHING:
1702 match = (val[0] != '\0');
1703 break;
1704 case GL_UNSET:
1705 return false;
1706 }
1707
1708 return token->key.op == (match ? OP_MATCH : OP_NOMATCH);
1709 }
1710
1711 static bool match_attr(UdevRules *rules, sd_device *dev, UdevEvent *event, struct token *cur) {
1712 char nbuf[UTIL_NAME_SIZE], vbuf[UTIL_NAME_SIZE];
1713 const char *name, *value;
1714 size_t len;
1715
1716 name = rules_str(rules, cur->key.attr_off);
1717 switch (cur->key.attrsubst) {
1718 case SB_FORMAT:
1719 udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false);
1720 name = nbuf;
1721 _fallthrough_;
1722 case SB_NONE:
1723 if (sd_device_get_sysattr_value(dev, name, &value) < 0)
1724 return false;
1725 break;
1726 case SB_SUBSYS:
1727 if (util_resolve_subsys_kernel(name, vbuf, sizeof(vbuf), true) < 0)
1728 return false;
1729 value = vbuf;
1730 break;
1731 default:
1732 return false;
1733 }
1734
1735 /* remove trailing whitespace, if not asked to match for it */
1736 len = strlen(value);
1737 if (len > 0 && isspace(value[len-1])) {
1738 const char *key_value;
1739 size_t klen;
1740
1741 key_value = rules_str(rules, cur->key.value_off);
1742 klen = strlen(key_value);
1743 if (klen > 0 && !isspace(key_value[klen-1])) {
1744 if (value != vbuf) {
1745 strscpy(vbuf, sizeof(vbuf), value);
1746 value = vbuf;
1747 }
1748 while (len > 0 && isspace(vbuf[--len]))
1749 vbuf[len] = '\0';
1750 }
1751 }
1752
1753 return match_key(rules, cur, value);
1754 }
1755
1756 enum escape_type {
1757 ESCAPE_UNSET,
1758 ESCAPE_NONE,
1759 ESCAPE_REPLACE,
1760 };
1761
1762 int udev_rules_apply_to_event(
1763 UdevRules *rules,
1764 UdevEvent *event,
1765 usec_t timeout_usec,
1766 Hashmap *properties_list) {
1767 sd_device *dev = event->dev;
1768 enum escape_type esc = ESCAPE_UNSET;
1769 struct token *cur, *rule;
1770 const char *action, *val;
1771 bool can_set_name;
1772 int r;
1773
1774 if (!rules->tokens)
1775 return 0;
1776
1777 r = sd_device_get_property_value(dev, "ACTION", &action);
1778 if (r < 0)
1779 return r;
1780
1781 can_set_name = (!streq(action, "remove") &&
1782 (sd_device_get_devnum(dev, NULL) >= 0 ||
1783 sd_device_get_ifindex(dev, NULL) >= 0));
1784
1785 /* loop through token list, match, run actions or forward to next rule */
1786 cur = &rules->tokens[0];
1787 rule = cur;
1788 for (;;) {
1789 dump_token(rules, cur);
1790 switch (cur->type) {
1791 case TK_RULE:
1792 /* current rule */
1793 rule = cur;
1794 /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */
1795 if (!can_set_name && rule->rule.can_set_name)
1796 goto nomatch;
1797 esc = ESCAPE_UNSET;
1798 break;
1799 case TK_M_ACTION:
1800 if (!match_key(rules, cur, action))
1801 goto nomatch;
1802 break;
1803 case TK_M_DEVPATH:
1804 if (sd_device_get_devpath(dev, &val) < 0)
1805 goto nomatch;
1806 if (!match_key(rules, cur, val))
1807 goto nomatch;
1808 break;
1809 case TK_M_KERNEL:
1810 if (sd_device_get_sysname(dev, &val) < 0)
1811 goto nomatch;
1812 if (!match_key(rules, cur, val))
1813 goto nomatch;
1814 break;
1815 case TK_M_DEVLINK: {
1816 const char *devlink;
1817 bool match = false;
1818
1819 FOREACH_DEVICE_DEVLINK(dev, devlink)
1820 if (match_key(rules, cur, devlink + STRLEN("/dev/"))) {
1821 match = true;
1822 break;
1823 }
1824
1825 if (!match)
1826 goto nomatch;
1827 break;
1828 }
1829 case TK_M_NAME:
1830 if (!match_key(rules, cur, event->name))
1831 goto nomatch;
1832 break;
1833 case TK_M_ENV: {
1834 const char *key_name = rules_str(rules, cur->key.attr_off);
1835
1836 if (sd_device_get_property_value(dev, key_name, &val) < 0) {
1837 /* check global properties */
1838 if (properties_list)
1839 val = hashmap_get(properties_list, key_name);
1840 else
1841 val = NULL;
1842 }
1843
1844 if (!match_key(rules, cur, strempty(val)))
1845 goto nomatch;
1846 break;
1847 }
1848 case TK_M_TAG: {
1849 bool match = false;
1850 const char *tag;
1851
1852 FOREACH_DEVICE_TAG(dev, tag)
1853 if (streq(rules_str(rules, cur->key.value_off), tag)) {
1854 match = true;
1855 break;
1856 }
1857
1858 if ((!match && (cur->key.op != OP_NOMATCH)) ||
1859 (match && (cur->key.op == OP_NOMATCH)))
1860 goto nomatch;
1861 break;
1862 }
1863 case TK_M_SUBSYSTEM:
1864 if (sd_device_get_subsystem(dev, &val) < 0)
1865 goto nomatch;
1866 if (!match_key(rules, cur, val))
1867 goto nomatch;
1868 break;
1869 case TK_M_DRIVER:
1870 if (sd_device_get_driver(dev, &val) < 0)
1871 goto nomatch;
1872 if (!match_key(rules, cur, val))
1873 goto nomatch;
1874 break;
1875 case TK_M_ATTR:
1876 if (!match_attr(rules, dev, event, cur))
1877 goto nomatch;
1878 break;
1879 case TK_M_SYSCTL: {
1880 char filename[UTIL_PATH_SIZE];
1881 _cleanup_free_ char *value = NULL;
1882 size_t len;
1883
1884 udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename), false);
1885 sysctl_normalize(filename);
1886 if (sysctl_read(filename, &value) < 0)
1887 goto nomatch;
1888
1889 len = strlen(value);
1890 while (len > 0 && isspace(value[--len]))
1891 value[len] = '\0';
1892 if (!match_key(rules, cur, value))
1893 goto nomatch;
1894 break;
1895 }
1896 case TK_M_KERNELS:
1897 case TK_M_SUBSYSTEMS:
1898 case TK_M_DRIVERS:
1899 case TK_M_ATTRS:
1900 case TK_M_TAGS: {
1901 struct token *next;
1902
1903 /* get whole sequence of parent matches */
1904 next = cur;
1905 while (next->type > TK_M_PARENTS_MIN && next->type < TK_M_PARENTS_MAX)
1906 next++;
1907
1908 /* loop over parents */
1909 event->dev_parent = dev;
1910 for (;;) {
1911 struct token *key;
1912
1913 /* loop over sequence of parent match keys */
1914 for (key = cur; key < next; key++ ) {
1915 dump_token(rules, key);
1916 switch(key->type) {
1917 case TK_M_KERNELS:
1918 if (sd_device_get_sysname(event->dev_parent, &val) < 0)
1919 goto try_parent;
1920 if (!match_key(rules, key, val))
1921 goto try_parent;
1922 break;
1923 case TK_M_SUBSYSTEMS:
1924 if (sd_device_get_subsystem(event->dev_parent, &val) < 0)
1925 goto try_parent;
1926 if (!match_key(rules, key, val))
1927 goto try_parent;
1928 break;
1929 case TK_M_DRIVERS:
1930 if (sd_device_get_driver(event->dev_parent, &val) < 0)
1931 goto try_parent;
1932 if (!match_key(rules, key, val))
1933 goto try_parent;
1934 break;
1935 case TK_M_ATTRS:
1936 if (!match_attr(rules, event->dev_parent, event, key))
1937 goto try_parent;
1938 break;
1939 case TK_M_TAGS: {
1940 bool match = sd_device_has_tag(event->dev_parent, rules_str(rules, cur->key.value_off));
1941
1942 if (match && key->key.op == OP_NOMATCH)
1943 goto try_parent;
1944 if (!match && key->key.op == OP_MATCH)
1945 goto try_parent;
1946 break;
1947 }
1948 default:
1949 goto nomatch;
1950 }
1951 }
1952 break;
1953
1954 try_parent:
1955 if (sd_device_get_parent(event->dev_parent, &event->dev_parent) < 0) {
1956 event->dev_parent = NULL;
1957 goto nomatch;
1958 }
1959 }
1960 /* move behind our sequence of parent match keys */
1961 cur = next;
1962 continue;
1963 }
1964 case TK_M_TEST: {
1965 char filename[UTIL_PATH_SIZE];
1966 struct stat statbuf;
1967 int match;
1968
1969 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename), false);
1970 if (util_resolve_subsys_kernel(filename, filename, sizeof(filename), false) < 0) {
1971 if (filename[0] != '/') {
1972 char tmp[UTIL_PATH_SIZE];
1973
1974 if (sd_device_get_syspath(dev, &val) < 0)
1975 goto nomatch;
1976
1977 strscpy(tmp, sizeof(tmp), filename);
1978 strscpyl(filename, sizeof(filename), val, "/", tmp, NULL);
1979 }
1980 }
1981 attr_subst_subdir(filename, sizeof(filename));
1982
1983 match = (stat(filename, &statbuf) == 0);
1984 if (match && cur->key.mode > 0)
1985 match = ((statbuf.st_mode & cur->key.mode) > 0);
1986 if (match && cur->key.op == OP_NOMATCH)
1987 goto nomatch;
1988 if (!match && cur->key.op == OP_MATCH)
1989 goto nomatch;
1990 break;
1991 }
1992 case TK_M_PROGRAM: {
1993 char program[UTIL_PATH_SIZE], result[UTIL_LINE_SIZE];
1994
1995 event->program_result = mfree(event->program_result);
1996 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), program, sizeof(program), false);
1997 log_device_debug(dev, "PROGRAM '%s' %s:%u",
1998 program,
1999 rules_str(rules, rule->rule.filename_off),
2000 rule->rule.filename_line);
2001
2002 if (udev_event_spawn(event, timeout_usec, true, program, result, sizeof(result)) != 0) {
2003 if (cur->key.op != OP_NOMATCH)
2004 goto nomatch;
2005 } else {
2006 int count;
2007
2008 delete_trailing_chars(result, "\n");
2009 if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
2010 count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
2011 if (count > 0)
2012 log_device_debug(dev, "Replaced %i character(s) from result of '%s'" , count, program);
2013 }
2014 event->program_result = strdup(result);
2015 if (cur->key.op == OP_NOMATCH)
2016 goto nomatch;
2017 }
2018 break;
2019 }
2020 case TK_M_IMPORT_FILE: {
2021 char import[UTIL_PATH_SIZE];
2022
2023 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
2024 if (import_file_into_properties(dev, import) < 0)
2025 if (cur->key.op != OP_NOMATCH)
2026 goto nomatch;
2027 break;
2028 }
2029 case TK_M_IMPORT_PROG: {
2030 char import[UTIL_PATH_SIZE];
2031
2032 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
2033 log_device_debug(dev, "IMPORT '%s' %s:%u",
2034 import,
2035 rules_str(rules, rule->rule.filename_off),
2036 rule->rule.filename_line);
2037
2038 if (import_program_into_properties(event, timeout_usec, import) < 0)
2039 if (cur->key.op != OP_NOMATCH)
2040 goto nomatch;
2041 break;
2042 }
2043 case TK_M_IMPORT_BUILTIN: {
2044 char command[UTIL_PATH_SIZE];
2045
2046 if (udev_builtin_run_once(cur->key.builtin_cmd)) {
2047 /* check if we ran already */
2048 if (event->builtin_run & (1 << cur->key.builtin_cmd)) {
2049 log_device_debug(dev, "IMPORT builtin skip '%s' %s:%u",
2050 udev_builtin_name(cur->key.builtin_cmd),
2051 rules_str(rules, rule->rule.filename_off),
2052 rule->rule.filename_line);
2053 /* return the result from earlier run */
2054 if (event->builtin_ret & (1 << cur->key.builtin_cmd))
2055 if (cur->key.op != OP_NOMATCH)
2056 goto nomatch;
2057 break;
2058 }
2059 /* mark as ran */
2060 event->builtin_run |= (1 << cur->key.builtin_cmd);
2061 }
2062
2063 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), command, sizeof(command), false);
2064 log_device_debug(dev, "IMPORT builtin '%s' %s:%u",
2065 udev_builtin_name(cur->key.builtin_cmd),
2066 rules_str(rules, rule->rule.filename_off),
2067 rule->rule.filename_line);
2068
2069 r = udev_builtin_run(dev, cur->key.builtin_cmd, command, false);
2070 if (r < 0) {
2071 /* remember failure */
2072 log_device_debug_errno(dev, r, "IMPORT builtin '%s' fails: %m",
2073 udev_builtin_name(cur->key.builtin_cmd));
2074 event->builtin_ret |= (1 << cur->key.builtin_cmd);
2075 if (cur->key.op != OP_NOMATCH)
2076 goto nomatch;
2077 }
2078 break;
2079 }
2080 case TK_M_IMPORT_DB: {
2081 const char *key;
2082
2083 key = rules_str(rules, cur->key.value_off);
2084 if (event->dev_db_clone &&
2085 sd_device_get_property_value(event->dev_db_clone, key, &val) >= 0)
2086 device_add_property(dev, key, val);
2087 else if (cur->key.op != OP_NOMATCH)
2088 goto nomatch;
2089 break;
2090 }
2091 case TK_M_IMPORT_CMDLINE: {
2092 _cleanup_free_ char *value = NULL;
2093 bool imported = false;
2094 const char *key;
2095
2096 key = rules_str(rules, cur->key.value_off);
2097 r = proc_cmdline_get_key(key, PROC_CMDLINE_VALUE_OPTIONAL, &value);
2098 if (r < 0)
2099 log_device_debug_errno(dev, r, "Failed to read %s from /proc/cmdline, ignoring: %m", key);
2100 else if (r > 0) {
2101 imported = true;
2102
2103 if (value)
2104 device_add_property(dev, key, value);
2105 else
2106 /* we import simple flags as 'FLAG=1' */
2107 device_add_property(dev, key, "1");
2108 }
2109
2110 if (!imported && cur->key.op != OP_NOMATCH)
2111 goto nomatch;
2112 break;
2113 }
2114 case TK_M_IMPORT_PARENT: {
2115 char import[UTIL_PATH_SIZE];
2116
2117 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
2118 if (import_parent_into_properties(dev, import) < 0)
2119 if (cur->key.op != OP_NOMATCH)
2120 goto nomatch;
2121 break;
2122 }
2123 case TK_M_RESULT:
2124 if (!match_key(rules, cur, event->program_result))
2125 goto nomatch;
2126 break;
2127 case TK_A_STRING_ESCAPE_NONE:
2128 esc = ESCAPE_NONE;
2129 break;
2130 case TK_A_STRING_ESCAPE_REPLACE:
2131 esc = ESCAPE_REPLACE;
2132 break;
2133 case TK_A_DB_PERSIST:
2134 device_set_db_persist(dev);
2135 break;
2136 case TK_A_INOTIFY_WATCH:
2137 if (event->inotify_watch_final)
2138 break;
2139 if (cur->key.op == OP_ASSIGN_FINAL)
2140 event->inotify_watch_final = true;
2141 event->inotify_watch = cur->key.watch;
2142 break;
2143 case TK_A_DEVLINK_PRIO:
2144 device_set_devlink_priority(dev, cur->key.devlink_prio);
2145 break;
2146 case TK_A_OWNER: {
2147 char owner[UTIL_NAME_SIZE];
2148 const char *ow = owner;
2149
2150 if (event->owner_final)
2151 break;
2152 if (cur->key.op == OP_ASSIGN_FINAL)
2153 event->owner_final = true;
2154 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner), false);
2155 event->owner_set = true;
2156 r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
2157 if (r < 0) {
2158 log_unknown_owner(dev, r, "user", owner);
2159 event->uid = 0;
2160 }
2161 log_device_debug(dev, "OWNER %u %s:%u",
2162 event->uid,
2163 rules_str(rules, rule->rule.filename_off),
2164 rule->rule.filename_line);
2165 break;
2166 }
2167 case TK_A_GROUP: {
2168 char group[UTIL_NAME_SIZE];
2169 const char *gr = group;
2170
2171 if (event->group_final)
2172 break;
2173 if (cur->key.op == OP_ASSIGN_FINAL)
2174 event->group_final = true;
2175 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group), false);
2176 event->group_set = true;
2177 r = get_group_creds(&gr, &event->gid, USER_CREDS_ALLOW_MISSING);
2178 if (r < 0) {
2179 log_unknown_owner(dev, r, "group", group);
2180 event->gid = 0;
2181 }
2182 log_device_debug(dev, "GROUP %u %s:%u",
2183 event->gid,
2184 rules_str(rules, rule->rule.filename_off),
2185 rule->rule.filename_line);
2186 break;
2187 }
2188 case TK_A_MODE: {
2189 char mode_str[UTIL_NAME_SIZE];
2190 mode_t mode;
2191
2192 if (event->mode_final)
2193 break;
2194 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), mode_str, sizeof(mode_str), false);
2195 r = parse_mode(mode_str, &mode);
2196 if (r < 0) {
2197 log_device_error_errno(dev, r, "Failed to parse mode '%s': %m", mode_str);
2198 break;
2199 }
2200 if (cur->key.op == OP_ASSIGN_FINAL)
2201 event->mode_final = true;
2202 event->mode_set = true;
2203 event->mode = mode;
2204 log_device_debug(dev, "MODE %#o %s:%u",
2205 event->mode,
2206 rules_str(rules, rule->rule.filename_off),
2207 rule->rule.filename_line);
2208 break;
2209 }
2210 case TK_A_OWNER_ID:
2211 if (event->owner_final)
2212 break;
2213 if (cur->key.op == OP_ASSIGN_FINAL)
2214 event->owner_final = true;
2215 event->owner_set = true;
2216 event->uid = cur->key.uid;
2217 log_device_debug(dev, "OWNER %u %s:%u",
2218 event->uid,
2219 rules_str(rules, rule->rule.filename_off),
2220 rule->rule.filename_line);
2221 break;
2222 case TK_A_GROUP_ID:
2223 if (event->group_final)
2224 break;
2225 if (cur->key.op == OP_ASSIGN_FINAL)
2226 event->group_final = true;
2227 event->group_set = true;
2228 event->gid = cur->key.gid;
2229 log_device_debug(dev, "GROUP %u %s:%u",
2230 event->gid,
2231 rules_str(rules, rule->rule.filename_off),
2232 rule->rule.filename_line);
2233 break;
2234 case TK_A_MODE_ID:
2235 if (event->mode_final)
2236 break;
2237 if (cur->key.op == OP_ASSIGN_FINAL)
2238 event->mode_final = true;
2239 event->mode_set = true;
2240 event->mode = cur->key.mode;
2241 log_device_debug(dev, "MODE %#o %s:%u",
2242 event->mode,
2243 rules_str(rules, rule->rule.filename_off),
2244 rule->rule.filename_line);
2245 break;
2246 case TK_A_SECLABEL: {
2247 _cleanup_free_ char *name = NULL, *label = NULL;
2248 char label_str[UTIL_LINE_SIZE] = {};
2249
2250 name = strdup(rules_str(rules, cur->key.attr_off));
2251 if (!name)
2252 return log_oom();
2253
2254 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), label_str, sizeof(label_str), false);
2255 if (!isempty(label_str))
2256 label = strdup(label_str);
2257 else
2258 label = strdup(rules_str(rules, cur->key.value_off));
2259 if (!label)
2260 return log_oom();
2261
2262 if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
2263 hashmap_clear_free_free(event->seclabel_list);
2264
2265 r = hashmap_ensure_allocated(&event->seclabel_list, NULL);
2266 if (r < 0)
2267 return log_oom();
2268
2269 r = hashmap_put(event->seclabel_list, name, label);
2270 if (r < 0)
2271 return log_oom();
2272 log_device_debug(dev, "SECLABEL{%s}='%s' %s:%u",
2273 name, label,
2274 rules_str(rules, rule->rule.filename_off),
2275 rule->rule.filename_line);
2276 name = label = NULL;
2277
2278 break;
2279 }
2280 case TK_A_ENV: {
2281 char value_new[UTIL_NAME_SIZE];
2282 const char *name, *value_old;
2283
2284 name = rules_str(rules, cur->key.attr_off);
2285 val = rules_str(rules, cur->key.value_off);
2286 if (val[0] == '\0') {
2287 if (cur->key.op == OP_ADD)
2288 break;
2289 device_add_property(dev, name, NULL);
2290 break;
2291 }
2292
2293 if (cur->key.op == OP_ADD &&
2294 sd_device_get_property_value(dev, name, &value_old) >= 0) {
2295 char temp[UTIL_NAME_SIZE];
2296
2297 /* append value separated by space */
2298 udev_event_apply_format(event, val, temp, sizeof(temp), false);
2299 strscpyl(value_new, sizeof(value_new), value_old, " ", temp, NULL);
2300 } else
2301 udev_event_apply_format(event, val, value_new, sizeof(value_new), false);
2302
2303 device_add_property(dev, name, value_new);
2304 break;
2305 }
2306 case TK_A_TAG: {
2307 char tag[UTIL_PATH_SIZE];
2308 const char *p;
2309
2310 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), tag, sizeof(tag), false);
2311 if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
2312 device_cleanup_tags(dev);
2313 for (p = tag; *p != '\0'; p++) {
2314 if ((*p >= 'a' && *p <= 'z') ||
2315 (*p >= 'A' && *p <= 'Z') ||
2316 (*p >= '0' && *p <= '9') ||
2317 IN_SET(*p, '-', '_'))
2318 continue;
2319 log_device_error(dev, "Ignoring invalid tag name '%s'", tag);
2320 break;
2321 }
2322 if (cur->key.op == OP_REMOVE)
2323 device_remove_tag(dev, tag);
2324 else
2325 device_add_tag(dev, tag);
2326 break;
2327 }
2328 case TK_A_NAME: {
2329 char name_str[UTIL_PATH_SIZE];
2330 const char *name;
2331 int count;
2332
2333 name = rules_str(rules, cur->key.value_off);
2334 if (event->name_final)
2335 break;
2336 if (cur->key.op == OP_ASSIGN_FINAL)
2337 event->name_final = true;
2338 udev_event_apply_format(event, name, name_str, sizeof(name_str), false);
2339 if (IN_SET(esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
2340 count = util_replace_chars(name_str, "/");
2341 if (count > 0)
2342 log_device_debug(dev, "Replaced %i character(s) from result of NAME=\"%s\"", count, name);
2343 }
2344 if (sd_device_get_devnum(dev, NULL) >= 0 &&
2345 (sd_device_get_devname(dev, &val) < 0 ||
2346 !streq(name_str, val + STRLEN("/dev/")))) {
2347 log_device_error(dev, "Kernel device nodes cannot be renamed, ignoring NAME=\"%s\"; please fix it in %s:%u\n",
2348 name,
2349 rules_str(rules, rule->rule.filename_off),
2350 rule->rule.filename_line);
2351 break;
2352 }
2353 if (free_and_strdup(&event->name, name_str) < 0)
2354 return log_oom();
2355
2356 log_device_debug(dev, "NAME '%s' %s:%u",
2357 event->name,
2358 rules_str(rules, rule->rule.filename_off),
2359 rule->rule.filename_line);
2360 break;
2361 }
2362 case TK_A_DEVLINK: {
2363 char temp[UTIL_PATH_SIZE], filename[UTIL_PATH_SIZE], *pos, *next;
2364 int count = 0;
2365
2366 if (event->devlink_final)
2367 break;
2368 if (sd_device_get_devnum(dev, NULL) < 0)
2369 break;
2370 if (cur->key.op == OP_ASSIGN_FINAL)
2371 event->devlink_final = true;
2372 if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
2373 device_cleanup_devlinks(dev);
2374
2375 /* allow multiple symlinks separated by spaces */
2376 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), temp, sizeof(temp), esc != ESCAPE_NONE);
2377 if (esc == ESCAPE_UNSET)
2378 count = util_replace_chars(temp, "/ ");
2379 else if (esc == ESCAPE_REPLACE)
2380 count = util_replace_chars(temp, "/");
2381 if (count > 0)
2382 log_device_debug(dev, "Replaced %i character(s) from result of LINK" , count);
2383 pos = temp;
2384 while (isspace(pos[0]))
2385 pos++;
2386 next = strchr(pos, ' ');
2387 while (next) {
2388 next[0] = '\0';
2389 log_device_debug(dev, "LINK '%s' %s:%u", pos,
2390 rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
2391 strscpyl(filename, sizeof(filename), "/dev/", pos, NULL);
2392 device_add_devlink(dev, filename);
2393 while (isspace(next[1]))
2394 next++;
2395 pos = &next[1];
2396 next = strchr(pos, ' ');
2397 }
2398 if (pos[0] != '\0') {
2399 log_device_debug(dev, "LINK '%s' %s:%u", pos,
2400 rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
2401 strscpyl(filename, sizeof(filename), "/dev/", pos, NULL);
2402 device_add_devlink(dev, filename);
2403 }
2404 break;
2405 }
2406 case TK_A_ATTR: {
2407 char attr[UTIL_PATH_SIZE], value[UTIL_NAME_SIZE];
2408 _cleanup_fclose_ FILE *f = NULL;
2409 const char *key_name;
2410
2411 key_name = rules_str(rules, cur->key.attr_off);
2412 if (util_resolve_subsys_kernel(key_name, attr, sizeof(attr), false) < 0 &&
2413 sd_device_get_syspath(dev, &val) >= 0)
2414 strscpyl(attr, sizeof(attr), val, "/", key_name, NULL);
2415 attr_subst_subdir(attr, sizeof(attr));
2416
2417 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value), false);
2418 log_device_debug(dev, "ATTR '%s' writing '%s' %s:%u", attr, value,
2419 rules_str(rules, rule->rule.filename_off),
2420 rule->rule.filename_line);
2421 f = fopen(attr, "we");
2422 if (!f)
2423 log_device_error_errno(dev, errno, "Failed to open ATTR{%s} for writing: %m", attr);
2424 else if (fprintf(f, "%s", value) <= 0)
2425 log_device_error_errno(dev, errno, "Failed to write ATTR{%s}: %m", attr);
2426 break;
2427 }
2428 case TK_A_SYSCTL: {
2429 char filename[UTIL_PATH_SIZE], value[UTIL_NAME_SIZE];
2430
2431 udev_event_apply_format(event, rules_str(rules, cur->key.attr_off), filename, sizeof(filename), false);
2432 sysctl_normalize(filename);
2433 udev_event_apply_format(event, rules_str(rules, cur->key.value_off), value, sizeof(value), false);
2434 log_device_debug(dev, "SYSCTL '%s' writing '%s' %s:%u", filename, value,
2435 rules_str(rules, rule->rule.filename_off), rule->rule.filename_line);
2436 r = sysctl_write(filename, value);
2437 if (r < 0)
2438 log_device_error_errno(dev, r, "Failed to write SYSCTL{%s}='%s': %m", filename, value);
2439 break;
2440 }
2441 case TK_A_RUN_BUILTIN:
2442 case TK_A_RUN_PROGRAM: {
2443 _cleanup_free_ char *cmd = NULL;
2444
2445 if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
2446 hashmap_clear_free_key(event->run_list);
2447
2448 r = hashmap_ensure_allocated(&event->run_list, NULL);
2449 if (r < 0)
2450 return log_oom();
2451
2452 cmd = strdup(rules_str(rules, cur->key.value_off));
2453 if (!cmd)
2454 return log_oom();
2455
2456 r = hashmap_put(event->run_list, cmd, INT_TO_PTR(cur->key.builtin_cmd));
2457 if (r < 0)
2458 return log_oom();
2459
2460 cmd = NULL;
2461
2462 log_device_debug(dev, "RUN '%s' %s:%u",
2463 rules_str(rules, cur->key.value_off),
2464 rules_str(rules, rule->rule.filename_off),
2465 rule->rule.filename_line);
2466 break;
2467 }
2468 case TK_A_GOTO:
2469 if (cur->key.rule_goto == 0)
2470 break;
2471 cur = &rules->tokens[cur->key.rule_goto];
2472 continue;
2473 case TK_END:
2474 return 0;
2475
2476 case TK_M_PARENTS_MIN:
2477 case TK_M_PARENTS_MAX:
2478 case TK_M_MAX:
2479 case TK_UNSET:
2480 log_device_error(dev, "Wrong type %u", cur->type);
2481 goto nomatch;
2482 }
2483
2484 cur++;
2485 continue;
2486 nomatch:
2487 /* fast-forward to next rule */
2488 cur = rule + rule->rule.token_count;
2489 }
2490
2491 return 0;
2492 }
2493
2494 int udev_rules_apply_static_dev_perms(UdevRules *rules) {
2495 struct token *cur;
2496 struct token *rule;
2497 uid_t uid = 0;
2498 gid_t gid = 0;
2499 mode_t mode = 0;
2500 _cleanup_strv_free_ char **tags = NULL;
2501 char **t;
2502 FILE *f = NULL;
2503 _cleanup_free_ char *path = NULL;
2504 int r;
2505
2506 if (!rules->tokens)
2507 return 0;
2508
2509 cur = &rules->tokens[0];
2510 rule = cur;
2511 for (;;) {
2512 switch (cur->type) {
2513 case TK_RULE:
2514 /* current rule */
2515 rule = cur;
2516
2517 /* skip rules without a static_node tag */
2518 if (!rule->rule.has_static_node)
2519 goto next;
2520
2521 uid = 0;
2522 gid = 0;
2523 mode = 0;
2524 tags = strv_free(tags);
2525 break;
2526 case TK_A_OWNER_ID:
2527 uid = cur->key.uid;
2528 break;
2529 case TK_A_GROUP_ID:
2530 gid = cur->key.gid;
2531 break;
2532 case TK_A_MODE_ID:
2533 mode = cur->key.mode;
2534 break;
2535 case TK_A_TAG:
2536 r = strv_extend(&tags, rules_str(rules, cur->key.value_off));
2537 if (r < 0)
2538 goto finish;
2539
2540 break;
2541 case TK_A_STATIC_NODE: {
2542 char device_node[UTIL_PATH_SIZE];
2543 char tags_dir[UTIL_PATH_SIZE];
2544 char tag_symlink[UTIL_PATH_SIZE];
2545 struct stat stats;
2546
2547 /* we assure, that the permissions tokens are sorted before the static token */
2548
2549 if (mode == 0 && uid == 0 && gid == 0 && !tags)
2550 goto next;
2551
2552 strscpyl(device_node, sizeof(device_node), "/dev/", rules_str(rules, cur->key.value_off), NULL);
2553 if (stat(device_node, &stats) < 0)
2554 break;
2555 if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
2556 break;
2557
2558 /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */
2559 if (tags) {
2560 STRV_FOREACH(t, tags) {
2561 _cleanup_free_ char *unescaped_filename = NULL;
2562
2563 strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL);
2564 r = mkdir_p(tags_dir, 0755);
2565 if (r < 0)
2566 return log_error_errno(r, "Failed to create %s: %m", tags_dir);
2567
2568 unescaped_filename = xescape(rules_str(rules, cur->key.value_off), "/.");
2569
2570 strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL);
2571 r = symlink(device_node, tag_symlink);
2572 if (r < 0 && errno != EEXIST)
2573 return log_error_errno(errno, "Failed to create symlink %s -> %s: %m",
2574 tag_symlink, device_node);
2575 }
2576 }
2577
2578 /* don't touch the permissions if only the tags were set */
2579 if (mode == 0 && uid == 0 && gid == 0)
2580 break;
2581
2582 if (mode == 0) {
2583 if (gid > 0)
2584 mode = 0660;
2585 else
2586 mode = 0600;
2587 }
2588 if (mode != (stats.st_mode & 01777)) {
2589 r = chmod(device_node, mode);
2590 if (r < 0)
2591 return log_error_errno(errno, "Failed to chmod '%s' %#o: %m",
2592 device_node, mode);
2593 else
2594 log_debug("chmod '%s' %#o", device_node, mode);
2595 }
2596
2597 if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) {
2598 r = chown(device_node, uid, gid);
2599 if (r < 0)
2600 return log_error_errno(errno, "Failed to chown '%s' %u %u: %m",
2601 device_node, uid, gid);
2602 else
2603 log_debug("chown '%s' %u %u", device_node, uid, gid);
2604 }
2605
2606 utimensat(AT_FDCWD, device_node, NULL, 0);
2607 break;
2608 }
2609 case TK_END:
2610 goto finish;
2611 }
2612
2613 cur++;
2614 continue;
2615 next:
2616 /* fast-forward to next rule */
2617 cur = rule + rule->rule.token_count;
2618 continue;
2619 }
2620
2621 finish:
2622 if (f) {
2623 fflush(f);
2624 fchmod(fileno(f), 0644);
2625 if (ferror(f) || rename(path, "/run/udev/static_node-tags") < 0) {
2626 unlink_noerrno("/run/udev/static_node-tags");
2627 unlink_noerrno(path);
2628 return -errno;
2629 }
2630 }
2631
2632 return 0;
2633 }