]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/udev-rules.c
gtk-doc: delete empty files
[thirdparty/systemd.git] / udev / udev-rules.c
CommitLineData
2232cac8 1/*
5539f624 2 * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
023ed7b0 3 * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
2232cac8 4 *
55e9959b
KS
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
3d6d12c6 9 *
55e9959b
KS
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
2232cac8 14 *
55e9959b
KS
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2232cac8
GKH
17 */
18
19#include <stddef.h>
1449a55d 20#include <limits.h>
2232cac8 21#include <stdlib.h>
6d87ee2e 22#include <stdbool.h>
2232cac8
GKH
23#include <string.h>
24#include <stdio.h>
25#include <fcntl.h>
26#include <ctype.h>
27#include <unistd.h>
28#include <errno.h>
5ee7ecfb 29#include <dirent.h>
cea61f5c 30#include <fnmatch.h>
959e8b5d 31#include <time.h>
2232cac8 32
2232cac8 33#include "udev.h"
2232cac8 34
6880b25d
KS
35#define PREALLOC_TOKEN 2048
36#define PREALLOC_STRBUF 32 * 1024
1449a55d 37#define PREALLOC_TRIE 256
c7521974 38
4052400f
KS
39struct uid_gid {
40 unsigned int name_off;
41 union {
42 uid_t uid;
43 gid_t gid;
44 };
45};
46
1449a55d 47struct trie_node {
023ed7b0 48 /* this node's first child */
bcf44d55 49 unsigned int child_idx;
023ed7b0
KS
50 /* the next child of our parent node's child list */
51 unsigned int next_child_idx;
52 /* this node's last child (shortcut for append) */
bcf44d55 53 unsigned int last_child_idx;
1449a55d 54 unsigned int value_off;
bcf44d55 55 unsigned short value_len;
023ed7b0 56 unsigned char key;
1449a55d
AJ
57};
58
4052400f
KS
59struct udev_rules {
60 struct udev *udev;
61 int resolve_names;
62
63 /* every key in the rules file becomes a token */
64 struct token *tokens;
65 unsigned int token_cur;
66 unsigned int token_max;
67
68 /* all key strings are copied to a single string buffer */
69 char *buf;
70 size_t buf_cur;
71 size_t buf_max;
72 unsigned int buf_count;
73
bcf44d55 74 /* during rule parsing, strings are indexed to find duplicates */
bcf44d55
KS
75 struct trie_node *trie_nodes;
76 unsigned int trie_nodes_cur;
77 unsigned int trie_nodes_max;
1449a55d 78
bcf44d55 79 /* during rule parsing, uid/gid lookup results are cached */
4052400f
KS
80 struct uid_gid *uids;
81 unsigned int uids_cur;
82 unsigned int uids_max;
83 struct uid_gid *gids;
84 unsigned int gids_cur;
85 unsigned int gids_max;
86};
87
1449a55d 88/* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */
b0f7409f
KS
89enum operation_type {
90 OP_UNSET,
91
92 OP_MATCH,
93 OP_NOMATCH,
94 OP_MATCH_MAX,
95
96 OP_ADD,
97 OP_ASSIGN,
98 OP_ASSIGN_FINAL,
c7521974
KS
99};
100
ac218d9c
KS
101enum string_glob_type {
102 GL_UNSET,
db463fd3
KS
103 GL_PLAIN, /* no special chars */
104 GL_GLOB, /* shell globs ?,*,[] */
105 GL_SPLIT, /* multi-value A|B */
106 GL_SPLIT_GLOB, /* multi-value with glob A*|B* */
107 GL_SOMETHING, /* commonly used "?*" */
ac218d9c
KS
108};
109
32028733
KS
110enum string_subst_type {
111 SB_UNSET,
112 SB_NONE,
113 SB_FORMAT,
114 SB_SUBSYS,
115};
116
154a7b84 117/* tokens of a rule are sorted/handled in this order */
6880b25d 118enum token_type {
ac218d9c 119 TK_UNSET,
6880b25d
KS
120 TK_RULE,
121
6880b25d
KS
122 TK_M_ACTION, /* val */
123 TK_M_DEVPATH, /* val */
124 TK_M_KERNEL, /* val */
125 TK_M_DEVLINK, /* val */
126 TK_M_NAME, /* val */
127 TK_M_ENV, /* val, attr */
3f896a2a 128 TK_M_TAG, /* val */
6880b25d
KS
129 TK_M_SUBSYSTEM, /* val */
130 TK_M_DRIVER, /* val */
7aeeaedc 131 TK_M_WAITFOR, /* val */
6880b25d
KS
132 TK_M_ATTR, /* val, attr */
133
d15fcce4 134 TK_M_PARENTS_MIN,
6880b25d
KS
135 TK_M_KERNELS, /* val */
136 TK_M_SUBSYSTEMS, /* val */
137 TK_M_DRIVERS, /* val */
138 TK_M_ATTRS, /* val, attr */
7df0ed83 139 TK_M_TAGS, /* val */
b0f7409f 140 TK_M_PARENTS_MAX,
6880b25d
KS
141
142 TK_M_TEST, /* val, mode_t */
2181d30a 143 TK_M_EVENT_TIMEOUT, /* int */
6880b25d
KS
144 TK_M_PROGRAM, /* val */
145 TK_M_IMPORT_FILE, /* val */
146 TK_M_IMPORT_PROG, /* val */
5539f624 147 TK_M_IMPORT_DB, /* val */
c4f6dcc4 148 TK_M_IMPORT_CMDLINE, /* val */
6880b25d
KS
149 TK_M_IMPORT_PARENT, /* val */
150 TK_M_RESULT, /* val */
ac218d9c 151 TK_M_MAX,
6880b25d 152
6880b25d
KS
153 TK_A_STRING_ESCAPE_NONE,
154 TK_A_STRING_ESCAPE_REPLACE,
9ead6627 155 TK_A_DB_PERSIST,
46f194cb 156 TK_A_INOTIFY_WATCH, /* int */
6880b25d
KS
157 TK_A_DEVLINK_PRIO, /* int */
158 TK_A_OWNER, /* val */
159 TK_A_GROUP, /* val */
160 TK_A_MODE, /* val */
161 TK_A_OWNER_ID, /* uid_t */
162 TK_A_GROUP_ID, /* gid_t */
163 TK_A_MODE_ID, /* mode_t */
761dfddc 164 TK_A_STATIC_NODE, /* val */
6880b25d 165 TK_A_ENV, /* val, attr */
28460195 166 TK_A_TAG, /* val */
6880b25d
KS
167 TK_A_NAME, /* val */
168 TK_A_DEVLINK, /* val */
6880b25d
KS
169 TK_A_ATTR, /* val, attr */
170 TK_A_RUN, /* val, bool */
171 TK_A_GOTO, /* size_t */
6880b25d
KS
172
173 TK_END,
c7521974
KS
174};
175
3f3aa9f5 176/* we try to pack stuff in a way that we take only 12 bytes per token */
4052400f
KS
177struct token {
178 union {
761dfddc 179 unsigned char type; /* same in rule and key */
4052400f 180 struct {
a25d547d 181 enum token_type type:8;
761dfddc
KS
182 bool can_set_name:1;
183 bool has_static_node:1;
184 unsigned int unused:6;
3f3aa9f5 185 unsigned short token_count;
4052400f
KS
186 unsigned int label_off;
187 unsigned short filename_off;
188 unsigned short filename_line;
189 } rule;
190 struct {
a25d547d
KS
191 enum token_type type:8;
192 enum operation_type op:8;
193 enum string_glob_type glob:8;
32028733
KS
194 enum string_subst_type subst:4;
195 enum string_subst_type attrsubst:4;
4052400f
KS
196 unsigned int value_off;
197 union {
198 unsigned int attr_off;
6c29f2b9
KS
199 int devlink_unique;
200 int fail_on_error;
4052400f
KS
201 unsigned int rule_goto;
202 mode_t mode;
203 uid_t uid;
204 gid_t gid;
4052400f
KS
205 int devlink_prio;
206 int event_timeout;
46f194cb 207 int watch;
4052400f
KS
208 };
209 } key;
210 };
211};
212
213#define MAX_TK 64
214struct rule_tmp {
215 struct udev_rules *rules;
216 struct token rule;
217 struct token token[MAX_TK];
218 unsigned int token_cur;
219};
220
045a3bc8 221#ifdef ENABLE_DEBUG
5d6a1fa6
KS
222static const char *operation_str(enum operation_type type)
223{
224 static const char *operation_strs[] = {
225 [OP_UNSET] = "UNSET",
226 [OP_MATCH] = "match",
227 [OP_NOMATCH] = "nomatch",
228 [OP_MATCH_MAX] = "MATCH_MAX",
229
230 [OP_ADD] = "add",
231 [OP_ASSIGN] = "assign",
232 [OP_ASSIGN_FINAL] = "assign-final",
233} ;
234
235 return operation_strs[type];
236}
4052400f 237
5d6a1fa6
KS
238static const char *string_glob_str(enum string_glob_type type)
239{
240 static const char *string_glob_strs[] = {
241 [GL_UNSET] = "UNSET",
242 [GL_PLAIN] = "plain",
243 [GL_GLOB] = "glob",
244 [GL_SPLIT] = "split",
245 [GL_SPLIT_GLOB] = "split-glob",
246 [GL_SOMETHING] = "split-glob",
5d6a1fa6 247 };
4052400f 248
5d6a1fa6
KS
249 return string_glob_strs[type];
250}
251
252static const char *token_str(enum token_type type)
253{
254 static const char *token_strs[] = {
255 [TK_UNSET] = "UNSET",
256 [TK_RULE] = "RULE",
257
258 [TK_M_ACTION] = "M ACTION",
259 [TK_M_DEVPATH] = "M DEVPATH",
260 [TK_M_KERNEL] = "M KERNEL",
261 [TK_M_DEVLINK] = "M DEVLINK",
262 [TK_M_NAME] = "M NAME",
263 [TK_M_ENV] = "M ENV",
3f896a2a 264 [TK_M_TAG] = "M TAG",
5d6a1fa6
KS
265 [TK_M_SUBSYSTEM] = "M SUBSYSTEM",
266 [TK_M_DRIVER] = "M DRIVER",
267 [TK_M_WAITFOR] = "M WAITFOR",
268 [TK_M_ATTR] = "M ATTR",
269
270 [TK_M_PARENTS_MIN] = "M PARENTS_MIN",
271 [TK_M_KERNELS] = "M KERNELS",
272 [TK_M_SUBSYSTEMS] = "M SUBSYSTEMS",
273 [TK_M_DRIVERS] = "M DRIVERS",
274 [TK_M_ATTRS] = "M ATTRS",
7df0ed83 275 [TK_M_TAGS] = "M TAGS",
5d6a1fa6
KS
276 [TK_M_PARENTS_MAX] = "M PARENTS_MAX",
277
278 [TK_M_TEST] = "M TEST",
2181d30a 279 [TK_M_EVENT_TIMEOUT] = "M EVENT_TIMEOUT",
5d6a1fa6
KS
280 [TK_M_PROGRAM] = "M PROGRAM",
281 [TK_M_IMPORT_FILE] = "M IMPORT_FILE",
282 [TK_M_IMPORT_PROG] = "M IMPORT_PROG",
5539f624 283 [TK_M_IMPORT_DB] = "M IMPORT_DB",
c4f6dcc4 284 [TK_M_IMPORT_CMDLINE] = "M IMPORT_CMDLINE",
214a6c79 285 [TK_M_IMPORT_PARENT] = "M IMPORT_PARENT",
5d6a1fa6
KS
286 [TK_M_RESULT] = "M RESULT",
287 [TK_M_MAX] = "M MAX",
288
5d6a1fa6
KS
289 [TK_A_STRING_ESCAPE_NONE] = "A STRING_ESCAPE_NONE",
290 [TK_A_STRING_ESCAPE_REPLACE] = "A STRING_ESCAPE_REPLACE",
9ead6627 291 [TK_A_DB_PERSIST] = "A DB_PERSIST",
bd284db1 292 [TK_A_INOTIFY_WATCH] = "A INOTIFY_WATCH",
5d6a1fa6
KS
293 [TK_A_DEVLINK_PRIO] = "A DEVLINK_PRIO",
294 [TK_A_OWNER] = "A OWNER",
295 [TK_A_GROUP] = "A GROUP",
296 [TK_A_MODE] = "A MODE",
297 [TK_A_OWNER_ID] = "A OWNER_ID",
298 [TK_A_GROUP_ID] = "A GROUP_ID",
761dfddc 299 [TK_A_STATIC_NODE] = "A STATIC_NODE",
5d6a1fa6
KS
300 [TK_A_MODE_ID] = "A MODE_ID",
301 [TK_A_ENV] = "A ENV",
28460195 302 [TK_A_TAG] = "A ENV",
5d6a1fa6
KS
303 [TK_A_NAME] = "A NAME",
304 [TK_A_DEVLINK] = "A DEVLINK",
5d6a1fa6
KS
305 [TK_A_ATTR] = "A ATTR",
306 [TK_A_RUN] = "A RUN",
307 [TK_A_GOTO] = "A GOTO",
5d6a1fa6
KS
308
309 [TK_END] = "END",
310 };
311
312 return token_strs[type];
313}
c7521974 314
4052400f
KS
315static void dump_token(struct udev_rules *rules, struct token *token)
316{
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->buf[token->key.value_off];
321 const char *attr = &rules->buf[token->key.attr_off];
154a7b84 322
4052400f
KS
323 switch (type) {
324 case TK_RULE:
325 {
326 const char *tks_ptr = (char *)rules->tokens;
327 const char *tk_ptr = (char *)token;
5d6a1fa6 328 unsigned int idx = (tk_ptr - tks_ptr) / sizeof(struct token);
154a7b84 329
d80f8ffd 330 dbg(rules->udev, "* RULE %s:%u, token: %u, count: %u, label: '%s'\n",
4052400f 331 &rules->buf[token->rule.filename_off], token->rule.filename_line,
5d6a1fa6 332 idx, token->rule.token_count,
d80f8ffd 333 &rules->buf[token->rule.label_off]);
4052400f
KS
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:
7df0ed83 347 case TK_M_TAGS:
4052400f
KS
348 case TK_M_PROGRAM:
349 case TK_M_IMPORT_FILE:
350 case TK_M_IMPORT_PROG:
5539f624 351 case TK_M_IMPORT_DB:
c4f6dcc4 352 case TK_M_IMPORT_CMDLINE:
4052400f
KS
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:
361 dbg(rules->udev, "%s %s '%s'(%s)\n",
5d6a1fa6 362 token_str(type), operation_str(op), value, string_glob_str(glob));
4052400f
KS
363 break;
364 case TK_M_ATTR:
365 case TK_M_ATTRS:
366 case TK_M_ENV:
367 case TK_A_ATTR:
368 case TK_A_ENV:
369 dbg(rules->udev, "%s %s '%s' '%s'(%s)\n",
5d6a1fa6 370 token_str(type), operation_str(op), attr, value, string_glob_str(glob));
4052400f 371 break;
3f896a2a 372 case TK_M_TAG:
28460195
KS
373 case TK_A_TAG:
374 dbg(rules->udev, "%s %s '%s'\n", token_str(type), operation_str(op), value);
375 break;
4052400f
KS
376 case TK_A_STRING_ESCAPE_NONE:
377 case TK_A_STRING_ESCAPE_REPLACE:
9ead6627 378 case TK_A_DB_PERSIST:
5d69a34c
KS
379 dbg(rules->udev, "%s\n", token_str(type));
380 break;
4052400f
KS
381 case TK_M_TEST:
382 dbg(rules->udev, "%s %s '%s'(%s) %#o\n",
5d6a1fa6 383 token_str(type), operation_str(op), value, string_glob_str(glob), token->key.mode);
4052400f 384 break;
46f194cb 385 case TK_A_INOTIFY_WATCH:
2236ddae 386 dbg(rules->udev, "%s %u\n", token_str(type), token->key.watch);
46f194cb 387 break;
4052400f 388 case TK_A_DEVLINK_PRIO:
761dfddc 389 dbg(rules->udev, "%s %u\n", token_str(type), token->key.devlink_prio);
4052400f
KS
390 break;
391 case TK_A_OWNER_ID:
5d6a1fa6 392 dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.uid);
4052400f
KS
393 break;
394 case TK_A_GROUP_ID:
5d6a1fa6 395 dbg(rules->udev, "%s %s %u\n", token_str(type), operation_str(op), token->key.gid);
4052400f
KS
396 break;
397 case TK_A_MODE_ID:
5d6a1fa6 398 dbg(rules->udev, "%s %s %#o\n", token_str(type), operation_str(op), token->key.mode);
4052400f 399 break;
761dfddc
KS
400 case TK_A_STATIC_NODE:
401 dbg(rules->udev, "%s '%s'\n", token_str(type), value);
402 break;
2181d30a 403 case TK_M_EVENT_TIMEOUT:
761dfddc 404 dbg(rules->udev, "%s %u\n", token_str(type), token->key.event_timeout);
4052400f
KS
405 break;
406 case TK_A_GOTO:
5d6a1fa6 407 dbg(rules->udev, "%s '%s' %u\n", token_str(type), value, token->key.rule_goto);
4052400f
KS
408 break;
409 case TK_END:
5d6a1fa6 410 dbg(rules->udev, "* %s\n", token_str(type));
4052400f
KS
411 break;
412 case TK_M_PARENTS_MIN:
413 case TK_M_PARENTS_MAX:
414 case TK_M_MAX:
415 case TK_UNSET:
416 dbg(rules->udev, "unknown type %u\n", type);
417 break;
418 }
419}
154a7b84 420
4052400f
KS
421static void dump_rules(struct udev_rules *rules)
422{
423 unsigned int i;
154a7b84 424
4052400f
KS
425 dbg(rules->udev, "dumping %u (%zu bytes) tokens, %u (%zu bytes) strings\n",
426 rules->token_cur,
427 rules->token_cur * sizeof(struct token),
428 rules->buf_count,
429 rules->buf_cur);
430 for(i = 0; i < rules->token_cur; i++)
431 dump_token(rules, &rules->tokens[i]);
432}
433#else
5d6a1fa6
KS
434static inline const char *operation_str(enum operation_type type) { return NULL; }
435static inline const char *token_str(enum token_type type) { return NULL; }
4052400f
KS
436static inline void dump_token(struct udev_rules *rules, struct token *token) {}
437static inline void dump_rules(struct udev_rules *rules) {}
045a3bc8 438#endif /* ENABLE_DEBUG */
c7521974 439
1449a55d 440static int add_new_string(struct udev_rules *rules, const char *str, size_t bytes)
c7521974 441{
6880b25d 442 int off;
c7521974 443
34d6a259 444 /* grow buffer if needed */
1449a55d 445 if (rules->buf_cur + bytes+1 >= rules->buf_max) {
6880b25d
KS
446 char *buf;
447 unsigned int add;
c7521974 448
6880b25d
KS
449 /* double the buffer size */
450 add = rules->buf_max;
1449a55d
AJ
451 if (add < bytes * 8)
452 add = bytes * 8;
c7521974 453
6880b25d
KS
454 buf = realloc(rules->buf, rules->buf_max + add);
455 if (buf == NULL)
456 return -1;
86b57788 457 dbg(rules->udev, "extend buffer from %zu to %zu\n", rules->buf_max, rules->buf_max + add);
6880b25d
KS
458 rules->buf = buf;
459 rules->buf_max += add;
c7521974 460 }
6880b25d 461 off = rules->buf_cur;
1449a55d
AJ
462 memcpy(&rules->buf[rules->buf_cur], str, bytes);
463 rules->buf_cur += bytes;
6880b25d
KS
464 rules->buf_count++;
465 return off;
c7521974
KS
466}
467
1449a55d 468static int add_string(struct udev_rules *rules, const char *str)
c7521974 469{
bcf44d55
KS
470 unsigned int node_idx;
471 struct trie_node *new_node;
472 unsigned int new_node_idx;
1449a55d 473 unsigned char key;
bcf44d55 474 unsigned short len;
1c8af93a 475 unsigned int depth;
1449a55d 476 unsigned int off;
023ed7b0 477 struct trie_node *parent;
1449a55d 478
023ed7b0 479 /* walk trie, start from last character of str to find matching tails */
949075db 480 len = strlen(str);
023ed7b0 481 key = str[len-1];
949075db 482 node_idx = 0;
023ed7b0
KS
483 for (depth = 0; depth <= len; depth++) {
484 struct trie_node *node;
485 unsigned int child_idx;
486
487 node = &rules->trie_nodes[node_idx];
488 off = node->value_off + node->value_len - len;
489
490 /* match against current node */
491 if (depth == len || (node->value_len >= len && memcmp(&rules->buf[off], str, len) == 0))
492 return off;
493
494 /* lookup child node */
495 key = str[len - 1 - depth];
496 child_idx = node->child_idx;
497 while (child_idx > 0) {
498 struct trie_node *child;
499
500 child = &rules->trie_nodes[child_idx];
501 if (child->key == key)
1449a55d 502 break;
023ed7b0 503 child_idx = child->next_child_idx;
1449a55d 504 }
023ed7b0
KS
505 if (child_idx == 0)
506 break;
507 node_idx = child_idx;
1449a55d
AJ
508 }
509
510 /* string not found, add it */
511 off = add_new_string(rules, str, len + 1);
512
bcf44d55
KS
513 /* grow trie nodes if needed */
514 if (rules->trie_nodes_cur >= rules->trie_nodes_max) {
515 struct trie_node *nodes;
516 unsigned int add;
1449a55d
AJ
517
518 /* double the buffer size */
bcf44d55 519 add = rules->trie_nodes_max;
1449a55d
AJ
520 if (add < 8)
521 add = 8;
522
bcf44d55
KS
523 nodes = realloc(rules->trie_nodes, (rules->trie_nodes_max + add) * sizeof(struct trie_node));
524 if (nodes == NULL)
1449a55d 525 return -1;
bcf44d55
KS
526 dbg(rules->udev, "extend trie nodes from %u to %u\n",
527 rules->trie_nodes_max, rules->trie_nodes_max + add);
528 rules->trie_nodes = nodes;
529 rules->trie_nodes_max += add;
1449a55d
AJ
530 }
531
023ed7b0 532 /* get a new node */
bcf44d55
KS
533 new_node_idx = rules->trie_nodes_cur;
534 rules->trie_nodes_cur++;
535 new_node = &rules->trie_nodes[new_node_idx];
023ed7b0 536 memset(new_node, 0x00, sizeof(struct trie_node));
bcf44d55
KS
537 new_node->value_off = off;
538 new_node->value_len = len;
023ed7b0 539 new_node->key = key;
bcf44d55 540
023ed7b0
KS
541 /* join the parent's child list */
542 parent = &rules->trie_nodes[node_idx];
543 if (parent->child_idx == 0) {
544 parent->child_idx = new_node_idx;
bcf44d55 545 } else {
023ed7b0 546 struct trie_node *last_child;
1449a55d 547
023ed7b0
KS
548 last_child = &rules->trie_nodes[parent->last_child_idx];
549 last_child->next_child_idx = new_node_idx;
bcf44d55 550 }
023ed7b0 551 parent->last_child_idx = new_node_idx;
1449a55d
AJ
552 return off;
553}
554
555static int add_token(struct udev_rules *rules, struct token *token)
556{
34d6a259 557 /* grow buffer if needed */
6880b25d
KS
558 if (rules->token_cur+1 >= rules->token_max) {
559 struct token *tokens;
560 unsigned int add;
c7521974 561
6880b25d
KS
562 /* double the buffer size */
563 add = rules->token_max;
154a7b84
KS
564 if (add < 8)
565 add = 8;
c7521974 566
6880b25d
KS
567 tokens = realloc(rules->tokens, (rules->token_max + add ) * sizeof(struct token));
568 if (tokens == NULL)
569 return -1;
86b57788 570 dbg(rules->udev, "extend tokens from %u to %u\n", rules->token_max, rules->token_max + add);
6880b25d
KS
571 rules->tokens = tokens;
572 rules->token_max += add;
c7521974 573 }
6880b25d
KS
574 memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
575 rules->token_cur++;
576 return 0;
c7521974 577}
a27cd06c 578
154a7b84
KS
579static uid_t add_uid(struct udev_rules *rules, const char *owner)
580{
581 unsigned int i;
582 uid_t uid;
583 unsigned int off;
584
585 /* lookup, if we know it already */
586 for (i = 0; i < rules->uids_cur; i++) {
587 off = rules->uids[i].name_off;
588 if (strcmp(&rules->buf[off], owner) == 0) {
589 uid = rules->uids[i].uid;
590 dbg(rules->udev, "return existing %u for '%s'\n", uid, owner);
591 return uid;
592 }
593 }
594 uid = util_lookup_user(rules->udev, owner);
595
596 /* grow buffer if needed */
597 if (rules->uids_cur+1 >= rules->uids_max) {
598 struct uid_gid *uids;
599 unsigned int add;
600
601 /* double the buffer size */
602 add = rules->uids_max;
603 if (add < 1)
604 add = 8;
605
606 uids = realloc(rules->uids, (rules->uids_max + add ) * sizeof(struct uid_gid));
607 if (uids == NULL)
608 return uid;
86b57788 609 dbg(rules->udev, "extend uids from %u to %u\n", rules->uids_max, rules->uids_max + add);
154a7b84
KS
610 rules->uids = uids;
611 rules->uids_max += add;
612 }
613 rules->uids[rules->uids_cur].uid = uid;
614 off = add_string(rules, owner);
615 if (off <= 0)
616 return uid;
617 rules->uids[rules->uids_cur].name_off = off;
618 rules->uids_cur++;
619 return uid;
620}
621
622static gid_t add_gid(struct udev_rules *rules, const char *group)
623{
624 unsigned int i;
625 gid_t gid;
626 unsigned int off;
627
628 /* lookup, if we know it already */
629 for (i = 0; i < rules->gids_cur; i++) {
630 off = rules->gids[i].name_off;
631 if (strcmp(&rules->buf[off], group) == 0) {
632 gid = rules->gids[i].gid;
ac218d9c 633 dbg(rules->udev, "return existing %u for '%s'\n", gid, group);
154a7b84
KS
634 return gid;
635 }
636 }
637 gid = util_lookup_group(rules->udev, group);
638
639 /* grow buffer if needed */
640 if (rules->gids_cur+1 >= rules->gids_max) {
641 struct uid_gid *gids;
642 unsigned int add;
643
644 /* double the buffer size */
645 add = rules->gids_max;
646 if (add < 1)
647 add = 8;
648
649 gids = realloc(rules->gids, (rules->gids_max + add ) * sizeof(struct uid_gid));
650 if (gids == NULL)
651 return gid;
86b57788 652 dbg(rules->udev, "extend gids from %u to %u\n", rules->gids_max, rules->gids_max + add);
154a7b84
KS
653 rules->gids = gids;
654 rules->gids_max += add;
655 }
656 rules->gids[rules->gids_cur].gid = gid;
657 off = add_string(rules, group);
658 if (off <= 0)
659 return gid;
660 rules->gids[rules->gids_cur].name_off = off;
661 rules->gids_cur++;
662 return gid;
663}
664
bb144ed1 665static int import_property_from_string(struct udev_device *dev, char *line)
bd0ed2ff 666{
bb144ed1
KS
667 struct udev *udev = udev_device_get_udev(dev);
668 char *key;
669 char *val;
670 size_t len;
bd0ed2ff 671
bb144ed1
KS
672 /* find key */
673 key = line;
674 while (isspace(key[0]))
675 key++;
bd0ed2ff 676
bb144ed1
KS
677 /* comment or empty line */
678 if (key[0] == '#' || key[0] == '\0')
679 return -1;
16511863 680
bb144ed1
KS
681 /* split key/value */
682 val = strchr(key, '=');
683 if (val == NULL)
684 return -1;
685 val[0] = '\0';
686 val++;
aa8734ff 687
bb144ed1
KS
688 /* find value */
689 while (isspace(val[0]))
690 val++;
691
692 /* terminate key */
693 len = strlen(key);
694 if (len == 0)
695 return -1;
696 while (isspace(key[len-1]))
697 len--;
698 key[len] = '\0';
699
700 /* terminate value */
701 len = strlen(val);
702 if (len == 0)
703 return -1;
704 while (isspace(val[len-1]))
705 len--;
706 val[len] = '\0';
707
708 if (len == 0)
709 return -1;
710
711 /* unquote */
712 if (val[0] == '"' || val[0] == '\'') {
713 if (val[len-1] != val[0]) {
714 info(udev, "inconsistent quoting: '%s', skip\n", line);
715 return -1;
bd0ed2ff 716 }
bb144ed1
KS
717 val[len-1] = '\0';
718 val++;
719 }
720
86b57788 721 dbg(udev, "adding '%s'='%s'\n", key, val);
bb144ed1
KS
722
723 /* handle device, renamed by external tool, returning new path */
724 if (strcmp(key, "DEVPATH") == 0) {
725 char syspath[UTIL_PATH_SIZE];
726
727 info(udev, "updating devpath from '%s' to '%s'\n",
728 udev_device_get_devpath(dev), val);
065db052 729 util_strscpyl(syspath, sizeof(syspath), udev_get_sys_path(udev), val, NULL);
bb144ed1
KS
730 udev_device_set_syspath(dev, syspath);
731 } else {
732 struct udev_list_entry *entry;
733
734 entry = udev_device_add_property(dev, key, val);
b25a9454
KS
735 /* store in db, skip private keys */
736 if (key[0] != '.')
8958da13 737 udev_list_entry_set_num(entry, true);
bd0ed2ff 738 }
be4bedd1
KS
739 return 0;
740}
741
6880b25d 742static int import_file_into_properties(struct udev_device *dev, const char *filename)
be4bedd1 743{
bb144ed1
KS
744 FILE *f;
745 char line[UTIL_LINE_SIZE];
be4bedd1 746
bb144ed1
KS
747 f = fopen(filename, "r");
748 if (f == NULL)
be4bedd1 749 return -1;
fc42bd5d 750 while (fgets(line, sizeof(line), f) != NULL)
bb144ed1
KS
751 import_property_from_string(dev, line);
752 fclose(f);
be4bedd1 753 return 0;
bd0ed2ff
KS
754}
755
2181d30a 756static int import_program_into_properties(struct udev_event *event, const char *program, const sigset_t *sigmask)
319c6700 757{
2181d30a 758 struct udev_device *dev = event->dev;
d0db192f 759 char **envp;
851dd4dd 760 char result[UTIL_LINE_SIZE];
bb144ed1 761 char *line;
2181d30a 762 int err;
319c6700 763
d0db192f 764 envp = udev_device_get_properties_envp(dev);
2181d30a
KS
765 err = udev_event_spawn(event, program, envp, sigmask, result, sizeof(result));
766 if (err < 0)
767 return err;
bb144ed1
KS
768
769 line = result;
770 while (line != NULL) {
771 char *pos;
772
773 pos = strchr(line, '\n');
774 if (pos != NULL) {
775 pos[0] = '\0';
776 pos = &pos[1];
777 }
778 import_property_from_string(dev, line);
779 line = pos;
780 }
781 return 0;
319c6700
KS
782}
783
6880b25d 784static int import_parent_into_properties(struct udev_device *dev, const char *filter)
0bfb84e1 785{
bb144ed1 786 struct udev *udev = udev_device_get_udev(dev);
aa8734ff
KS
787 struct udev_device *dev_parent;
788 struct udev_list_entry *list_entry;
0bfb84e1 789
bb144ed1 790 dev_parent = udev_device_get_parent(dev);
aa8734ff
KS
791 if (dev_parent == NULL)
792 return -1;
0bfb84e1 793
bb144ed1 794 dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
aa8734ff
KS
795 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) {
796 const char *key = udev_list_entry_get_name(list_entry);
797 const char *val = udev_list_entry_get_value(list_entry);
0bfb84e1 798
aa8734ff
KS
799 if (fnmatch(filter, key, 0) == 0) {
800 struct udev_list_entry *entry;
e2ecb34f 801
bb144ed1
KS
802 dbg(udev, "import key '%s=%s'\n", key, val);
803 entry = udev_device_add_property(dev, key, val);
b25a9454
KS
804 /* store in db, skip private keys */
805 if (key[0] != '.')
8958da13 806 udev_list_entry_set_num(entry, true);
aa8734ff 807 }
e2ecb34f 808 }
aa8734ff 809 return 0;
e2ecb34f
KS
810}
811
c86be870 812#define WAIT_LOOP_PER_SECOND 50
6880b25d 813static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
b2fe4b9a 814{
6880b25d 815 struct udev *udev = udev_device_get_udev(dev);
17fcfb59 816 char filepath[UTIL_PATH_SIZE];
1822e9b0 817 char devicepath[UTIL_PATH_SIZE];
b2fe4b9a
KS
818 struct stat stats;
819 int loop = timeout * WAIT_LOOP_PER_SECOND;
820
ea97dc37 821 /* a relative path is a device attribute */
1822e9b0 822 devicepath[0] = '\0';
ea97dc37 823 if (file[0] != '/') {
065db052
KS
824 util_strscpyl(devicepath, sizeof(devicepath),
825 udev_get_sys_path(udev), udev_device_get_devpath(dev), NULL);
826 util_strscpyl(filepath, sizeof(filepath), devicepath, "/", file, NULL);
ea97dc37
KS
827 file = filepath;
828 }
829
6880b25d 830 dbg(udev, "will wait %i sec for '%s'\n", timeout, file);
b2fe4b9a 831 while (--loop) {
959e8b5d
DM
832 const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND };
833
656ba91e 834 /* lookup file */
ea97dc37 835 if (stat(file, &stats) == 0) {
6880b25d 836 info(udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
b2fe4b9a
KS
837 return 0;
838 }
eb5b8640 839 /* make sure, the device did not disappear in the meantime */
ea97dc37 840 if (devicepath[0] != '\0' && stat(devicepath, &stats) != 0) {
6880b25d 841 info(udev, "device disappeared while waiting for '%s'\n", file);
656ba91e
KS
842 return -2;
843 }
6880b25d 844 info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
959e8b5d 845 nanosleep(&duration, NULL);
b2fe4b9a 846 }
6880b25d 847 info(udev, "waiting for '%s' failed\n", file);
b2fe4b9a
KS
848 return -1;
849}
850
0ea5e96e
KS
851static int attr_subst_subdir(char *attr, size_t len)
852{
761dfddc 853 bool found = false;
0ea5e96e 854
065db052
KS
855 if (strstr(attr, "/*/")) {
856 char *pos;
857 char dirname[UTIL_PATH_SIZE];
858 const char *tail;
0ea5e96e
KS
859 DIR *dir;
860
065db052
KS
861 util_strscpy(dirname, sizeof(dirname), attr);
862 pos = strstr(dirname, "/*/");
863 if (pos == NULL)
864 return -1;
865 pos[0] = '\0';
866 tail = &pos[2];
867 dir = opendir(dirname);
0ea5e96e
KS
868 if (dir != NULL) {
869 struct dirent *dent;
870
871 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
872 struct stat stats;
873
874 if (dent->d_name[0] == '.')
875 continue;
065db052 876 util_strscpyl(attr, len, dirname, "/", dent->d_name, tail, NULL);
0ea5e96e 877 if (stat(attr, &stats) == 0) {
761dfddc 878 found = true;
0ea5e96e
KS
879 break;
880 }
0ea5e96e
KS
881 }
882 closedir(dir);
883 }
0ea5e96e
KS
884 }
885
886 return found;
887}
888
b0f7409f 889static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value)
a0e5382d 890{
6880b25d
KS
891 char *linepos;
892 char *temp;
a0e5382d 893
6880b25d 894 linepos = *line;
9257ecfc 895 if (linepos == NULL || linepos[0] == '\0')
6880b25d 896 return -1;
a0e5382d 897
6880b25d
KS
898 /* skip whitespace */
899 while (isspace(linepos[0]) || linepos[0] == ',')
900 linepos++;
aa8734ff 901
6880b25d
KS
902 /* get the key */
903 if (linepos[0] == '\0')
904 return -1;
905 *key = linepos;
81313e1b 906
88cbfb09 907 for (;;) {
6880b25d
KS
908 linepos++;
909 if (linepos[0] == '\0')
910 return -1;
911 if (isspace(linepos[0]))
81313e1b 912 break;
6880b25d
KS
913 if (linepos[0] == '=')
914 break;
915 if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':'))
916 if (linepos[1] == '=')
1ff1aa42 917 break;
953249a3
KS
918 }
919
6880b25d
KS
920 /* remember end of key */
921 temp = linepos;
b2fe4b9a 922
6880b25d
KS
923 /* skip whitespace after key */
924 while (isspace(linepos[0]))
925 linepos++;
926 if (linepos[0] == '\0')
927 return -1;
b2fe4b9a 928
6880b25d
KS
929 /* get operation type */
930 if (linepos[0] == '=' && linepos[1] == '=') {
b0f7409f 931 *op = OP_MATCH;
6880b25d
KS
932 linepos += 2;
933 } else if (linepos[0] == '!' && linepos[1] == '=') {
b0f7409f 934 *op = OP_NOMATCH;
6880b25d
KS
935 linepos += 2;
936 } else if (linepos[0] == '+' && linepos[1] == '=') {
b0f7409f 937 *op = OP_ADD;
6880b25d
KS
938 linepos += 2;
939 } else if (linepos[0] == '=') {
b0f7409f 940 *op = OP_ASSIGN;
6880b25d
KS
941 linepos++;
942 } else if (linepos[0] == ':' && linepos[1] == '=') {
b0f7409f 943 *op = OP_ASSIGN_FINAL;
6880b25d
KS
944 linepos += 2;
945 } else
946 return -1;
d0c8cb7d 947
6880b25d
KS
948 /* terminate key */
949 temp[0] = '\0';
95776dc6 950
6880b25d
KS
951 /* skip whitespace after operator */
952 while (isspace(linepos[0]))
953 linepos++;
954 if (linepos[0] == '\0')
955 return -1;
aa8734ff 956
ac218d9c 957 /* get the value */
6880b25d
KS
958 if (linepos[0] == '"')
959 linepos++;
960 else
961 return -1;
962 *value = linepos;
aa8734ff 963
ac218d9c 964 /* terminate */
6880b25d
KS
965 temp = strchr(linepos, '"');
966 if (!temp)
967 return -1;
968 temp[0] = '\0';
969 temp++;
5d6a1fa6 970 dbg(udev, "%s '%s'-'%s'\n", operation_str(*op), *key, *value);
aa8734ff 971
6880b25d
KS
972 /* move line to next key */
973 *line = temp;
974 return 0;
975}
95776dc6 976
6880b25d
KS
977/* extract possible KEY{attr} */
978static char *get_key_attribute(struct udev *udev, char *str)
979{
980 char *pos;
981 char *attr;
95776dc6 982
6880b25d
KS
983 attr = strchr(str, '{');
984 if (attr != NULL) {
985 attr++;
986 pos = strchr(attr, '}');
987 if (pos == NULL) {
988 err(udev, "missing closing brace for format\n");
989 return NULL;
95776dc6 990 }
6880b25d
KS
991 pos[0] = '\0';
992 dbg(udev, "attribute='%s'\n", attr);
993 return attr;
95776dc6 994 }
6880b25d
KS
995 return NULL;
996}
95776dc6 997
0ef254d5
KS
998static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
999 enum operation_type op,
1000 const char *value, const void *data)
6880b25d
KS
1001{
1002 struct token *token = &rule_tmp->token[rule_tmp->token_cur];
32028733 1003 const char *attr = NULL;
ac218d9c
KS
1004
1005 memset(token, 0x00, sizeof(struct token));
6880b25d
KS
1006
1007 switch (type) {
6880b25d
KS
1008 case TK_M_ACTION:
1009 case TK_M_DEVPATH:
1010 case TK_M_KERNEL:
1011 case TK_M_SUBSYSTEM:
1012 case TK_M_DRIVER:
7aeeaedc 1013 case TK_M_WAITFOR:
6880b25d
KS
1014 case TK_M_DEVLINK:
1015 case TK_M_NAME:
1016 case TK_M_KERNELS:
1017 case TK_M_SUBSYSTEMS:
1018 case TK_M_DRIVERS:
7df0ed83 1019 case TK_M_TAGS:
6880b25d
KS
1020 case TK_M_PROGRAM:
1021 case TK_M_IMPORT_FILE:
1022 case TK_M_IMPORT_PROG:
5539f624 1023 case TK_M_IMPORT_DB:
c4f6dcc4 1024 case TK_M_IMPORT_CMDLINE:
6880b25d
KS
1025 case TK_M_IMPORT_PARENT:
1026 case TK_M_RESULT:
1027 case TK_A_OWNER:
1028 case TK_A_GROUP:
1029 case TK_A_MODE:
1030 case TK_A_NAME:
6880b25d 1031 case TK_A_GOTO:
3f896a2a 1032 case TK_M_TAG:
28460195 1033 case TK_A_TAG:
6880b25d 1034 token->key.value_off = add_string(rule_tmp->rules, value);
e57e7bc1 1035 break;
6880b25d
KS
1036 case TK_M_ENV:
1037 case TK_M_ATTR:
1038 case TK_M_ATTRS:
1039 case TK_A_ATTR:
1040 case TK_A_ENV:
32028733 1041 attr = data;
6880b25d
KS
1042 token->key.value_off = add_string(rule_tmp->rules, value);
1043 token->key.attr_off = add_string(rule_tmp->rules, attr);
1044 break;
6c29f2b9
KS
1045 case TK_A_DEVLINK:
1046 token->key.value_off = add_string(rule_tmp->rules, value);
1047 token->key.devlink_unique = *(int *)data;
1048 break;
6880b25d 1049 case TK_M_TEST:
6880b25d 1050 token->key.value_off = add_string(rule_tmp->rules, value);
ac218d9c
KS
1051 if (data != NULL)
1052 token->key.mode = *(mode_t *)data;
6880b25d 1053 break;
6880b25d
KS
1054 case TK_A_STRING_ESCAPE_NONE:
1055 case TK_A_STRING_ESCAPE_REPLACE:
9ead6627 1056 case TK_A_DB_PERSIST:
5d69a34c 1057 break;
6880b25d
KS
1058 case TK_A_RUN:
1059 token->key.value_off = add_string(rule_tmp->rules, value);
6c29f2b9 1060 token->key.fail_on_error = *(int *)data;
6880b25d 1061 break;
46f194cb 1062 case TK_A_INOTIFY_WATCH:
6880b25d
KS
1063 case TK_A_DEVLINK_PRIO:
1064 token->key.devlink_prio = *(int *)data;
1065 break;
1066 case TK_A_OWNER_ID:
1067 token->key.uid = *(uid_t *)data;
1068 break;
1069 case TK_A_GROUP_ID:
1070 token->key.gid = *(gid_t *)data;
1071 break;
1072 case TK_A_MODE_ID:
1073 token->key.mode = *(mode_t *)data;
1074 break;
761dfddc
KS
1075 case TK_A_STATIC_NODE:
1076 token->key.value_off = add_string(rule_tmp->rules, value);
1077 break;
2181d30a 1078 case TK_M_EVENT_TIMEOUT:
6880b25d
KS
1079 token->key.event_timeout = *(int *)data;
1080 break;
1081 case TK_RULE:
d15fcce4 1082 case TK_M_PARENTS_MIN:
b0f7409f 1083 case TK_M_PARENTS_MAX:
ac218d9c 1084 case TK_M_MAX:
6880b25d 1085 case TK_END:
ac218d9c 1086 case TK_UNSET:
6880b25d
KS
1087 err(rule_tmp->rules->udev, "wrong type %u\n", type);
1088 return -1;
724257d9 1089 }
ac218d9c 1090
fb045134
KS
1091 if (value != NULL && type < TK_M_MAX) {
1092 /* check if we need to split or call fnmatch() while matching rules */
32028733 1093 enum string_glob_type glob;
fb045134
KS
1094 int has_split;
1095 int has_glob;
1096
1097 has_split = (strchr(value, '|') != NULL);
32028733 1098 has_glob = (strchr(value, '*') != NULL || strchr(value, '?') != NULL || strchr(value, '[') != NULL);
fb045134
KS
1099 if (has_split && has_glob) {
1100 glob = GL_SPLIT_GLOB;
1101 } else if (has_split) {
1102 glob = GL_SPLIT;
1103 } else if (has_glob) {
1104 if (strcmp(value, "?*") == 0)
1105 glob = GL_SOMETHING;
1106 else
1107 glob = GL_GLOB;
32028733
KS
1108 } else {
1109 glob = GL_PLAIN;
ac218d9c 1110 }
32028733
KS
1111 token->key.glob = glob;
1112 }
1113
1114 if (value != NULL && type > TK_M_MAX) {
1115 /* check if assigned value has substitution chars */
1116 if (value[0] == '[')
1117 token->key.subst = SB_SUBSYS;
1118 else if (strchr(value, '%') != NULL || strchr(value, '$') != NULL)
1119 token->key.subst = SB_FORMAT;
1120 else
1121 token->key.subst = SB_NONE;
1122 }
1123
1124 if (attr != NULL) {
1125 /* check if property/attribut name has substitution chars */
1126 if (attr[0] == '[')
1127 token->key.attrsubst = SB_SUBSYS;
1128 else if (strchr(attr, '%') != NULL || strchr(attr, '$') != NULL)
1129 token->key.attrsubst = SB_FORMAT;
1130 else
1131 token->key.attrsubst = SB_NONE;
ac218d9c
KS
1132 }
1133
0ef254d5 1134 token->key.type = type;
6880b25d
KS
1135 token->key.op = op;
1136 rule_tmp->token_cur++;
1137 if (rule_tmp->token_cur >= ARRAY_SIZE(rule_tmp->token)) {
1138 err(rule_tmp->rules->udev, "temporary rule array too small\n");
1139 return -1;
e57e7bc1 1140 }
6880b25d
KS
1141 return 0;
1142}
e57e7bc1 1143
6880b25d
KS
1144static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp)
1145{
1146 unsigned int i;
1147 unsigned int start = 0;
1148 unsigned int end = rule_tmp->token_cur;
1149
1150 for (i = 0; i < rule_tmp->token_cur; i++) {
ac218d9c 1151 enum token_type next_val = TK_UNSET;
78715f65 1152 unsigned int next_idx = 0;
6880b25d
KS
1153 unsigned int j;
1154
1155 /* find smallest value */
1156 for (j = start; j < end; j++) {
ac218d9c 1157 if (rule_tmp->token[j].type == TK_UNSET)
6880b25d 1158 continue;
ac218d9c 1159 if (next_val == TK_UNSET || rule_tmp->token[j].type < next_val) {
6880b25d
KS
1160 next_val = rule_tmp->token[j].type;
1161 next_idx = j;
db6e59df 1162 }
5618b561 1163 }
5618b561 1164
6880b25d
KS
1165 /* add token and mark done */
1166 if (add_token(rules, &rule_tmp->token[next_idx]) != 0)
1167 return -1;
ac218d9c 1168 rule_tmp->token[next_idx].type = TK_UNSET;
956cf793 1169
6880b25d
KS
1170 /* shrink range */
1171 if (next_idx == start)
1172 start++;
1173 if (next_idx+1 == end)
1174 end--;
d0c8cb7d 1175 }
e57e7bc1 1176 return 0;
724257d9
GKH
1177}
1178
6880b25d
KS
1179static int add_rule(struct udev_rules *rules, char *line,
1180 const char *filename, unsigned int filename_off, unsigned int lineno)
724257d9 1181{
6880b25d
KS
1182 char *linepos;
1183 char *attr;
6880b25d 1184 struct rule_tmp rule_tmp;
6d87ee2e
KS
1185 bool bus_warn = false;
1186 bool sysfs_warn = false;
1187 bool id_warn = false;
724257d9 1188
6880b25d
KS
1189 memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
1190 rule_tmp.rules = rules;
1191 rule_tmp.rule.type = TK_RULE;
1192 rule_tmp.rule.rule.filename_off = filename_off;
0ef254d5 1193 rule_tmp.rule.rule.filename_line = lineno;
724257d9 1194
6880b25d 1195 linepos = line;
88cbfb09 1196 for (;;) {
6880b25d
KS
1197 char *key;
1198 char *value;
ac218d9c 1199 enum operation_type op;
6880b25d
KS
1200
1201 if (get_key(rules->udev, &linepos, &key, &op, &value) != 0)
6bf0ffe8
KS
1202 break;
1203
bd75fddb 1204 if (strcmp(key, "ACTION") == 0) {
b0f7409f 1205 if (op > OP_MATCH_MAX) {
6880b25d
KS
1206 err(rules->udev, "invalid ACTION operation\n");
1207 goto invalid;
1208 }
0ef254d5 1209 rule_add_key(&rule_tmp, TK_M_ACTION, op, value, NULL);
bf5d2964
KS
1210 continue;
1211 }
1212
bd75fddb 1213 if (strcmp(key, "DEVPATH") == 0) {
b0f7409f 1214 if (op > OP_MATCH_MAX) {
6880b25d
KS
1215 err(rules->udev, "invalid DEVPATH operation\n");
1216 goto invalid;
fd9efc00 1217 }
0ef254d5 1218 rule_add_key(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
6880b25d
KS
1219 continue;
1220 }
c7521974 1221
bd75fddb 1222 if (strcmp(key, "KERNEL") == 0) {
b0f7409f 1223 if (op > OP_MATCH_MAX) {
c7521974
KS
1224 err(rules->udev, "invalid KERNEL operation\n");
1225 goto invalid;
1226 }
0ef254d5 1227 rule_add_key(&rule_tmp, TK_M_KERNEL, op, value, NULL);
c7521974
KS
1228 continue;
1229 }
1230
bd75fddb 1231 if (strcmp(key, "SUBSYSTEM") == 0) {
b0f7409f 1232 if (op > OP_MATCH_MAX) {
c7521974
KS
1233 err(rules->udev, "invalid SUBSYSTEM operation\n");
1234 goto invalid;
1235 }
1236 /* bus, class, subsystem events should all be the same */
1237 if (strcmp(value, "subsystem") == 0 ||
1238 strcmp(value, "bus") == 0 ||
1239 strcmp(value, "class") == 0) {
1240 if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
1241 err(rules->udev, "'%s' must be specified as 'subsystem' \n"
1242 "please fix it in %s:%u", value, filename, lineno);
0ef254d5 1243 rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL);
c7521974 1244 } else
0ef254d5 1245 rule_add_key(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL);
c7521974
KS
1246 continue;
1247 }
1248
bd75fddb 1249 if (strcmp(key, "DRIVER") == 0) {
b0f7409f 1250 if (op > OP_MATCH_MAX) {
c7521974
KS
1251 err(rules->udev, "invalid DRIVER operation\n");
1252 goto invalid;
1253 }
0ef254d5 1254 rule_add_key(&rule_tmp, TK_M_DRIVER, op, value, NULL);
c7521974
KS
1255 continue;
1256 }
1257
bd75fddb 1258 if (strncmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
6880b25d 1259 attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1);
c7521974
KS
1260 if (attr == NULL) {
1261 err(rules->udev, "error parsing ATTR attribute\n");
1262 goto invalid;
1263 }
b0f7409f 1264 if (op < OP_MATCH_MAX) {
0ef254d5 1265 rule_add_key(&rule_tmp, TK_M_ATTR, op, value, attr);
6880b25d 1266 } else {
0ef254d5 1267 rule_add_key(&rule_tmp, TK_A_ATTR, op, value, attr);
6880b25d 1268 }
c7521974
KS
1269 continue;
1270 }
1271
6d87ee2e 1272 if (strcmp(key, "KERNELS") == 0) {
b0f7409f 1273 if (op > OP_MATCH_MAX) {
c7521974
KS
1274 err(rules->udev, "invalid KERNELS operation\n");
1275 goto invalid;
1276 }
0ef254d5 1277 rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
c7521974
KS
1278 continue;
1279 }
1280
6d87ee2e
KS
1281 if (strcmp(key, "ID") == 0) {
1282 if (!id_warn) {
1283 id_warn = true;
1284 err(rules->udev, "ID= will be removed in a future udev version, "
1285 "please use KERNEL= to match the event device, or KERNELS= "
1286 "to match a parent device, in %s:%u\n", filename, lineno);
1287 }
1288 if (op > OP_MATCH_MAX) {
1289 err(rules->udev, "invalid KERNELS operation\n");
1290 goto invalid;
1291 }
1292 rule_add_key(&rule_tmp, TK_M_KERNELS, op, value, NULL);
1293 continue;
1294 }
1295
1296 if (strcmp(key, "SUBSYSTEMS") == 0) {
1297 if (op > OP_MATCH_MAX) {
1298 err(rules->udev, "invalid SUBSYSTEMS operation\n");
1299 goto invalid;
1300 }
1301 rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
1302 continue;
1303 }
1304
1305 if (strcmp(key, "BUS") == 0) {
1306 if (!bus_warn) {
1307 bus_warn = true;
1308 err(rules->udev, "BUS= will be removed in a future udev version, "
1309 "please use SUBSYSTEM= to match the event device, or SUBSYSTEMS= "
1310 "to match a parent device, in %s:%u\n", filename, lineno);
1311 }
b0f7409f 1312 if (op > OP_MATCH_MAX) {
c7521974
KS
1313 err(rules->udev, "invalid SUBSYSTEMS operation\n");
1314 goto invalid;
1315 }
0ef254d5 1316 rule_add_key(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
c7521974
KS
1317 continue;
1318 }
1319
bd75fddb 1320 if (strcmp(key, "DRIVERS") == 0) {
b0f7409f 1321 if (op > OP_MATCH_MAX) {
c7521974
KS
1322 err(rules->udev, "invalid DRIVERS operation\n");
1323 goto invalid;
1324 }
0ef254d5 1325 rule_add_key(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
c7521974
KS
1326 continue;
1327 }
1328
6d87ee2e 1329 if (strncmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0) {
b0f7409f 1330 if (op > OP_MATCH_MAX) {
c7521974
KS
1331 err(rules->udev, "invalid ATTRS operation\n");
1332 goto invalid;
1333 }
6880b25d 1334 attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
c7521974
KS
1335 if (attr == NULL) {
1336 err(rules->udev, "error parsing ATTRS attribute\n");
1337 goto invalid;
1338 }
1339 if (strncmp(attr, "device/", 7) == 0)
1340 err(rules->udev, "the 'device' link may not be available in a future kernel, "
1341 "please fix it in %s:%u", filename, lineno);
1342 else if (strstr(attr, "../") != NULL)
1343 err(rules->udev, "do not reference parent sysfs directories directly, "
1344 "it may break with a future kernel, please fix it in %s:%u", filename, lineno);
0ef254d5 1345 rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
c7521974
KS
1346 continue;
1347 }
1348
7df0ed83
KS
1349 if (strcmp(key, "TAGS") == 0) {
1350 if (op > OP_MATCH_MAX) {
1351 err(rules->udev, "invalid TAGS operation\n");
1352 goto invalid;
1353 }
1354 rule_add_key(&rule_tmp, TK_M_TAGS, op, value, NULL);
1355 continue;
1356 }
1357
6d87ee2e
KS
1358 if (strncmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
1359 if (!sysfs_warn) {
1360 sysfs_warn = true;
1361 err(rules->udev, "SYSFS{}= will be removed in a future udev version, "
1362 "please use ATTR{}= to match the event device, or ATTRS{}= "
1363 "to match a parent device, in %s:%u\n", filename, lineno);
1364 }
1365 if (op > OP_MATCH_MAX) {
1366 err(rules->udev, "invalid ATTRS operation\n");
1367 goto invalid;
1368 }
1369 attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
1370 if (attr == NULL) {
1371 err(rules->udev, "error parsing ATTRS attribute\n");
1372 goto invalid;
1373 }
1374 rule_add_key(&rule_tmp, TK_M_ATTRS, op, value, attr);
1375 continue;
1376 }
1377
bd75fddb 1378 if (strncmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
6880b25d 1379 attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
c7521974
KS
1380 if (attr == NULL) {
1381 err(rules->udev, "error parsing ENV attribute\n");
1382 goto invalid;
1383 }
b0f7409f 1384 if (op < OP_MATCH_MAX) {
0ef254d5 1385 if (rule_add_key(&rule_tmp, TK_M_ENV, op, value, attr) != 0)
6880b25d
KS
1386 goto invalid;
1387 } else {
ace6bfa7
KS
1388 static const char *blacklist[] = {
1389 "ACTION",
1390 "SUBSYSTEM",
1391 "DEVTYPE",
1392 "MAJOR",
1393 "MINOR",
1394 "DRIVER",
1395 "IFINDEX",
1396 "DEVNAME",
1397 "DEVLINKS",
1398 "DEVPATH",
1399 "TAGS",
1400 };
1401 unsigned int i;
1402
1403 for (i = 0; i < ARRAY_SIZE(blacklist); i++)
1404 if (strcmp(attr, blacklist[i]) == 0) {
1405 err(rules->udev, "invalid ENV attribute, '%s' can not be set %s:%u\n", attr, filename, lineno);
1406 continue;
1407 }
0ef254d5 1408 if (rule_add_key(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
6880b25d
KS
1409 goto invalid;
1410 }
c7521974
KS
1411 continue;
1412 }
1413
28460195 1414 if (strcmp(key, "TAG") == 0) {
3f896a2a
KS
1415 if (op < OP_MATCH_MAX)
1416 rule_add_key(&rule_tmp, TK_M_TAG, op, value, NULL);
1417 else
1418 rule_add_key(&rule_tmp, TK_A_TAG, op, value, NULL);
28460195
KS
1419 continue;
1420 }
1421
bd75fddb 1422 if (strcmp(key, "PROGRAM") == 0) {
0ef254d5 1423 rule_add_key(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
c7521974
KS
1424 continue;
1425 }
1426
bd75fddb 1427 if (strcmp(key, "RESULT") == 0) {
b0f7409f 1428 if (op > OP_MATCH_MAX) {
c7521974
KS
1429 err(rules->udev, "invalid RESULT operation\n");
1430 goto invalid;
1431 }
0ef254d5 1432 rule_add_key(&rule_tmp, TK_M_RESULT, op, value, NULL);
c7521974
KS
1433 continue;
1434 }
1435
bd75fddb 1436 if (strncmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
6880b25d 1437 attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1);
c7521974
KS
1438 if (attr != NULL && strstr(attr, "program")) {
1439 dbg(rules->udev, "IMPORT will be executed\n");
0ef254d5 1440 rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
c7521974
KS
1441 } else if (attr != NULL && strstr(attr, "file")) {
1442 dbg(rules->udev, "IMPORT will be included as file\n");
0ef254d5 1443 rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
5539f624
KS
1444 } else if (attr != NULL && strstr(attr, "db")) {
1445 dbg(rules->udev, "IMPORT will include db values\n");
1446 rule_add_key(&rule_tmp, TK_M_IMPORT_DB, op, value, NULL);
c4f6dcc4
KS
1447 } else if (attr != NULL && strstr(attr, "cmdline")) {
1448 dbg(rules->udev, "IMPORT will include db values\n");
1449 rule_add_key(&rule_tmp, TK_M_IMPORT_CMDLINE, op, value, NULL);
c7521974
KS
1450 } else if (attr != NULL && strstr(attr, "parent")) {
1451 dbg(rules->udev, "IMPORT will include the parent values\n");
0ef254d5 1452 rule_add_key(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
c7521974
KS
1453 } else {
1454 /* figure it out if it is executable */
1455 char file[UTIL_PATH_SIZE];
1456 char *pos;
1457 struct stat statbuf;
1458
065db052
KS
1459 /* allow programs in /lib/udev called without the path */
1460 if (value[0] != '/')
6133f343 1461 util_strscpyl(file, sizeof(file), LIBEXECDIR "/", value, NULL);
065db052
KS
1462 else
1463 util_strscpy(file, sizeof(file), value);
c7521974
KS
1464 pos = strchr(file, ' ');
1465 if (pos)
1466 pos[0] = '\0';
c7521974 1467 dbg(rules->udev, "IMPORT auto mode for '%s'\n", file);
065db052 1468 if (stat(file, &statbuf) == 0 && (statbuf.st_mode & S_IXUSR)) {
6880b25d 1469 dbg(rules->udev, "IMPORT will be executed (autotype)\n");
0ef254d5 1470 rule_add_key(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
c7521974 1471 } else {
6880b25d 1472 dbg(rules->udev, "IMPORT will be included as file (autotype)\n");
0ef254d5 1473 rule_add_key(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
c7521974
KS
1474 }
1475 }
c7521974
KS
1476 continue;
1477 }
1478
bd75fddb 1479 if (strncmp(key, "TEST", sizeof("TEST")-1) == 0) {
6880b25d
KS
1480 mode_t mode = 0;
1481
b0f7409f 1482 if (op > OP_MATCH_MAX) {
c7521974
KS
1483 err(rules->udev, "invalid TEST operation\n");
1484 goto invalid;
1485 }
6880b25d
KS
1486 attr = get_key_attribute(rules->udev, key + sizeof("TEST")-1);
1487 if (attr != NULL) {
1488 mode = strtol(attr, NULL, 8);
0ef254d5 1489 rule_add_key(&rule_tmp, TK_M_TEST, op, value, &mode);
6880b25d 1490 } else {
0ef254d5 1491 rule_add_key(&rule_tmp, TK_M_TEST, op, value, NULL);
6880b25d 1492 }
c7521974
KS
1493 continue;
1494 }
1495
bd75fddb 1496 if (strncmp(key, "RUN", sizeof("RUN")-1) == 0) {
6880b25d
KS
1497 int flag = 0;
1498
1499 attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1);
16dd0aa9 1500 if (attr != NULL && strstr(attr, "fail_event_on_error"))
6880b25d 1501 flag = 1;
0ef254d5 1502 rule_add_key(&rule_tmp, TK_A_RUN, op, value, &flag);
c7521974
KS
1503 continue;
1504 }
1505
bd75fddb 1506 if (strcmp(key, "WAIT_FOR") == 0 || strcmp(key, "WAIT_FOR_SYSFS") == 0) {
0ef254d5 1507 rule_add_key(&rule_tmp, TK_M_WAITFOR, 0, value, NULL);
c7521974
KS
1508 continue;
1509 }
1510
bd75fddb 1511 if (strcmp(key, "LABEL") == 0) {
6880b25d 1512 rule_tmp.rule.rule.label_off = add_string(rules, value);
c7521974
KS
1513 continue;
1514 }
1515
bd75fddb 1516 if (strcmp(key, "GOTO") == 0) {
0ef254d5 1517 rule_add_key(&rule_tmp, TK_A_GOTO, 0, value, NULL);
c7521974
KS
1518 continue;
1519 }
1520
bd75fddb 1521 if (strncmp(key, "NAME", sizeof("NAME")-1) == 0) {
b0f7409f 1522 if (op < OP_MATCH_MAX) {
0ef254d5 1523 rule_add_key(&rule_tmp, TK_M_NAME, op, value, NULL);
6880b25d 1524 } else {
75cb1ac5 1525 if (strcmp(value, "%k") == 0) {
d0d7b8d0 1526 err(rules->udev, "NAME=\"%%k\" is ignored, because it breaks kernel supplied names, "
75cb1ac5
KS
1527 "please remove it from %s:%u\n", filename, lineno);
1528 continue;
1529 }
d0d7b8d0
KS
1530 if (value[0] == '\0') {
1531 info(rules->udev, "NAME=\"\" is ignored, because udev will not delete any device nodes, "
1532 "please remove it from %s:%u\n", filename, lineno);
75cb1ac5 1533 continue;
d0d7b8d0 1534 }
0ef254d5 1535 rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL);
c7521974 1536 }
761dfddc 1537 rule_tmp.rule.rule.can_set_name = true;
c7521974
KS
1538 continue;
1539 }
1540
bcb8b231 1541 if (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) {
6c29f2b9 1542 if (op < OP_MATCH_MAX) {
0ef254d5 1543 rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
6c29f2b9
KS
1544 } else {
1545 int flag = 0;
1546
1547 attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1);
1548 if (attr != NULL && strstr(attr, "unique") != NULL)
1549 flag = 1;
1550 rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag);
1551 }
761dfddc 1552 rule_tmp.rule.rule.can_set_name = true;
b0f7409f
KS
1553 continue;
1554 }
c7521974 1555
bd75fddb 1556 if (strcmp(key, "OWNER") == 0) {
6880b25d
KS
1557 uid_t uid;
1558 char *endptr;
1559
1560 uid = strtoul(value, &endptr, 10);
1561 if (endptr[0] == '\0') {
0ef254d5 1562 rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
5f03ed8a 1563 } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
154a7b84 1564 uid = add_uid(rules, value);
0ef254d5 1565 rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
055e40ed 1566 } else if (rules->resolve_names >= 0) {
0ef254d5 1567 rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
c7521974 1568 }
761dfddc 1569 rule_tmp.rule.rule.can_set_name = true;
c7521974
KS
1570 continue;
1571 }
1572
bd75fddb 1573 if (strcmp(key, "GROUP") == 0) {
6880b25d
KS
1574 gid_t gid;
1575 char *endptr;
1576
1577 gid = strtoul(value, &endptr, 10);
1578 if (endptr[0] == '\0') {
0ef254d5 1579 rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
5f03ed8a 1580 } else if ((rules->resolve_names > 0) && strchr("$%", value[0]) == NULL) {
154a7b84 1581 gid = add_gid(rules, value);
0ef254d5 1582 rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
055e40ed 1583 } else if (rules->resolve_names >= 0) {
0ef254d5 1584 rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
c7521974 1585 }
761dfddc 1586 rule_tmp.rule.rule.can_set_name = true;
c7521974
KS
1587 continue;
1588 }
1589
bd75fddb 1590 if (strcmp(key, "MODE") == 0) {
6880b25d
KS
1591 mode_t mode;
1592 char *endptr;
1593
1594 mode = strtol(value, &endptr, 8);
1595 if (endptr[0] == '\0')
0ef254d5 1596 rule_add_key(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode);
6880b25d 1597 else
0ef254d5 1598 rule_add_key(&rule_tmp, TK_A_MODE, op, value, NULL);
761dfddc 1599 rule_tmp.rule.rule.can_set_name = true;
c7521974
KS
1600 continue;
1601 }
1602
bd75fddb 1603 if (strcmp(key, "OPTIONS") == 0) {
c7521974
KS
1604 const char *pos;
1605
c7521974
KS
1606 pos = strstr(value, "link_priority=");
1607 if (pos != NULL) {
6880b25d
KS
1608 int prio = atoi(&pos[strlen("link_priority=")]);
1609
3b529da4 1610 rule_add_key(&rule_tmp, TK_A_DEVLINK_PRIO, op, NULL, &prio);
6880b25d 1611 dbg(rules->udev, "link priority=%i\n", prio);
c7521974 1612 }
9ead6627 1613
c7521974
KS
1614 pos = strstr(value, "event_timeout=");
1615 if (pos != NULL) {
6880b25d
KS
1616 int tout = atoi(&pos[strlen("event_timeout=")]);
1617
2181d30a 1618 rule_add_key(&rule_tmp, TK_M_EVENT_TIMEOUT, op, NULL, &tout);
214a6c79 1619 dbg(rules->udev, "event timeout=%i\n", tout);
c7521974 1620 }
9ead6627 1621
c7521974
KS
1622 pos = strstr(value, "string_escape=");
1623 if (pos != NULL) {
1624 pos = &pos[strlen("string_escape=")];
1625 if (strncmp(pos, "none", strlen("none")) == 0)
3b529da4 1626 rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_NONE, op, NULL, NULL);
c7521974 1627 else if (strncmp(pos, "replace", strlen("replace")) == 0)
3b529da4 1628 rule_add_key(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, op, NULL, NULL);
c7521974 1629 }
9ead6627 1630
d3990a57 1631 pos = strstr(value, "db_persist");
9ead6627
KS
1632 if (pos != NULL)
1633 rule_add_key(&rule_tmp, TK_A_DB_PERSIST, op, NULL, NULL);
1634
46f194cb 1635 pos = strstr(value, "nowatch");
bd284db1 1636 if (pos != NULL) {
46f194cb
KS
1637 const int off = 0;
1638
3b529da4 1639 rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &off);
46f194cb
KS
1640 dbg(rules->udev, "inotify watch of device disabled\n");
1641 } else {
1642 pos = strstr(value, "watch");
1643 if (pos != NULL) {
1644 const int on = 1;
1645
3b529da4 1646 rule_add_key(&rule_tmp, TK_A_INOTIFY_WATCH, op, NULL, &on);
46f194cb
KS
1647 dbg(rules->udev, "inotify watch of device requested\n");
1648 }
bd284db1 1649 }
9ead6627 1650
761dfddc
KS
1651 pos = strstr(value, "static_node=");
1652 if (pos != NULL) {
3b529da4 1653 rule_add_key(&rule_tmp, TK_A_STATIC_NODE, op, &pos[strlen("static_node=")], NULL);
761dfddc
KS
1654 rule_tmp.rule.rule.has_static_node = true;
1655 }
9ead6627 1656
c7521974
KS
1657 continue;
1658 }
c7521974
KS
1659 err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
1660 }
1661
6880b25d 1662 /* add rule token */
3f3aa9f5 1663 rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur;
6880b25d
KS
1664 if (add_token(rules, &rule_tmp.rule) != 0)
1665 goto invalid;
c7521974 1666
6880b25d
KS
1667 /* add tokens to list, sorted by type */
1668 if (sort_token(rules, &rule_tmp) != 0)
1669 goto invalid;
3f3aa9f5 1670
6880b25d 1671 return 0;
c7521974
KS
1672invalid:
1673 err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
1674 return -1;
1675}
1676
0ef254d5 1677static int parse_file(struct udev_rules *rules, const char *filename, unsigned short filename_off)
c7521974
KS
1678{
1679 FILE *f;
77f89e93 1680 unsigned int first_token;
c7521974 1681 char line[UTIL_LINE_SIZE];
6880b25d
KS
1682 int line_nr = 0;
1683 unsigned int i;
c7521974 1684
c7521974
KS
1685 info(rules->udev, "reading '%s' as rules file\n", filename);
1686
1687 f = fopen(filename, "r");
1688 if (f == NULL)
1689 return -1;
77f89e93
KS
1690
1691 first_token = rules->token_cur;
1692
335e316a 1693 while (fgets(line, sizeof(line), f) != NULL) {
c7521974
KS
1694 char *key;
1695 size_t len;
1696
1697 /* skip whitespace */
1698 line_nr++;
1699 key = line;
1700 while (isspace(key[0]))
1701 key++;
1702
1703 /* comment */
1704 if (key[0] == '#')
1705 continue;
1706
1707 len = strlen(line);
1708 if (len < 3)
1709 continue;
1710
1711 /* continue reading if backslash+newline is found */
1712 while (line[len-2] == '\\') {
1713 if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL)
1714 break;
6d691b2b
FZ
1715 if (strlen(&line[len-2]) < 2)
1716 break;
c7521974
KS
1717 line_nr++;
1718 len = strlen(line);
1719 }
1720
1721 if (len+1 >= sizeof(line)) {
1722 err(rules->udev, "line too long '%s':%u, ignored\n", filename, line_nr);
1723 continue;
1724 }
6880b25d 1725 add_rule(rules, key, filename, filename_off, line_nr);
c7521974
KS
1726 }
1727 fclose(f);
1728
6880b25d 1729 /* link GOTOs to LABEL rules in this file to be able to fast-forward */
77f89e93 1730 for (i = first_token+1; i < rules->token_cur; i++) {
6880b25d
KS
1731 if (rules->tokens[i].type == TK_A_GOTO) {
1732 char *label = &rules->buf[rules->tokens[i].key.value_off];
1733 unsigned int j;
1734
1735 for (j = i+1; j < rules->token_cur; j++) {
1736 if (rules->tokens[j].type != TK_RULE)
1737 continue;
1738 if (rules->tokens[j].rule.label_off == 0)
1739 continue;
1740 if (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0)
1741 continue;
1742 rules->tokens[i].key.rule_goto = j;
0c377989 1743 break;
c7521974 1744 }
6880b25d
KS
1745 if (rules->tokens[i].key.rule_goto == 0)
1746 err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename);
c7521974
KS
1747 }
1748 }
1749 return 0;
1750}
1751
1752static int add_matching_files(struct udev *udev, struct udev_list_node *file_list, const char *dirname, const char *suffix)
1753{
c7521974 1754 DIR *dir;
c7c32e9c 1755 struct dirent *dent;
c7521974
KS
1756 char filename[UTIL_PATH_SIZE];
1757
1758 dbg(udev, "open directory '%s'\n", dirname);
1759 dir = opendir(dirname);
1760 if (dir == NULL) {
92e52e2f 1761 info(udev, "unable to open '%s': %m\n", dirname);
c7521974
KS
1762 return -1;
1763 }
1764
c7c32e9c 1765 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
78230c0d 1766 if (dent->d_name[0] == '.')
c7521974
KS
1767 continue;
1768
1769 /* look for file matching with specified suffix */
1770 if (suffix != NULL) {
1771 const char *ext;
1772
78230c0d 1773 ext = strrchr(dent->d_name, '.');
c7521974
KS
1774 if (ext == NULL)
1775 continue;
1776 if (strcmp(ext, suffix) != 0)
1777 continue;
1778 }
e6c1a2bd
KS
1779 util_strscpyl(filename, sizeof(filename), dirname, "/", dent->d_name, NULL);
1780 dbg(udev, "put file '%s' into list\n", filename);
c7c32e9c
KS
1781 /*
1782 * the basename is the key, the filename the value
1783 * identical basenames from different directories overwrite each other
1784 * entries are sorted after basename
1785 */
8958da13 1786 udev_list_entry_add(udev, file_list, dent->d_name, filename, UDEV_LIST_UNIQUE|UDEV_LIST_SORT);
c7521974
KS
1787 }
1788
1789 closedir(dir);
1790 return 0;
1791}
1792
d7ddce18 1793struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
c7521974 1794{
d7ddce18 1795 struct udev_rules *rules;
c7521974 1796 struct udev_list_node file_list;
c7c32e9c 1797 struct udev_list_entry *file_loop;
6880b25d 1798 struct token end_token;
c7521974 1799
27f4528b 1800 rules = calloc(1, sizeof(struct udev_rules));
d7ddce18 1801 if (rules == NULL)
6880b25d 1802 return NULL;
c7521974
KS
1803 rules->udev = udev;
1804 rules->resolve_names = resolve_names;
1805 udev_list_init(&file_list);
1806
6880b25d
KS
1807 /* init token array and string buffer */
1808 rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token));
1851332c
YK
1809 if (rules->tokens == NULL) {
1810 free(rules);
34d6a259 1811 return NULL;
1851332c 1812 }
34d6a259 1813 rules->token_max = PREALLOC_TOKEN;
bcf44d55 1814
6880b25d 1815 rules->buf = malloc(PREALLOC_STRBUF);
1851332c
YK
1816 if (rules->buf == NULL) {
1817 free(rules->tokens);
1818 free(rules);
34d6a259 1819 return NULL;
1851332c 1820 }
34d6a259
KS
1821 rules->buf_max = PREALLOC_STRBUF;
1822 /* offset 0 is always '\0' */
1823 rules->buf[0] = '\0';
1824 rules->buf_cur = 1;
86b57788
KS
1825 dbg(udev, "prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
1826 rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
6880b25d 1827
bcf44d55 1828 rules->trie_nodes = malloc(PREALLOC_TRIE * sizeof(struct trie_node));
1851332c
YK
1829 if (rules->trie_nodes == NULL) {
1830 free(rules->buf);
1831 free(rules->tokens);
1832 free(rules);
bcf44d55 1833 return NULL;
1851332c 1834 }
bcf44d55 1835 rules->trie_nodes_max = PREALLOC_TRIE;
949075db 1836 /* offset 0 is the trie root, with an empty string */
023ed7b0 1837 memset(rules->trie_nodes, 0x00, sizeof(struct trie_node));
bcf44d55
KS
1838 rules->trie_nodes_cur = 1;
1839
c7c32e9c
KS
1840 if (udev_get_rules_path(udev) == NULL) {
1841 char filename[UTIL_PATH_SIZE];
c7521974 1842
c7c32e9c
KS
1843 /* /lib/udev -- default/package rules */
1844 add_matching_files(udev, &file_list, LIBEXECDIR "/rules.d", ".rules");
1845
1846 /* /etc/udev -- system-specific/user/admin rules */
c7521974
KS
1847 add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules");
1848
c7c32e9c 1849 /* /run/udev -- throw-away/temporary rules */
4ec9c3e7 1850 util_strscpyl(filename, sizeof(filename), udev_get_run_path(udev), "/rules.d", NULL);
c7c32e9c
KS
1851 add_matching_files(udev, &file_list, filename, ".rules");
1852 } else {
1853 /* custom rules files location for testing */
1854 add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
c7521974
KS
1855 }
1856
0ef254d5
KS
1857 /* add all filenames to the string buffer */
1858 udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
c7c32e9c 1859 const char *filename = udev_list_entry_get_value(file_loop);
0ef254d5
KS
1860 unsigned int filename_off;
1861
1862 filename_off = add_string(rules, filename);
1863 /* the offset in the rule is limited to unsigned short */
1864 if (filename_off < USHRT_MAX)
8958da13 1865 udev_list_entry_set_num(file_loop, filename_off);
0ef254d5
KS
1866 }
1867
c7c32e9c
KS
1868 /* parse all rules files */
1869 udev_list_entry_foreach(file_loop, udev_list_get_entry(&file_list)) {
1870 const char *filename = udev_list_entry_get_value(file_loop);
8958da13 1871 unsigned int filename_off = udev_list_entry_get_num(file_loop);
a178e7fe 1872 struct stat st;
c7521974 1873
a178e7fe
KS
1874 if (stat(filename, &st) != 0) {
1875 err(udev, "can not find '%s': %m\n", filename);
1876 continue;
1877 }
1878 if (S_ISREG(st.st_mode) && st.st_size <= 0) {
1879 info(udev, "ignore empty '%s'\n", filename);
1880 continue;
1881 }
1882 if (S_ISCHR(st.st_mode)) {
1883 info(udev, "ignore masked '%s'\n", filename);
1884 continue;
1885 }
1886 parse_file(rules, filename, filename_off);
c7521974 1887 }
c7c32e9c 1888 udev_list_cleanup_entries(udev, &file_list);
6880b25d
KS
1889
1890 memset(&end_token, 0x00, sizeof(struct token));
1891 end_token.type = TK_END;
1892 add_token(rules, &end_token);
1893
154a7b84 1894 /* shrink allocated token and string buffer */
6880b25d
KS
1895 if (rules->token_cur < rules->token_max) {
1896 struct token *tokens;
1897
1898 tokens = realloc(rules->tokens, rules->token_cur * sizeof(struct token));
1899 if (tokens != NULL || rules->token_cur == 0) {
1900 rules->tokens = tokens;
1901 rules->token_max = rules->token_cur;
1902 }
1903 }
1904 if (rules->buf_cur < rules->buf_max) {
1905 char *buf;
1906
1907 buf = realloc(rules->buf, rules->buf_cur);
1908 if (buf != NULL || rules->buf_cur == 0) {
1909 rules->buf = buf;
1910 rules->buf_max = rules->buf_cur;
1911 }
1912 }
0dd9f015 1913 info(udev, "rules use %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
6880b25d 1914 rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
023ed7b0
KS
1915 info(udev, "temporary index used %zu bytes (%u * %zu bytes)\n",
1916 rules->trie_nodes_cur * sizeof(struct trie_node),
1917 rules->trie_nodes_cur, sizeof(struct trie_node));
1449a55d
AJ
1918
1919 /* cleanup trie */
bcf44d55
KS
1920 free(rules->trie_nodes);
1921 rules->trie_nodes = NULL;
1922 rules->trie_nodes_cur = 0;
1923 rules->trie_nodes_max = 0;
6880b25d 1924
154a7b84
KS
1925 /* cleanup uid/gid cache */
1926 free(rules->uids);
1927 rules->uids = NULL;
1928 rules->uids_cur = 0;
1929 rules->uids_max = 0;
1930 free(rules->gids);
1931 rules->gids = NULL;
1932 rules->gids_cur = 0;
1933 rules->gids_max = 0;
1934
6880b25d 1935 dump_rules(rules);
d7ddce18 1936 return rules;
c7521974
KS
1937}
1938
d7ddce18 1939void udev_rules_unref(struct udev_rules *rules)
c7521974 1940{
d7ddce18
KS
1941 if (rules == NULL)
1942 return;
6880b25d
KS
1943 free(rules->tokens);
1944 free(rules->buf);
bcf44d55 1945 free(rules->trie_nodes);
154a7b84
KS
1946 free(rules->uids);
1947 free(rules->gids);
d7ddce18 1948 free(rules);
c7521974 1949}
6880b25d
KS
1950
1951static int match_key(struct udev_rules *rules, struct token *token, const char *val)
1952{
6880b25d
KS
1953 char *key_value = &rules->buf[token->key.value_off];
1954 char *pos;
761dfddc 1955 bool match = false;
6880b25d
KS
1956
1957 if (val == NULL)
1958 val = "";
1959
ac218d9c
KS
1960 switch (token->key.glob) {
1961 case GL_PLAIN:
1962 match = (strcmp(key_value, val) == 0);
1963 break;
1964 case GL_GLOB:
1965 match = (fnmatch(key_value, val, 0) == 0);
1966 break;
1967 case GL_SPLIT:
1968 {
91a75e4a
KS
1969 const char *split;
1970 size_t len;
6880b25d 1971
91a75e4a
KS
1972 split = &rules->buf[token->key.value_off];
1973 len = strlen(val);
88cbfb09 1974 for (;;) {
91a75e4a
KS
1975 const char *next;
1976
1977 next = strchr(split, '|');
1978 if (next != NULL) {
1979 size_t matchlen = (size_t)(next - split);
1980
1981 match = (matchlen == len && strncmp(split, val, matchlen) == 0);
1982 if (match)
1983 break;
1984 } else {
1985 match = (strcmp(split, val) == 0);
ac218d9c 1986 break;
91a75e4a
KS
1987 }
1988 split = &next[1];
6880b25d 1989 }
ac218d9c 1990 break;
6880b25d 1991 }
ac218d9c
KS
1992 case GL_SPLIT_GLOB:
1993 {
1994 char value[UTIL_PATH_SIZE];
1995
065db052 1996 util_strscpy(value, sizeof(value), &rules->buf[token->key.value_off]);
ac218d9c
KS
1997 key_value = value;
1998 while (key_value != NULL) {
1999 pos = strchr(key_value, '|');
2000 if (pos != NULL) {
2001 pos[0] = '\0';
2002 pos = &pos[1];
2003 }
5d6a1fa6 2004 dbg(rules->udev, "match %s '%s' <-> '%s'\n", token_str(token->type), key_value, val);
ac218d9c
KS
2005 match = (fnmatch(key_value, val, 0) == 0);
2006 if (match)
2007 break;
2008 key_value = pos;
2009 }
2010 break;
2011 }
db463fd3
KS
2012 case GL_SOMETHING:
2013 match = (val[0] != '\0');
2014 break;
ac218d9c
KS
2015 case GL_UNSET:
2016 return -1;
6880b25d
KS
2017 }
2018
b0f7409f 2019 if (match && (token->key.op == OP_MATCH)) {
5d6a1fa6 2020 dbg(rules->udev, "%s is true (matching value)\n", token_str(token->type));
6880b25d
KS
2021 return 0;
2022 }
b0f7409f 2023 if (!match && (token->key.op == OP_NOMATCH)) {
5d6a1fa6 2024 dbg(rules->udev, "%s is true (non-matching value)\n", token_str(token->type));
6880b25d
KS
2025 return 0;
2026 }
5d6a1fa6 2027 dbg(rules->udev, "%s is not true\n", token_str(token->type));
6880b25d
KS
2028 return -1;
2029}
2030
2031static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur)
2032{
32028733
KS
2033 const char *name;
2034 char nbuf[UTIL_NAME_SIZE];
2035 const char *value;
2036 char vbuf[UTIL_NAME_SIZE];
6880b25d
KS
2037 size_t len;
2038
32028733
KS
2039 name = &rules->buf[cur->key.attr_off];
2040 switch (cur->key.attrsubst) {
2041 case SB_FORMAT:
2042 udev_event_apply_format(event, name, nbuf, sizeof(nbuf));
2043 name = nbuf;
2044 /* fall through */
2045 case SB_NONE:
2046 value = udev_device_get_sysattr_value(dev, name);
2047 if (value == NULL)
aeb53ca3 2048 return -1;
32028733
KS
2049 break;
2050 case SB_SUBSYS:
2051 if (util_resolve_subsys_kernel(event->udev, name, vbuf, sizeof(vbuf), 1) != 0)
2052 return -1;
2053 value = vbuf;
2054 break;
2055 default:
2056 return -1;
6880b25d 2057 }
6880b25d 2058
32028733
KS
2059 /* remove trailing whitespace, if not asked to match for it */
2060 len = strlen(value);
2061 if (len > 0 && isspace(value[len-1])) {
2062 const char *key_value;
2063 size_t klen;
2064
2065 key_value = &rules->buf[cur->key.value_off];
2066 klen = strlen(key_value);
2067 if (klen > 0 && !isspace(key_value[klen-1])) {
2068 if (value != vbuf) {
2069 util_strscpy(vbuf, sizeof(vbuf), value);
2070 value = vbuf;
2071 }
2072 while (len > 0 && isspace(vbuf[--len]))
2073 vbuf[len] = '\0';
2074 dbg(rules->udev, "removed trailing whitespace from '%s'\n", value);
2075 }
6880b25d 2076 }
32028733 2077
6880b25d
KS
2078 return match_key(rules, cur, value);
2079}
2080
2081enum escape_type {
2082 ESCAPE_UNSET,
2083 ESCAPE_NONE,
2084 ESCAPE_REPLACE,
2085};
2086
2181d30a 2087int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event, const sigset_t *sigmask)
6880b25d 2088{
6880b25d 2089 struct token *cur;
34d6a259 2090 struct token *rule;
3e5c7595 2091 enum escape_type esc = ESCAPE_UNSET;
4b06c409 2092 bool can_set_name;
6880b25d
KS
2093
2094 if (rules->tokens == NULL)
2095 return -1;
2096
4b06c409 2097 can_set_name = ((strcmp(udev_device_get_action(event->dev), "remove") != 0) &&
00f98bd2 2098 (major(udev_device_get_devnum(event->dev)) > 0 ||
ff0e1f4e 2099 udev_device_get_ifindex(event->dev) > 0));
00f98bd2 2100
6880b25d
KS
2101 /* loop through token list, match, run actions or forward to next rule */
2102 cur = &rules->tokens[0];
34d6a259 2103 rule = cur;
761dfddc 2104 for (;;) {
6880b25d
KS
2105 dump_token(rules, cur);
2106 switch (cur->type) {
2107 case TK_RULE:
2108 /* current rule */
2109 rule = cur;
00f98bd2 2110 /* possibly skip rules which want to set NAME, SYMLINK, OWNER, GROUP, MODE */
761dfddc 2111 if (!can_set_name && rule->rule.can_set_name)
0c057e9c 2112 goto nomatch;
6880b25d
KS
2113 esc = ESCAPE_UNSET;
2114 break;
6880b25d
KS
2115 case TK_M_ACTION:
2116 if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0)
2117 goto nomatch;
2118 break;
2119 case TK_M_DEVPATH:
2120 if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0)
2121 goto nomatch;
2122 break;
2123 case TK_M_KERNEL:
2124 if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0)
2125 goto nomatch;
2126 break;
38932b9f
KS
2127 case TK_M_DEVLINK: {
2128 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
2129 struct udev_list_entry *list_entry;
2130 bool match = false;
2131
2132 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) {
2133 const char *devlink;
2134
2135 devlink = &udev_list_entry_get_name(list_entry)[devlen];
2136 if (match_key(rules, cur, devlink) == 0) {
2137 match = true;
2138 break;
6880b25d 2139 }
6880b25d 2140 }
38932b9f
KS
2141 if (!match)
2142 goto nomatch;
2143 break;
2144 }
6880b25d
KS
2145 case TK_M_NAME:
2146 if (match_key(rules, cur, event->name) != 0)
2147 goto nomatch;
2148 break;
38932b9f
KS
2149 case TK_M_ENV: {
2150 const char *key_name = &rules->buf[cur->key.attr_off];
2151 const char *value;
2152
2153 value = udev_device_get_property_value(event->dev, key_name);
2154 if (value == NULL) {
2155 dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
2156 value = "";
6880b25d 2157 }
38932b9f
KS
2158 if (match_key(rules, cur, value))
2159 goto nomatch;
2160 break;
2161 }
2162 case TK_M_TAG: {
2163 struct udev_list_entry *list_entry;
2164 bool match = false;
2165
2166 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(event->dev)) {
2167 if (strcmp(&rules->buf[cur->key.value_off], udev_list_entry_get_name(list_entry)) == 0) {
2168 match = true;
2169 break;
3f896a2a 2170 }
3f896a2a 2171 }
38932b9f
KS
2172 if (!match && (cur->key.op != OP_NOMATCH))
2173 goto nomatch;
2174 break;
2175 }
6880b25d
KS
2176 case TK_M_SUBSYSTEM:
2177 if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0)
2178 goto nomatch;
2179 break;
2180 case TK_M_DRIVER:
2181 if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0)
2182 goto nomatch;
2183 break;
38932b9f
KS
2184 case TK_M_WAITFOR: {
2185 char filename[UTIL_PATH_SIZE];
2186 int found;
2187
2188 udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename));
2189 found = (wait_for_file(event->dev, filename, 10) == 0);
2190 if (!found && (cur->key.op != OP_NOMATCH))
2191 goto nomatch;
2192 break;
2193 }
6880b25d
KS
2194 case TK_M_ATTR:
2195 if (match_attr(rules, event->dev, event, cur) != 0)
2196 goto nomatch;
2197 break;
2198 case TK_M_KERNELS:
2199 case TK_M_SUBSYSTEMS:
2200 case TK_M_DRIVERS:
7df0ed83
KS
2201 case TK_M_ATTRS:
2202 case TK_M_TAGS: {
38932b9f 2203 struct token *next;
6880b25d 2204
38932b9f
KS
2205 /* get whole sequence of parent matches */
2206 next = cur;
2207 while (next->type > TK_M_PARENTS_MIN && next->type < TK_M_PARENTS_MAX)
2208 next++;
6880b25d 2209
38932b9f
KS
2210 /* loop over parents */
2211 event->dev_parent = event->dev;
2212 for (;;) {
2213 struct token *key;
2214
2215 dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent));
2216 /* loop over sequence of parent match keys */
2217 for (key = cur; key < next; key++ ) {
2218 dump_token(rules, key);
2219 switch(key->type) {
2220 case TK_M_KERNELS:
2221 if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0)
2222 goto try_parent;
2223 break;
2224 case TK_M_SUBSYSTEMS:
2225 if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0)
2226 goto try_parent;
2227 break;
2228 case TK_M_DRIVERS:
2229 if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0)
2230 goto try_parent;
2231 break;
2232 case TK_M_ATTRS:
2233 if (match_attr(rules, event->dev_parent, event, key) != 0)
2234 goto try_parent;
2235 break;
7df0ed83
KS
2236 case TK_M_TAGS: {
2237 bool match = udev_device_has_tag(event->dev_parent, &rules->buf[cur->key.value_off]);
2238
2239 if (match && key->key.op == OP_NOMATCH)
2240 goto try_parent;
2241 if (!match && key->key.op == OP_MATCH)
2242 goto try_parent;
2243 break;
2244 }
38932b9f 2245 default:
6880b25d 2246 goto nomatch;
6880b25d 2247 }
38932b9f 2248 dbg(event->udev, "parent key matched\n");
065db052 2249 }
38932b9f 2250 dbg(event->udev, "all parent keys matched\n");
6880b25d 2251 break;
38932b9f
KS
2252
2253 try_parent:
2254 event->dev_parent = udev_device_get_parent(event->dev_parent);
2255 if (event->dev_parent == NULL)
2256 goto nomatch;
2257 }
2258 /* move behind our sequence of parent match keys */
2259 cur = next;
2260 continue;
2261 }
2262 case TK_M_TEST: {
2263 char filename[UTIL_PATH_SIZE];
2264 struct stat statbuf;
2265 int match;
2266
2267 udev_event_apply_format(event, &rules->buf[cur->key.value_off], filename, sizeof(filename));
2268 if (util_resolve_subsys_kernel(event->udev, filename, filename, sizeof(filename), 0) != 0) {
2269 if (filename[0] != '/') {
2270 char tmp[UTIL_PATH_SIZE];
2271
2272 util_strscpy(tmp, sizeof(tmp), filename);
2273 util_strscpyl(filename, sizeof(filename),
2274 udev_device_get_syspath(event->dev), "/", tmp, NULL);
2275 }
6880b25d 2276 }
38932b9f
KS
2277 attr_subst_subdir(filename, sizeof(filename));
2278
2279 match = (stat(filename, &statbuf) == 0);
2280 dbg(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
2281 if (match && cur->key.mode > 0) {
2282 match = ((statbuf.st_mode & cur->key.mode) > 0);
2283 dbg(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
2284 match ? "matches" : "does not match", cur->key.mode);
2285 }
2286 if (match && cur->key.op == OP_NOMATCH)
2287 goto nomatch;
2288 if (!match && cur->key.op == OP_MATCH)
2289 goto nomatch;
2290 break;
2291 }
2181d30a
KS
2292 case TK_M_EVENT_TIMEOUT:
2293 info(event->udev, "OPTIONS event_timeout=%u\n", cur->key.event_timeout);
2294 event->timeout_usec = cur->key.event_timeout * 1000 * 1000;
2295 break;
38932b9f
KS
2296 case TK_M_PROGRAM: {
2297 char program[UTIL_PATH_SIZE];
2298 char **envp;
2299 char result[UTIL_PATH_SIZE];
2300
2301 free(event->program_result);
2302 event->program_result = NULL;
2303 udev_event_apply_format(event, &rules->buf[cur->key.value_off], program, sizeof(program));
2304 envp = udev_device_get_properties_envp(event->dev);
2305 info(event->udev, "PROGRAM '%s' %s:%u\n",
2306 program,
2307 &rules->buf[rule->rule.filename_off],
2308 rule->rule.filename_line);
6880b25d 2309
38932b9f
KS
2310 if (udev_event_spawn(event, program, envp, sigmask, result, sizeof(result)) < 0) {
2311 if (cur->key.op != OP_NOMATCH)
2312 goto nomatch;
2313 } else {
2314 int count;
2315
2316 util_remove_trailing_chars(result, '\n');
2317 if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
2318 count = udev_util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT);
2319 if (count > 0)
2320 info(event->udev, "%i character(s) replaced\n" , count);
6880b25d 2321 }
38932b9f
KS
2322 event->program_result = strdup(result);
2323 dbg(event->udev, "storing result '%s'\n", event->program_result);
2324 if (cur->key.op == OP_NOMATCH)
2325 goto nomatch;
6880b25d 2326 }
38932b9f
KS
2327 break;
2328 }
2329 case TK_M_IMPORT_FILE: {
2330 char import[UTIL_PATH_SIZE];
6880b25d 2331
38932b9f
KS
2332 udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import));
2333 if (import_file_into_properties(event->dev, import) != 0)
2334 if (cur->key.op != OP_NOMATCH)
2335 goto nomatch;
2336 break;
2337 }
2338 case TK_M_IMPORT_PROG: {
2339 char import[UTIL_PATH_SIZE];
5539f624 2340
38932b9f
KS
2341 udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import));
2342 info(event->udev, "IMPORT '%s' %s:%u\n",
2343 import,
2344 &rules->buf[rule->rule.filename_off],
2345 rule->rule.filename_line);
5539f624 2346
38932b9f
KS
2347 if (import_program_into_properties(event, import, sigmask) != 0)
2348 if (cur->key.op != OP_NOMATCH)
2349 goto nomatch;
2350 break;
2351 }
2352 case TK_M_IMPORT_DB: {
2353 const char *key = &rules->buf[cur->key.value_off];
2354 const char *value;
2355
2356 value = udev_device_get_property_value(event->dev_db, key);
2357 if (value != NULL) {
2358 struct udev_list_entry *entry;
c4f6dcc4 2359
38932b9f
KS
2360 entry = udev_device_add_property(event->dev, key, value);
2361 udev_list_entry_set_num(entry, true);
2362 } else {
2363 if (cur->key.op != OP_NOMATCH)
2364 goto nomatch;
2365 }
2366 break;
2367 }
2368 case TK_M_IMPORT_CMDLINE: {
2369 FILE *f;
2370 bool imported = false;
2371
2372 f = fopen("/proc/cmdline", "r");
2373 if (f != NULL) {
2374 char cmdline[4096];
2375
2376 if (fgets(cmdline, sizeof(cmdline), f) != NULL) {
2377 const char *key = &rules->buf[cur->key.value_off];
2378 char *pos;
2379
2380 pos = strstr(cmdline, key);
2381 if (pos != NULL) {
2382 struct udev_list_entry *entry;
2383
2384 pos += strlen(key);
2385 if (pos[0] == '\0' || isspace(pos[0])) {
2386 /* we import simple flags as 'FLAG=1' */
2387 entry = udev_device_add_property(event->dev, key, "1");
2388 udev_list_entry_set_num(entry, true);
2389 imported = true;
2390 } else if (pos[0] == '=') {
2391 const char *value;
2392
2393 pos++;
2394 value = pos;
2395 while (pos[0] != '\0' && !isspace(pos[0]))
7d2b68b7 2396 pos++;
38932b9f
KS
2397 pos[0] = '\0';
2398 entry = udev_device_add_property(event->dev, key, value);
2399 udev_list_entry_set_num(entry, true);
2400 imported = true;
c4f6dcc4
KS
2401 }
2402 }
c4f6dcc4 2403 }
38932b9f 2404 fclose(f);
c4f6dcc4 2405 }
38932b9f
KS
2406 if (!imported && cur->key.op != OP_NOMATCH)
2407 goto nomatch;
2408 break;
2409 }
2410 case TK_M_IMPORT_PARENT: {
2411 char import[UTIL_PATH_SIZE];
6880b25d 2412
38932b9f
KS
2413 udev_event_apply_format(event, &rules->buf[cur->key.value_off], import, sizeof(import));
2414 if (import_parent_into_properties(event->dev, import) != 0)
2415 if (cur->key.op != OP_NOMATCH)
2416 goto nomatch;
2417 break;
2418 }
6880b25d
KS
2419 case TK_M_RESULT:
2420 if (match_key(rules, cur, event->program_result) != 0)
2421 goto nomatch;
2422 break;
6880b25d
KS
2423 case TK_A_STRING_ESCAPE_NONE:
2424 esc = ESCAPE_NONE;
2425 break;
2426 case TK_A_STRING_ESCAPE_REPLACE:
2427 esc = ESCAPE_REPLACE;
2428 break;
9ead6627
KS
2429 case TK_A_DB_PERSIST:
2430 udev_device_set_db_persist(event->dev);
2431 break;
bd284db1 2432 case TK_A_INOTIFY_WATCH:
3b529da4
KS
2433 if (event->inotify_watch_final)
2434 break;
2435 if (cur->key.op == OP_ASSIGN_FINAL)
2436 event->inotify_watch_final = true;
46f194cb 2437 event->inotify_watch = cur->key.watch;
bd284db1 2438 break;
6880b25d
KS
2439 case TK_A_DEVLINK_PRIO:
2440 udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio);
2441 break;
38932b9f
KS
2442 case TK_A_OWNER: {
2443 char owner[UTIL_NAME_SIZE];
6880b25d 2444
38932b9f 2445 if (event->owner_final)
6880b25d 2446 break;
38932b9f
KS
2447 if (cur->key.op == OP_ASSIGN_FINAL)
2448 event->owner_final = true;
2449 udev_event_apply_format(event, &rules->buf[cur->key.value_off], owner, sizeof(owner));
2450 event->uid = util_lookup_user(event->udev, owner);
2451 info(event->udev, "OWNER %u %s:%u\n",
2452 event->uid,
2453 &rules->buf[rule->rule.filename_off],
2454 rule->rule.filename_line);
2455 break;
2456 }
2457 case TK_A_GROUP: {
2458 char group[UTIL_NAME_SIZE];
6880b25d 2459
38932b9f 2460 if (event->group_final)
6880b25d 2461 break;
38932b9f
KS
2462 if (cur->key.op == OP_ASSIGN_FINAL)
2463 event->group_final = true;
2464 udev_event_apply_format(event, &rules->buf[cur->key.value_off], group, sizeof(group));
2465 event->gid = util_lookup_group(event->udev, group);
2466 info(event->udev, "GROUP %u %s:%u\n",
2467 event->gid,
2468 &rules->buf[rule->rule.filename_off],
2469 rule->rule.filename_line);
2470 break;
2471 }
2472 case TK_A_MODE: {
2473 char mode_str[UTIL_NAME_SIZE];
2474 mode_t mode;
2475 char *endptr;
6880b25d 2476
38932b9f
KS
2477 if (event->mode_final)
2478 break;
2479 udev_event_apply_format(event, &rules->buf[cur->key.value_off], mode_str, sizeof(mode_str));
2480 mode = strtol(mode_str, &endptr, 8);
2481 if (endptr[0] != '\0') {
2482 err(event->udev, "ignoring invalid mode '%s'\n", mode_str);
6880b25d
KS
2483 break;
2484 }
38932b9f
KS
2485 if (cur->key.op == OP_ASSIGN_FINAL)
2486 event->mode_final = true;
2487 event->mode_set = true;
2488 event->mode = mode;
2489 info(event->udev, "MODE %#o %s:%u\n",
2490 event->mode,
2491 &rules->buf[rule->rule.filename_off],
2492 rule->rule.filename_line);
2493 break;
2494 }
6880b25d
KS
2495 case TK_A_OWNER_ID:
2496 if (event->owner_final)
2497 break;
b0f7409f 2498 if (cur->key.op == OP_ASSIGN_FINAL)
761dfddc 2499 event->owner_final = true;
6880b25d 2500 event->uid = cur->key.uid;
0ef254d5
KS
2501 info(event->udev, "OWNER %u %s:%u\n",
2502 event->uid,
2503 &rules->buf[rule->rule.filename_off],
2504 rule->rule.filename_line);
6880b25d
KS
2505 break;
2506 case TK_A_GROUP_ID:
2507 if (event->group_final)
2508 break;
b0f7409f 2509 if (cur->key.op == OP_ASSIGN_FINAL)
761dfddc 2510 event->group_final = true;
6880b25d 2511 event->gid = cur->key.gid;
0ef254d5
KS
2512 info(event->udev, "GROUP %u %s:%u\n",
2513 event->gid,
2514 &rules->buf[rule->rule.filename_off],
2515 rule->rule.filename_line);
6880b25d
KS
2516 break;
2517 case TK_A_MODE_ID:
2518 if (event->mode_final)
2519 break;
b0f7409f 2520 if (cur->key.op == OP_ASSIGN_FINAL)
761dfddc 2521 event->mode_final = true;
3cf1a8e3 2522 event->mode_set = true;
6880b25d 2523 event->mode = cur->key.mode;
0ef254d5
KS
2524 info(event->udev, "MODE %#o %s:%u\n",
2525 event->mode,
2526 &rules->buf[rule->rule.filename_off],
2527 rule->rule.filename_line);
6880b25d 2528 break;
761dfddc
KS
2529 case TK_A_STATIC_NODE:
2530 break;
38932b9f
KS
2531 case TK_A_ENV: {
2532 const char *name = &rules->buf[cur->key.attr_off];
2533 char *value = &rules->buf[cur->key.value_off];
2534
2535 if (value[0] != '\0') {
2536 char temp_value[UTIL_NAME_SIZE];
2537 struct udev_list_entry *entry;
2538
2539 udev_event_apply_format(event, value, temp_value, sizeof(temp_value));
2540 entry = udev_device_add_property(event->dev, name, temp_value);
2541 /* store in db, skip private keys */
2542 if (name[0] != '.')
2543 udev_list_entry_set_num(entry, true);
2544 } else {
2545 udev_device_add_property(event->dev, name, NULL);
6880b25d 2546 }
38932b9f
KS
2547 break;
2548 }
1eb037a7
KS
2549 case TK_A_TAG: {
2550 char tag[UTIL_PATH_SIZE];
705a165d 2551 const char *p;
1eb037a7
KS
2552
2553 udev_event_apply_format(event, &rules->buf[cur->key.value_off], tag, sizeof(tag));
1dbfbfbe
KS
2554 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2555 udev_device_cleanup_tags_list(event->dev);
705a165d
KS
2556 for (p = tag; *p != '\0'; p++) {
2557 if ((*p >= 'a' && *p <= 'z') ||
2558 (*p >= 'A' && *p <= 'Z') ||
2559 (*p >= '0' && *p <= '9') ||
2560 *p == '-' || *p == '_')
2561 continue;
2562 err(event->udev, "ignoring invalid tag name '%s'\n", tag);
2563 break;
2564 }
1eb037a7 2565 udev_device_add_tag(event->dev, tag);
28460195 2566 break;
1eb037a7 2567 }
38932b9f
KS
2568 case TK_A_NAME: {
2569 const char *name = &rules->buf[cur->key.value_off];
2570 char name_str[UTIL_PATH_SIZE];
2571 int count;
6880b25d 2572
38932b9f 2573 if (event->name_final)
6880b25d 2574 break;
38932b9f
KS
2575 if (cur->key.op == OP_ASSIGN_FINAL)
2576 event->name_final = true;
2577 udev_event_apply_format(event, name, name_str, sizeof(name_str));
2578 if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
2579 count = udev_util_replace_chars(name_str, "/");
6880b25d 2580 if (count > 0)
38932b9f 2581 info(event->udev, "%i character(s) replaced\n", count);
6880b25d 2582 }
38932b9f
KS
2583 free(event->name);
2584 event->name = strdup(name_str);
2585 info(event->udev, "NAME '%s' %s:%u\n",
2586 event->name,
2587 &rules->buf[rule->rule.filename_off],
2588 rule->rule.filename_line);
6880b25d 2589 break;
38932b9f
KS
2590 }
2591 case TK_A_DEVLINK: {
2592 char temp[UTIL_PATH_SIZE];
2593 char filename[UTIL_PATH_SIZE];
2594 char *pos, *next;
2595 int count = 0;
2596
2597 if (event->devlink_final)
6880b25d 2598 break;
38932b9f 2599 if (major(udev_device_get_devnum(event->dev)) == 0)
6880b25d 2600 break;
38932b9f
KS
2601 if (cur->key.op == OP_ASSIGN_FINAL)
2602 event->devlink_final = true;
2603 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2604 udev_device_cleanup_devlinks_list(event->dev);
2605
2606 /* allow multiple symlinks separated by spaces */
2607 udev_event_apply_format(event, &rules->buf[cur->key.value_off], temp, sizeof(temp));
2608 if (esc == ESCAPE_UNSET)
2609 count = udev_util_replace_chars(temp, "/ ");
2610 else if (esc == ESCAPE_REPLACE)
2611 count = udev_util_replace_chars(temp, "/");
2612 if (count > 0)
2613 info(event->udev, "%i character(s) replaced\n" , count);
2614 dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
2615 pos = temp;
2616 while (isspace(pos[0]))
2617 pos++;
2618 next = strchr(pos, ' ');
2619 while (next != NULL) {
2620 next[0] = '\0';
2621 info(event->udev, "LINK '%s' %s:%u\n", pos,
2622 &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
2623 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
2624 udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
2625 while (isspace(next[1]))
2626 next++;
2627 pos = &next[1];
2628 next = strchr(pos, ' ');
2629 }
2630 if (pos[0] != '\0') {
2631 info(event->udev, "LINK '%s' %s:%u\n", pos,
2632 &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
2633 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
2634 udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
2635 }
2636 break;
2637 }
2638 case TK_A_ATTR: {
2639 const char *key_name = &rules->buf[cur->key.attr_off];
2640 char attr[UTIL_PATH_SIZE];
2641 char value[UTIL_NAME_SIZE];
2642 FILE *f;
2643
2644 if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0)
2645 util_strscpyl(attr, sizeof(attr), udev_device_get_syspath(event->dev), "/", key_name, NULL);
2646 attr_subst_subdir(attr, sizeof(attr));
2647
2648 udev_event_apply_format(event, &rules->buf[cur->key.value_off], value, sizeof(value));
2649 info(event->udev, "ATTR '%s' writing '%s' %s:%u\n", attr, value,
2650 &rules->buf[rule->rule.filename_off],
2651 rule->rule.filename_line);
2652 f = fopen(attr, "w");
2653 if (f != NULL) {
2654 if (fprintf(f, "%s", value) <= 0)
2655 err(event->udev, "error writing ATTR{%s}: %m\n", attr);
2656 fclose(f);
2657 } else {
2658 err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
6880b25d 2659 }
38932b9f
KS
2660 break;
2661 }
2662 case TK_A_RUN: {
2663 struct udev_list_entry *list_entry;
2664
2665 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2666 udev_list_cleanup_entries(event->udev, &event->run_list);
2667 info(event->udev, "RUN '%s' %s:%u\n",
2668 &rules->buf[cur->key.value_off],
2669 &rules->buf[rule->rule.filename_off],
2670 rule->rule.filename_line);
2671 list_entry = udev_list_entry_add(event->udev, &event->run_list,
2672 &rules->buf[cur->key.value_off], NULL, UDEV_LIST_UNIQUE);
2673 if (cur->key.fail_on_error)
2674 udev_list_entry_set_num(list_entry, true);
2675 break;
2676 }
6880b25d 2677 case TK_A_GOTO:
0c377989
KS
2678 if (cur->key.rule_goto == 0)
2679 break;
6880b25d
KS
2680 cur = &rules->tokens[cur->key.rule_goto];
2681 continue;
6270756c 2682 case TK_END:
11ae7578 2683 return 0;
6880b25d 2684
d15fcce4 2685 case TK_M_PARENTS_MIN:
b0f7409f 2686 case TK_M_PARENTS_MAX:
ac218d9c 2687 case TK_M_MAX:
ac218d9c 2688 case TK_UNSET:
6880b25d
KS
2689 err(rules->udev, "wrong type %u\n", cur->type);
2690 goto nomatch;
2691 }
2692
2693 cur++;
2694 continue;
2695 nomatch:
2696 /* fast-forward to next rule */
3f3aa9f5
AJ
2697 cur = rule + rule->rule.token_count;
2698 dbg(rules->udev, "forward to rule: %u\n",
2699 (unsigned int) (cur - rules->tokens));
6880b25d 2700 }
6880b25d 2701}
761dfddc
KS
2702
2703void udev_rules_apply_static_dev_perms(struct udev_rules *rules)
2704{
2705 struct token *cur;
2706 struct token *rule;
2707 uid_t uid = 0;
2708 gid_t gid = 0;
2709 mode_t mode = 0;
2710
2711 if (rules->tokens == NULL)
2712 return;
2713
2714 cur = &rules->tokens[0];
2715 rule = cur;
2716 for (;;) {
2717 switch (cur->type) {
2718 case TK_RULE:
2719 /* current rule */
2720 rule = cur;
2721
2722 /* skip rules without a static_node tag */
2723 if (!rule->rule.has_static_node)
2724 goto next;
2725
2726 uid = 0;
2727 gid = 0;
2728 mode = 0;
2729 break;
2730 case TK_A_OWNER_ID:
2731 uid = cur->key.uid;
2732 break;
2733 case TK_A_GROUP_ID:
2734 gid = cur->key.gid;
2735 break;
2736 case TK_A_MODE_ID:
2737 mode = cur->key.mode;
2738 break;
2739 case TK_A_STATIC_NODE: {
2740 char filename[UTIL_PATH_SIZE];
2741 struct stat stats;
c112873b 2742
761dfddc 2743 /* we assure, that the permissions tokens are sorted before the static token */
36acdbcc 2744 if (mode == 0 && uid == 0 && gid == 0)
761dfddc
KS
2745 goto next;
2746 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(rules->udev), "/",
2747 &rules->buf[cur->key.value_off], NULL);
2748 if (stat(filename, &stats) != 0)
2749 goto next;
2750 if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
2751 goto next;
c112873b
KS
2752
2753 if (mode == 0 && gid > 0)
2754 mode = 0660;
2755 if (mode != (stats.st_mode & 0777)) {
761dfddc
KS
2756 chmod(filename, mode);
2757 info(rules->udev, "chmod '%s' %#o\n", filename, mode);
2758 }
c112873b 2759
761dfddc
KS
2760 if ((uid != 0 && uid != stats.st_uid) || (gid != 0 && gid != stats.st_gid)) {
2761 chown(filename, uid, gid);
2762 info(rules->udev, "chown '%s' %u %u\n", filename, uid, gid);
2763 }
c112873b 2764
761dfddc
KS
2765 utimensat(AT_FDCWD, filename, NULL, 0);
2766 break;
2767 }
2768 case TK_END:
2769 return;
2770 }
2771
2772 cur++;
2773 continue;
2774next:
2775 /* fast-forward to next rule */
2776 cur = rule + rule->rule.token_count;
2777 continue;
2778 }
2779}