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