chiark / gitweb /
distinguish "match" from "assign" by (op < OP_MATCH_MAX)
[elogind.git] / udev / udev-rules.c
1 /*
2  * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stddef.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <fcntl.h>
23 #include <ctype.h>
24 #include <unistd.h>
25 #include <errno.h>
26 #include <dirent.h>
27 #include <fnmatch.h>
28
29 #include "udev.h"
30
31 #define PREALLOC_TOKEN                  2048
32 #define PREALLOC_STRBUF                 32 * 1024
33
34 /* KEY=="", KEY!="", KEY+="", KEY="", KEY:="" */
35 enum operation_type {
36         OP_UNSET,
37
38         OP_MATCH,
39         OP_NOMATCH,
40         OP_MATCH_MAX,
41
42         OP_ADD,
43         OP_ASSIGN,
44         OP_ASSIGN_FINAL,
45 };
46
47 static const char *operation_str[] = {
48         [OP_MATCH] =            "match",
49         [OP_NOMATCH] =          "nomatch",
50         [OP_MATCH_MAX] =        "match-max",
51
52         [OP_ADD] =              "add",
53         [OP_ASSIGN] =           "assign",
54         [OP_ASSIGN_FINAL] =     "assign-final",
55 };
56
57 /* tokens of a rule are sorted/handled in this order */
58 enum token_type {
59         TK_UNDEF,
60         TK_RULE,
61
62         TK_M_ACTION,                    /* val */
63         TK_M_DEVPATH,                   /* val */
64         TK_M_KERNEL,                    /* val */
65         TK_M_DEVLINK,                   /* val */
66         TK_M_NAME,                      /* val */
67         TK_M_ENV,                       /* val, attr */
68         TK_M_SUBSYSTEM,                 /* val */
69         TK_M_DRIVER,                    /* val */
70         TK_M_WAITFOR,                   /* val */
71         TK_M_ATTR,                      /* val, attr */
72
73         TK_M_KERNELS,                   /* val */
74         TK_M_SUBSYSTEMS,                /* val */
75         TK_M_DRIVERS,                   /* val */
76         TK_M_ATTRS,                     /* val, attr */
77         TK_M_PARENTS_MAX,
78
79         TK_M_TEST,                      /* val, mode_t */
80         TK_M_PROGRAM,                   /* val */
81         TK_M_IMPORT_FILE,               /* val */
82         TK_M_IMPORT_PROG,               /* val */
83         TK_M_IMPORT_PARENT,             /* val */
84         TK_M_RESULT,                    /* val */
85
86         TK_A_IGNORE_DEVICE,
87         TK_A_STRING_ESCAPE_NONE,
88         TK_A_STRING_ESCAPE_REPLACE,
89         TK_A_NUM_FAKE_PART,             /* int */
90         TK_A_DEVLINK_PRIO,              /* int */
91         TK_A_OWNER,                     /* val */
92         TK_A_GROUP,                     /* val */
93         TK_A_MODE,                      /* val */
94         TK_A_OWNER_ID,                  /* uid_t */
95         TK_A_GROUP_ID,                  /* gid_t */
96         TK_A_MODE_ID,                   /* mode_t */
97         TK_A_ENV,                       /* val, attr */
98         TK_A_NAME,                      /* val */
99         TK_A_DEVLINK,                   /* val */
100         TK_A_EVENT_TIMEOUT,             /* int */
101         TK_A_IGNORE_REMOVE,
102         TK_A_ATTR,                      /* val, attr */
103         TK_A_RUN,                       /* val, bool */
104         TK_A_GOTO,                      /* size_t */
105         TK_A_LAST_RULE,
106
107         TK_END,
108 };
109
110 static const char *token_str[] = {
111         [TK_UNDEF] =                    "UNDEF",
112         [TK_RULE] =                     "RULE",
113
114         [TK_M_ACTION] =                 "M ACTION",
115         [TK_M_DEVPATH] =                "M DEVPATH",
116         [TK_M_KERNEL] =                 "M KERNEL",
117         [TK_M_DEVLINK] =                "M DEVLINK",
118         [TK_M_NAME] =                   "M NAME",
119         [TK_M_ENV] =                    "M ENV",
120         [TK_M_SUBSYSTEM] =              "M SUBSYSTEM",
121         [TK_M_DRIVER] =                 "M DRIVER",
122         [TK_M_WAITFOR] =                "M WAITFOR",
123         [TK_M_ATTR] =                   "M ATTR",
124
125         [TK_M_KERNELS] =                "M KERNELS",
126         [TK_M_SUBSYSTEMS] =             "M SUBSYSTEMS",
127         [TK_M_DRIVERS] =                "M DRIVERS",
128         [TK_M_ATTRS] =                  "M ATTRS",
129         [TK_M_PARENTS_MAX] =            "M PARENTS_MAX",
130
131         [TK_M_TEST] =                   "M TEST",
132         [TK_M_PROGRAM] =                "M PROGRAM",
133         [TK_M_IMPORT_FILE] =            "M IMPORT_FILE",
134         [TK_M_IMPORT_PROG] =            "M IMPORT_PROG",
135         [TK_M_IMPORT_PARENT] =          "M MPORT_PARENT",
136         [TK_M_RESULT] =                 "M RESULT",
137
138         [TK_A_IGNORE_DEVICE] =          "A IGNORE_DEVICE",
139         [TK_A_STRING_ESCAPE_NONE] =     "A STRING_ESCAPE_NONE",
140         [TK_A_STRING_ESCAPE_REPLACE] =  "A STRING_ESCAPE_REPLACE",
141         [TK_A_NUM_FAKE_PART] =          "A NUM_FAKE_PART",
142         [TK_A_DEVLINK_PRIO] =           "A DEVLINK_PRIO",
143         [TK_A_OWNER] =                  "A OWNER",
144         [TK_A_GROUP] =                  "A GROUP",
145         [TK_A_MODE] =                   "A MODE",
146         [TK_A_OWNER_ID] =               "A OWNER_ID",
147         [TK_A_GROUP_ID] =               "A GROUP_ID",
148         [TK_A_MODE_ID] =                "A MODE_ID",
149         [TK_A_ENV] =                    "A ENV",
150         [TK_A_NAME] =                   "A NAME",
151         [TK_A_DEVLINK] =                "A DEVLINK",
152         [TK_A_EVENT_TIMEOUT] =          "A EVENT_TIMEOUT",
153         [TK_A_IGNORE_REMOVE] =          "A IGNORE_REMOVE",
154         [TK_A_ATTR] =                   "A ATTR",
155         [TK_A_RUN] =                    "A RUN",
156         [TK_A_GOTO] =                   "A GOTO",
157         [TK_A_LAST_RULE] =              "A LAST_RULE",
158
159         [TK_END] =                      "END",
160 };
161
162 struct token {
163         enum token_type type;
164         union {
165                 struct {
166                         unsigned int next_rule;
167                         unsigned int label_off;
168                         unsigned int filename_off;
169                 } rule;
170                 struct {
171                         enum operation_type op;
172                         unsigned int value_off;
173                         union {
174                                 unsigned int attr_off;
175                                 int ignore_error;
176                                 int i;
177                                 unsigned int rule_goto;
178                                 mode_t  mode;
179                                 uid_t uid;
180                                 gid_t gid;
181                                 int num_fake_part;
182                                 int devlink_prio;
183                                 int event_timeout;
184                         };
185                 } key;
186         };
187 };
188
189 #define MAX_TK          64
190 struct rule_tmp {
191         struct udev_rules *rules;
192         struct token rule;
193         struct token token[MAX_TK];
194         unsigned int token_cur;
195 };
196
197 struct uid_gid {
198         unsigned int name_off;
199         union {
200                 uid_t   uid;
201                 gid_t   gid;
202         };
203 };
204
205 struct udev_rules {
206         struct udev *udev;
207         int resolve_names;
208
209         /* every key in the rules file becomes a token */
210         struct token *tokens;
211         unsigned int token_cur;
212         unsigned int token_max;
213
214         /* all key strings are copied to a single string buffer */
215         char *buf;
216         size_t buf_cur;
217         size_t buf_max;
218         unsigned int buf_count;
219
220         /* during rule parsing, we cache uid/gid lookup results */
221         struct uid_gid *uids;
222         unsigned int uids_cur;
223         unsigned int uids_max;
224         struct uid_gid *gids;
225         unsigned int gids_cur;
226         unsigned int gids_max;
227 };
228
229 /* NOTE: we could lookup and return existing strings, or tails of strings */
230 static int add_string(struct udev_rules *rules, const char *str)
231 {
232         size_t len = strlen(str)+1;
233         int off;
234
235         /* offset 0 is always '\0' */
236         if (str[0] == '\0')
237                 return 0;
238
239         /* grow buffer if needed */
240         if (rules->buf_cur + len+1 >= rules->buf_max) {
241                 char *buf;
242                 unsigned int add;
243
244                 /* double the buffer size */
245                 add = rules->buf_max;
246                 if (add < len * 8)
247                         add = len * 8;
248
249                 buf = realloc(rules->buf, rules->buf_max + add);
250                 if (buf == NULL)
251                         return -1;
252                 info(rules->udev, "extend buffer from %zu to %zu\n", rules->buf_max, rules->buf_max + add);
253                 rules->buf = buf;
254                 rules->buf_max += add;
255         }
256         off = rules->buf_cur;
257         memcpy(&rules->buf[rules->buf_cur], str, len);
258         rules->buf_cur += len;
259         rules->buf_count++;
260         return off;
261 }
262
263 static int add_token(struct udev_rules *rules, struct token *token)
264 {
265
266         /* grow buffer if needed */
267         if (rules->token_cur+1 >= rules->token_max) {
268                 struct token *tokens;
269                 unsigned int add;
270
271                 /* double the buffer size */
272                 add = rules->token_max;
273                 if (add < 8)
274                         add = 8;
275
276                 tokens = realloc(rules->tokens, (rules->token_max + add ) * sizeof(struct token));
277                 if (tokens == NULL)
278                         return -1;
279                 info(rules->udev, "extend tokens from %u to %u\n", rules->token_max, rules->token_max + add);
280                 rules->tokens = tokens;
281                 rules->token_max += add;
282         }
283         memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
284         rules->token_cur++;
285         return 0;
286 }
287
288 static uid_t add_uid(struct udev_rules *rules, const char *owner)
289 {
290         unsigned int i;
291         uid_t uid;
292         unsigned int off;
293
294         /* lookup, if we know it already */
295         for (i = 0; i < rules->uids_cur; i++) {
296                 off = rules->uids[i].name_off;
297                 if (strcmp(&rules->buf[off], owner) == 0) {
298                         uid = rules->uids[i].uid;
299                         dbg(rules->udev, "return existing %u for '%s'\n", uid, owner);
300                         return uid;
301                 }
302         }
303         uid = util_lookup_user(rules->udev, owner);
304
305         /* grow buffer if needed */
306         if (rules->uids_cur+1 >= rules->uids_max) {
307                 struct uid_gid *uids;
308                 unsigned int add;
309
310                 /* double the buffer size */
311                 add = rules->uids_max;
312                 if (add < 1)
313                         add = 8;
314
315                 uids = realloc(rules->uids, (rules->uids_max + add ) * sizeof(struct uid_gid));
316                 if (uids == NULL)
317                         return uid;
318                 info(rules->udev, "extend uids from %u to %u\n", rules->uids_max, rules->uids_max + add);
319                 rules->uids = uids;
320                 rules->uids_max += add;
321         }
322         rules->uids[rules->uids_cur].uid = uid;
323         off = add_string(rules, owner);
324         if (off <= 0)
325                 return uid;
326         rules->uids[rules->uids_cur].name_off = off;
327         rules->uids_cur++;
328         return uid;
329 }
330
331 static gid_t add_gid(struct udev_rules *rules, const char *group)
332 {
333         unsigned int i;
334         gid_t gid;
335         unsigned int off;
336
337         /* lookup, if we know it already */
338         for (i = 0; i < rules->gids_cur; i++) {
339                 off = rules->gids[i].name_off;
340                 if (strcmp(&rules->buf[off], group) == 0) {
341                         gid = rules->gids[i].gid;
342                         info(rules->udev, "return existing %u for '%s'\n", gid, group);
343                         return gid;
344                 }
345         }
346         gid = util_lookup_group(rules->udev, group);
347
348         /* grow buffer if needed */
349         if (rules->gids_cur+1 >= rules->gids_max) {
350                 struct uid_gid *gids;
351                 unsigned int add;
352
353                 /* double the buffer size */
354                 add = rules->gids_max;
355                 if (add < 1)
356                         add = 8;
357
358                 gids = realloc(rules->gids, (rules->gids_max + add ) * sizeof(struct uid_gid));
359                 if (gids == NULL)
360                         return gid;
361                 info(rules->udev, "extend gids from %u to %u\n", rules->gids_max, rules->gids_max + add);
362                 rules->gids = gids;
363                 rules->gids_max += add;
364         }
365         rules->gids[rules->gids_cur].gid = gid;
366         off = add_string(rules, group);
367         if (off <= 0)
368                 return gid;
369         rules->gids[rules->gids_cur].name_off = off;
370         rules->gids_cur++;
371         return gid;
372 }
373
374 static int import_property_from_string(struct udev_device *dev, char *line)
375 {
376         struct udev *udev = udev_device_get_udev(dev);
377         char *key;
378         char *val;
379         size_t len;
380
381         /* find key */
382         key = line;
383         while (isspace(key[0]))
384                 key++;
385
386         /* comment or empty line */
387         if (key[0] == '#' || key[0] == '\0')
388                 return -1;
389
390         /* split key/value */
391         val = strchr(key, '=');
392         if (val == NULL)
393                 return -1;
394         val[0] = '\0';
395         val++;
396
397         /* find value */
398         while (isspace(val[0]))
399                 val++;
400
401         /* terminate key */
402         len = strlen(key);
403         if (len == 0)
404                 return -1;
405         while (isspace(key[len-1]))
406                 len--;
407         key[len] = '\0';
408
409         /* terminate value */
410         len = strlen(val);
411         if (len == 0)
412                 return -1;
413         while (isspace(val[len-1]))
414                 len--;
415         val[len] = '\0';
416
417         if (len == 0)
418                 return -1;
419
420         /* unquote */
421         if (val[0] == '"' || val[0] == '\'') {
422                 if (val[len-1] != val[0]) {
423                         info(udev, "inconsistent quoting: '%s', skip\n", line);
424                         return -1;
425                 }
426                 val[len-1] = '\0';
427                 val++;
428         }
429
430         info(udev, "adding '%s'='%s'\n", key, val);
431
432         /* handle device, renamed by external tool, returning new path */
433         if (strcmp(key, "DEVPATH") == 0) {
434                 char syspath[UTIL_PATH_SIZE];
435
436                 info(udev, "updating devpath from '%s' to '%s'\n",
437                      udev_device_get_devpath(dev), val);
438                 util_strlcpy(syspath, udev_get_sys_path(udev), sizeof(syspath));
439                 util_strlcat(syspath, val, sizeof(syspath));
440                 udev_device_set_syspath(dev, syspath);
441         } else {
442                 struct udev_list_entry *entry;
443
444                 entry = udev_device_add_property(dev, key, val);
445                 /* store in db */
446                 udev_list_entry_set_flag(entry, 1);
447         }
448         return 0;
449 }
450
451 static int import_file_into_properties(struct udev_device *dev, const char *filename)
452 {
453         FILE *f;
454         char line[UTIL_LINE_SIZE];
455
456         f = fopen(filename, "r");
457         if (f == NULL)
458                 return -1;
459         while (fgets(line, sizeof(line), f) != NULL)
460                 import_property_from_string(dev, line);
461         fclose(f);
462         return 0;
463 }
464
465 static int import_program_into_properties(struct udev_device *dev, const char *program)
466 {
467         struct udev *udev = udev_device_get_udev(dev);
468         char **envp;
469         char result[2048];
470         size_t reslen;
471         char *line;
472
473         envp = udev_device_get_properties_envp(dev);
474         if (util_run_program(udev, program, envp, result, sizeof(result), &reslen) != 0)
475                 return -1;
476
477         line = result;
478         while (line != NULL) {
479                 char *pos;
480
481                 pos = strchr(line, '\n');
482                 if (pos != NULL) {
483                         pos[0] = '\0';
484                         pos = &pos[1];
485                 }
486                 import_property_from_string(dev, line);
487                 line = pos;
488         }
489         return 0;
490 }
491
492 static int import_parent_into_properties(struct udev_device *dev, const char *filter)
493 {
494         struct udev *udev = udev_device_get_udev(dev);
495         struct udev_device *dev_parent;
496         struct udev_list_entry *list_entry;
497
498         dev_parent = udev_device_get_parent(dev);
499         if (dev_parent == NULL)
500                 return -1;
501
502         dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
503         udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) {
504                 const char *key = udev_list_entry_get_name(list_entry);
505                 const char *val = udev_list_entry_get_value(list_entry);
506
507                 if (fnmatch(filter, key, 0) == 0) {
508                         struct udev_list_entry *entry;
509
510                         dbg(udev, "import key '%s=%s'\n", key, val);
511                         entry = udev_device_add_property(dev, key, val);
512                         /* store in db */
513                         udev_list_entry_set_flag(entry, 1);
514                 }
515         }
516         return 0;
517 }
518
519 #define WAIT_LOOP_PER_SECOND            50
520 static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
521 {
522         struct udev *udev = udev_device_get_udev(dev);
523         char filepath[UTIL_PATH_SIZE];
524         char devicepath[UTIL_PATH_SIZE] = "";
525         struct stat stats;
526         int loop = timeout * WAIT_LOOP_PER_SECOND;
527
528         /* a relative path is a device attribute */
529         if (file[0] != '/') {
530                 util_strlcpy(devicepath, udev_get_sys_path(udev), sizeof(devicepath));
531                 util_strlcat(devicepath, udev_device_get_devpath(dev), sizeof(devicepath));
532
533                 util_strlcpy(filepath, devicepath, sizeof(filepath));
534                 util_strlcat(filepath, "/", sizeof(filepath));
535                 util_strlcat(filepath, file, sizeof(filepath));
536                 file = filepath;
537         }
538
539         dbg(udev, "will wait %i sec for '%s'\n", timeout, file);
540         while (--loop) {
541                 /* lookup file */
542                 if (stat(file, &stats) == 0) {
543                         info(udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
544                         return 0;
545                 }
546                 /* make sure, the device did not disappear in the meantime */
547                 if (devicepath[0] != '\0' && stat(devicepath, &stats) != 0) {
548                         info(udev, "device disappeared while waiting for '%s'\n", file);
549                         return -2;
550                 }
551                 info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
552                 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
553         }
554         info(udev, "waiting for '%s' failed\n", file);
555         return -1;
556 }
557
558 static int attr_subst_subdir(char *attr, size_t len)
559 {
560         char *pos;
561         int found = 0;
562
563         pos = strstr(attr, "/*/");
564         if (pos != NULL) {
565                 char str[UTIL_PATH_SIZE];
566                 DIR *dir;
567
568                 pos[1] = '\0';
569                 util_strlcpy(str, &pos[2], sizeof(str));
570                 dir = opendir(attr);
571                 if (dir != NULL) {
572                         struct dirent *dent;
573
574                         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
575                                 struct stat stats;
576
577                                 if (dent->d_name[0] == '.')
578                                         continue;
579                                 util_strlcat(attr, dent->d_name, len);
580                                 util_strlcat(attr, str, len);
581                                 if (stat(attr, &stats) == 0) {
582                                         found = 1;
583                                         break;
584                                 }
585                                 pos[1] = '\0';
586                         }
587                         closedir(dir);
588                 }
589                 if (!found)
590                         util_strlcat(attr, str, len);
591         }
592
593         return found;
594 }
595
596 static int get_key(struct udev *udev, char **line, char **key, enum operation_type *op, char **value)
597 {
598         char *linepos;
599         char *temp;
600
601         linepos = *line;
602         if (linepos == NULL && linepos[0] == '\0')
603                 return -1;
604
605         /* skip whitespace */
606         while (isspace(linepos[0]) || linepos[0] == ',')
607                 linepos++;
608
609         /* get the key */
610         if (linepos[0] == '\0')
611                 return -1;
612         *key = linepos;
613
614         while (1) {
615                 linepos++;
616                 if (linepos[0] == '\0')
617                         return -1;
618                 if (isspace(linepos[0]))
619                         break;
620                 if (linepos[0] == '=')
621                         break;
622                 if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':'))
623                         if (linepos[1] == '=')
624                                 break;
625         }
626
627         /* remember end of key */
628         temp = linepos;
629
630         /* skip whitespace after key */
631         while (isspace(linepos[0]))
632                 linepos++;
633         if (linepos[0] == '\0')
634                 return -1;
635
636         /* get operation type */
637         if (linepos[0] == '=' && linepos[1] == '=') {
638                 *op = OP_MATCH;
639                 linepos += 2;
640         } else if (linepos[0] == '!' && linepos[1] == '=') {
641                 *op = OP_NOMATCH;
642                 linepos += 2;
643         } else if (linepos[0] == '+' && linepos[1] == '=') {
644                 *op = OP_ADD;
645                 linepos += 2;
646         } else if (linepos[0] == '=') {
647                 *op = OP_ASSIGN;
648                 linepos++;
649         } else if (linepos[0] == ':' && linepos[1] == '=') {
650                 *op = OP_ASSIGN_FINAL;
651                 linepos += 2;
652         } else
653                 return -1;
654
655         /* terminate key */
656         temp[0] = '\0';
657
658         /* skip whitespace after operator */
659         while (isspace(linepos[0]))
660                 linepos++;
661         if (linepos[0] == '\0')
662                 return -1;
663
664         /* get the value*/
665         if (linepos[0] == '"')
666                 linepos++;
667         else
668                 return -1;
669         *value = linepos;
670
671         temp = strchr(linepos, '"');
672         if (!temp)
673                 return -1;
674         temp[0] = '\0';
675         temp++;
676         dbg(udev, "%s '%s'-'%s'\n", operation_str[*op], *key, *value);
677
678         /* move line to next key */
679         *line = temp;
680         return 0;
681 }
682
683 /* extract possible KEY{attr} */
684 static char *get_key_attribute(struct udev *udev, char *str)
685 {
686         char *pos;
687         char *attr;
688
689         attr = strchr(str, '{');
690         if (attr != NULL) {
691                 attr++;
692                 pos = strchr(attr, '}');
693                 if (pos == NULL) {
694                         err(udev, "missing closing brace for format\n");
695                         return NULL;
696                 }
697                 pos[0] = '\0';
698                 dbg(udev, "attribute='%s'\n", attr);
699                 return attr;
700         }
701         return NULL;
702 }
703
704 static int rule_add_token(struct rule_tmp *rule_tmp, enum token_type type,
705                           enum operation_type op,
706                           const char *value, const void *data)
707 {
708         struct token *token = &rule_tmp->token[rule_tmp->token_cur];
709         const char *attr = data;
710         mode_t mode = 0000;
711
712         switch (type) {
713         case TK_M_ACTION:
714         case TK_M_DEVPATH:
715         case TK_M_KERNEL:
716         case TK_M_SUBSYSTEM:
717         case TK_M_DRIVER:
718         case TK_M_WAITFOR:
719         case TK_M_DEVLINK:
720         case TK_M_NAME:
721         case TK_M_KERNELS:
722         case TK_M_SUBSYSTEMS:
723         case TK_M_DRIVERS:
724         case TK_M_PROGRAM:
725         case TK_M_IMPORT_FILE:
726         case TK_M_IMPORT_PROG:
727         case TK_M_IMPORT_PARENT:
728         case TK_M_RESULT:
729         case TK_A_OWNER:
730         case TK_A_GROUP:
731         case TK_A_MODE:
732         case TK_A_NAME:
733         case TK_A_DEVLINK:
734         case TK_A_GOTO:
735                 token->key.value_off = add_string(rule_tmp->rules, value);
736                 break;
737         case TK_M_ENV:
738         case TK_M_ATTR:
739         case TK_M_ATTRS:
740         case TK_A_ATTR:
741         case TK_A_ENV:
742                 token->key.value_off = add_string(rule_tmp->rules, value);
743                 token->key.attr_off = add_string(rule_tmp->rules, attr);
744                 break;
745         case TK_M_TEST:
746                 if (data != NULL)
747                         mode = *(mode_t *)data;
748                 token->key.value_off = add_string(rule_tmp->rules, value);
749                 token->key.mode = mode;
750                 break;
751         case TK_A_IGNORE_DEVICE:
752         case TK_A_STRING_ESCAPE_NONE:
753         case TK_A_STRING_ESCAPE_REPLACE:
754         case TK_A_IGNORE_REMOVE:
755         case TK_A_LAST_RULE:
756                 break;
757         case TK_A_RUN:
758                 token->key.value_off = add_string(rule_tmp->rules, value);
759                 token->key.ignore_error = *(int *)data;
760                 break;
761         case TK_A_NUM_FAKE_PART:
762                 token->key.num_fake_part = *(int *)data;
763                 break;
764         case TK_A_DEVLINK_PRIO:
765                 token->key.devlink_prio = *(int *)data;
766                 break;
767         case TK_A_OWNER_ID:
768                 token->key.uid = *(uid_t *)data;
769                 break;
770         case TK_A_GROUP_ID:
771                 token->key.gid = *(gid_t *)data;
772                 break;
773         case TK_A_MODE_ID:
774                 token->key.mode = *(mode_t *)data;
775                 break;
776         case TK_A_EVENT_TIMEOUT:
777                 token->key.event_timeout = *(int *)data;
778                 break;
779         case TK_RULE:
780         case TK_M_PARENTS_MAX:
781         case TK_END:
782         case TK_UNDEF:
783                 err(rule_tmp->rules->udev, "wrong type %u\n", type);
784                 return -1;
785         }
786         token->type = type;
787         token->key.op = op;
788         rule_tmp->token_cur++;
789         if (rule_tmp->token_cur >= ARRAY_SIZE(rule_tmp->token)) {
790                 err(rule_tmp->rules->udev, "temporary rule array too small\n");
791                 return -1;
792         }
793         return 0;
794 }
795
796 #ifdef DEBUG
797 static void dump_token(struct udev_rules *rules, struct token *token)
798 {
799         enum token_type type = token->type;
800         enum operation_type op = token->key.op;
801         const char *value = &rules->buf[token->key.value_off];
802         const char *attr = &rules->buf[token->key.attr_off];
803
804         switch (type) {
805         case TK_RULE:
806                 {
807                         const char *tks_ptr = (char *)rules->tokens;
808                         const char *tk_ptr = (char *)token;
809                         unsigned int off = tk_ptr - tks_ptr;
810
811                         dbg(rules->udev, "* RULE '%s', off: %u(%u), next: %u, label: '%s'\n",
812                             &rules->buf[token->rule.filename_off],
813                             off / (unsigned int) sizeof(struct token), off,
814                             token->rule.next_rule,
815                             &rules->buf[token->rule.label_off]);
816                         break;
817                 }
818         case TK_M_ACTION:
819         case TK_M_DEVPATH:
820         case TK_M_KERNEL:
821         case TK_M_SUBSYSTEM:
822         case TK_M_DRIVER:
823         case TK_M_WAITFOR:
824         case TK_M_DEVLINK:
825         case TK_M_NAME:
826         case TK_M_KERNELS:
827         case TK_M_SUBSYSTEMS:
828         case TK_M_DRIVERS:
829         case TK_M_PROGRAM:
830         case TK_M_IMPORT_FILE:
831         case TK_M_IMPORT_PROG:
832         case TK_M_IMPORT_PARENT:
833         case TK_M_RESULT:
834         case TK_A_NAME:
835         case TK_A_DEVLINK:
836         case TK_A_OWNER:
837         case TK_A_GROUP:
838         case TK_A_MODE:
839         case TK_A_RUN:
840                 dbg(rules->udev, "%s %s '%s'\n", token_str[type], operation_str[op], value);
841                 break;
842         case TK_M_ATTR:
843         case TK_M_ATTRS:
844         case TK_M_ENV:
845         case TK_A_ATTR:
846         case TK_A_ENV:
847                 dbg(rules->udev, "%s %s '%s' '%s'\n", token_str[type], operation_str[op], attr, value);
848                 break;
849         case TK_A_IGNORE_DEVICE:
850         case TK_A_STRING_ESCAPE_NONE:
851         case TK_A_STRING_ESCAPE_REPLACE:
852         case TK_A_LAST_RULE:
853         case TK_A_IGNORE_REMOVE:
854                 dbg(rules->udev, "%s\n", token_str[type]);
855                 break;
856         case TK_M_TEST:
857                 dbg(rules->udev, "%s %s '%s' %#o\n", token_str[type], operation_str[op], value, token->key.mode);
858                 break;
859         case TK_A_NUM_FAKE_PART:
860                 dbg(rules->udev, "%s %u\n", token_str[type], token->key.num_fake_part);
861                 break;
862         case TK_A_DEVLINK_PRIO:
863                 dbg(rules->udev, "%s %s %u\n", token_str[type], operation_str[op], token->key.devlink_prio);
864                 break;
865         case TK_A_OWNER_ID:
866                 dbg(rules->udev, "%s %s %u\n", token_str[type], operation_str[op], token->key.uid);
867                 break;
868         case TK_A_GROUP_ID:
869                 dbg(rules->udev, "%s %s %u\n", token_str[type], operation_str[op], token->key.gid);
870                 break;
871         case TK_A_MODE_ID:
872                 dbg(rules->udev, "%s %s %#o\n", token_str[type], operation_str[op], token->key.mode);
873                 break;
874         case TK_A_EVENT_TIMEOUT:
875                 dbg(rules->udev, "%s %s %u\n", token_str[type], operation_str[op], token->key.event_timeout);
876                 break;
877         case TK_A_GOTO:
878                 dbg(rules->udev, "%s '%s' %u\n", token_str[type], value, token->key.rule_goto);
879                 break;
880         case TK_END:
881                 dbg(rules->udev, "* %s\n", token_str[type]);
882                 break;
883         case TK_M_PARENTS_MAX:
884         case TK_UNDEF:
885                 dbg(rules->udev, "unknown type %u\n", type);
886                 break;
887         }
888 }
889
890 static void dump_rules(struct udev_rules *rules)
891 {
892         unsigned int i;
893
894         dbg(rules->udev, "dumping %u (%zu bytes) tokens, %u (%zu bytes) strings\n",
895             rules->token_cur,
896             rules->token_cur * sizeof(struct token),
897             rules->buf_count,
898             rules->buf_cur);
899         for(i = 0; i < rules->token_cur; i++)
900                 dump_token(rules, &rules->tokens[i]);
901 }
902 #else
903 static inline void dump_token(struct udev_rules *rules, struct token *token) {}
904 static inline void dump_rules(struct udev_rules *rules) {}
905 #endif /* DEBUG */
906
907 static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp)
908 {
909         unsigned int i;
910         unsigned int start = 0;
911         unsigned int end = rule_tmp->token_cur;
912
913         for (i = 0; i < rule_tmp->token_cur; i++) {
914                 enum token_type next_val = TK_UNDEF;
915                 unsigned int next_idx;
916                 unsigned int j;
917
918                 /* find smallest value */
919                 for (j = start; j < end; j++) {
920                         if (rule_tmp->token[j].type == TK_UNDEF)
921                                 continue;
922                         if (next_val == TK_UNDEF || rule_tmp->token[j].type < next_val) {
923                                 next_val = rule_tmp->token[j].type;
924                                 next_idx = j;
925                         }
926                 }
927
928                 /* add token and mark done */
929                 if (add_token(rules, &rule_tmp->token[next_idx]) != 0)
930                         return -1;
931                 rule_tmp->token[next_idx].type = TK_UNDEF;
932
933                 /* shrink range */
934                 if (next_idx == start)
935                         start++;
936                 if (next_idx+1 == end)
937                         end--;
938         }
939         return 0;
940 }
941
942 static int add_rule(struct udev_rules *rules, char *line,
943                     const char *filename, unsigned int filename_off, unsigned int lineno)
944 {
945         int valid = 0;
946         char *linepos;
947         char *attr;
948         int physdev = 0;
949         struct rule_tmp rule_tmp;
950
951         memset(&rule_tmp, 0x00, sizeof(struct rule_tmp));
952         rule_tmp.rules = rules;
953         rule_tmp.rule.type = TK_RULE;
954         rule_tmp.rule.rule.filename_off = filename_off;
955
956         linepos = line;
957         while (1) {
958                 char *key;
959                 char *value;
960                 enum operation_type op = OP_UNSET;
961
962                 if (get_key(rules->udev, &linepos, &key, &op, &value) != 0)
963                         break;
964
965                 if (strcasecmp(key, "ACTION") == 0) {
966                         if (op > OP_MATCH_MAX) {
967                                 err(rules->udev, "invalid ACTION operation\n");
968                                 goto invalid;
969                         }
970                         rule_add_token(&rule_tmp, TK_M_ACTION, op, value, NULL);
971                         valid = 1;
972                         continue;
973                 }
974
975                 if (strcasecmp(key, "DEVPATH") == 0) {
976                         if (op > OP_MATCH_MAX) {
977                                 err(rules->udev, "invalid DEVPATH operation\n");
978                                 goto invalid;
979                         }
980                         rule_add_token(&rule_tmp, TK_M_DEVPATH, op, value, NULL);
981                         valid = 1;
982                         continue;
983                 }
984
985                 if (strcasecmp(key, "KERNEL") == 0) {
986                         if (op > OP_MATCH_MAX) {
987                                 err(rules->udev, "invalid KERNEL operation\n");
988                                 goto invalid;
989                         }
990                         rule_add_token(&rule_tmp, TK_M_KERNEL, op, value, NULL);
991                         valid = 1;
992                         continue;
993                 }
994
995                 if (strcasecmp(key, "SUBSYSTEM") == 0) {
996                         if (op > OP_MATCH_MAX) {
997                                 err(rules->udev, "invalid SUBSYSTEM operation\n");
998                                 goto invalid;
999                         }
1000                         /* bus, class, subsystem events should all be the same */
1001                         if (strcmp(value, "subsystem") == 0 ||
1002                             strcmp(value, "bus") == 0 ||
1003                             strcmp(value, "class") == 0) {
1004                                 if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
1005                                         err(rules->udev, "'%s' must be specified as 'subsystem' \n"
1006                                             "please fix it in %s:%u", value, filename, lineno);
1007                                 rule_add_token(&rule_tmp, TK_M_SUBSYSTEM, op, "subsystem|class|bus", NULL);
1008                         } else
1009                                 rule_add_token(&rule_tmp, TK_M_SUBSYSTEM, op, value, NULL);
1010                         valid = 1;
1011                         continue;
1012                 }
1013
1014                 if (strcasecmp(key, "DRIVER") == 0) {
1015                         if (op > OP_MATCH_MAX) {
1016                                 err(rules->udev, "invalid DRIVER operation\n");
1017                                 goto invalid;
1018                         }
1019                         rule_add_token(&rule_tmp, TK_M_DRIVER, op, value, NULL);
1020                         valid = 1;
1021                         continue;
1022                 }
1023
1024                 if (strncasecmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
1025                         attr = get_key_attribute(rules->udev, key + sizeof("ATTR")-1);
1026                         if (attr == NULL) {
1027                                 err(rules->udev, "error parsing ATTR attribute\n");
1028                                 goto invalid;
1029                         }
1030                         if (op < OP_MATCH_MAX) {
1031                                 rule_add_token(&rule_tmp, TK_M_ATTR, op, value, attr);
1032                         } else {
1033                                 rule_add_token(&rule_tmp, TK_A_ATTR, op, value, attr);
1034                         }
1035                         valid = 1;
1036                         continue;
1037                 }
1038
1039                 if (strcasecmp(key, "KERNELS") == 0 ||
1040                     strcasecmp(key, "ID") == 0) {
1041                         if (op > OP_MATCH_MAX) {
1042                                 err(rules->udev, "invalid KERNELS operation\n");
1043                                 goto invalid;
1044                         }
1045                         rule_add_token(&rule_tmp, TK_M_KERNELS, op, value, NULL);
1046                         valid = 1;
1047                         continue;
1048                 }
1049
1050                 if (strcasecmp(key, "SUBSYSTEMS") == 0 ||
1051                     strcasecmp(key, "BUS") == 0) {
1052                         if (op > OP_MATCH_MAX) {
1053                                 err(rules->udev, "invalid SUBSYSTEMS operation\n");
1054                                 goto invalid;
1055                         }
1056                         rule_add_token(&rule_tmp, TK_M_SUBSYSTEMS, op, value, NULL);
1057                         valid = 1;
1058                         continue;
1059                 }
1060
1061                 if (strcasecmp(key, "DRIVERS") == 0) {
1062                         if (op > OP_MATCH_MAX) {
1063                                 err(rules->udev, "invalid DRIVERS operation\n");
1064                                 goto invalid;
1065                         }
1066                         rule_add_token(&rule_tmp, TK_M_DRIVERS, op, value, NULL);
1067                         valid = 1;
1068                         continue;
1069                 }
1070
1071                 if (strncasecmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 ||
1072                     strncasecmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
1073                         if (op > OP_MATCH_MAX) {
1074                                 err(rules->udev, "invalid ATTRS operation\n");
1075                                 goto invalid;
1076                         }
1077                         attr = get_key_attribute(rules->udev, key + sizeof("ATTRS")-1);
1078                         if (attr == NULL) {
1079                                 err(rules->udev, "error parsing ATTRS attribute\n");
1080                                 goto invalid;
1081                         }
1082                         if (strncmp(attr, "device/", 7) == 0)
1083                                 err(rules->udev, "the 'device' link may not be available in a future kernel, "
1084                                     "please fix it in %s:%u", filename, lineno);
1085                         else if (strstr(attr, "../") != NULL)
1086                                 err(rules->udev, "do not reference parent sysfs directories directly, "
1087                                     "it may break with a future kernel, please fix it in %s:%u", filename, lineno);
1088                         rule_add_token(&rule_tmp, TK_M_ATTRS, op, value, attr);
1089                         valid = 1;
1090                         continue;
1091                 }
1092
1093                 if (strncasecmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
1094                         attr = get_key_attribute(rules->udev, key + sizeof("ENV")-1);
1095                         if (attr == NULL) {
1096                                 err(rules->udev, "error parsing ENV attribute\n");
1097                                 goto invalid;
1098                         }
1099                         if (strncmp(attr, "PHYSDEV", 7) == 0)
1100                                 physdev = 1;
1101                         if (op < OP_MATCH_MAX) {
1102                                 if (rule_add_token(&rule_tmp, TK_M_ENV, op, value, attr) != 0)
1103                                         goto invalid;
1104                         } else {
1105                                 if (rule_add_token(&rule_tmp, TK_A_ENV, op, value, attr) != 0)
1106                                         goto invalid;
1107                         }
1108                         valid = 1;
1109                         continue;
1110                 }
1111
1112                 if (strcasecmp(key, "PROGRAM") == 0) {
1113                         rule_add_token(&rule_tmp, TK_M_PROGRAM, op, value, NULL);
1114                         valid = 1;
1115                         continue;
1116                 }
1117
1118                 if (strcasecmp(key, "RESULT") == 0) {
1119                         if (op > OP_MATCH_MAX) {
1120                                 err(rules->udev, "invalid RESULT operation\n");
1121                                 goto invalid;
1122                         }
1123                         rule_add_token(&rule_tmp, TK_M_RESULT, op, value, NULL);
1124                         valid = 1;
1125                         continue;
1126                 }
1127
1128                 if (strncasecmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
1129                         attr = get_key_attribute(rules->udev, key + sizeof("IMPORT")-1);
1130                         if (attr != NULL && strstr(attr, "program")) {
1131                                 dbg(rules->udev, "IMPORT will be executed\n");
1132                                 rule_add_token(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
1133                                 valid = 1;
1134                         } else if (attr != NULL && strstr(attr, "file")) {
1135                                 dbg(rules->udev, "IMPORT will be included as file\n");
1136                                 rule_add_token(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
1137                                 valid = 1;
1138                         } else if (attr != NULL && strstr(attr, "parent")) {
1139                                 dbg(rules->udev, "IMPORT will include the parent values\n");
1140                                 rule_add_token(&rule_tmp, TK_M_IMPORT_PARENT, op, value, NULL);
1141                                 valid = 1;
1142                         } else {
1143                                 /* figure it out if it is executable */
1144                                 char file[UTIL_PATH_SIZE];
1145                                 char *pos;
1146                                 struct stat statbuf;
1147
1148                                 util_strlcpy(file, value, sizeof(file));
1149                                 pos = strchr(file, ' ');
1150                                 if (pos)
1151                                         pos[0] = '\0';
1152
1153                                 /* allow programs in /lib/udev called without the path */
1154                                 if (strchr(file, '/') == NULL) {
1155                                         util_strlcpy(file, UDEV_PREFIX "/lib/udev/", sizeof(file));
1156                                         util_strlcat(file, value, sizeof(file));
1157                                         pos = strchr(file, ' ');
1158                                         if (pos)
1159                                                 pos[0] = '\0';
1160                                 }
1161
1162                                 dbg(rules->udev, "IMPORT auto mode for '%s'\n", file);
1163                                 if (!lstat(file, &statbuf) && (statbuf.st_mode & S_IXUSR)) {
1164                                         dbg(rules->udev, "IMPORT will be executed (autotype)\n");
1165                                         rule_add_token(&rule_tmp, TK_M_IMPORT_PROG, op, value, NULL);
1166                                         valid = 1;
1167                                 } else {
1168                                         dbg(rules->udev, "IMPORT will be included as file (autotype)\n");
1169                                         rule_add_token(&rule_tmp, TK_M_IMPORT_FILE, op, value, NULL);
1170                                         valid = 1;
1171                                 }
1172                         }
1173                         continue;
1174                 }
1175
1176                 if (strncasecmp(key, "TEST", sizeof("TEST")-1) == 0) {
1177                         mode_t mode = 0;
1178
1179                         if (op > OP_MATCH_MAX) {
1180                                 err(rules->udev, "invalid TEST operation\n");
1181                                 goto invalid;
1182                         }
1183                         attr = get_key_attribute(rules->udev, key + sizeof("TEST")-1);
1184                         if (attr != NULL) {
1185                                 mode = strtol(attr, NULL, 8);
1186                                 rule_add_token(&rule_tmp, TK_M_TEST, op, value, &mode);
1187                         } else {
1188                                 rule_add_token(&rule_tmp, TK_M_TEST, op, value, NULL);
1189                         }
1190                         valid = 1;
1191                         continue;
1192                 }
1193
1194                 if (strncasecmp(key, "RUN", sizeof("RUN")-1) == 0) {
1195                         int flag = 0;
1196
1197                         attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1);
1198                         if (attr != NULL && strstr(attr, "ignore_error"))
1199                                 flag = 1;
1200                         rule_add_token(&rule_tmp, TK_A_RUN, op, value, &flag);
1201                         valid = 1;
1202                         continue;
1203                 }
1204
1205                 if (strcasecmp(key, "WAIT_FOR") == 0 || strcasecmp(key, "WAIT_FOR_SYSFS") == 0) {
1206                         rule_add_token(&rule_tmp, TK_M_WAITFOR, 0, value, NULL);
1207                         valid = 1;
1208                         continue;
1209                 }
1210
1211                 if (strcasecmp(key, "LABEL") == 0) {
1212                         rule_tmp.rule.rule.label_off = add_string(rules, value);
1213                         valid = 1;
1214                         continue;
1215                 }
1216
1217                 if (strcasecmp(key, "GOTO") == 0) {
1218                         rule_add_token(&rule_tmp, TK_A_GOTO, 0, value, NULL);
1219                         valid = 1;
1220                         continue;
1221                 }
1222
1223                 if (strncasecmp(key, "NAME", sizeof("NAME")-1) == 0) {
1224                         if (op < OP_MATCH_MAX) {
1225                                 rule_add_token(&rule_tmp, TK_M_NAME, op, value, NULL);
1226                         } else {
1227                                 if (value[0] == '\0')
1228                                         dbg(rules->udev, "name empty, node creation suppressed\n");
1229                                 rule_add_token(&rule_tmp, TK_A_NAME, op, value, NULL);
1230                                 attr = get_key_attribute(rules->udev, key + sizeof("NAME")-1);
1231                                 if (attr != NULL) {
1232                                         if (strstr(attr, "all_partitions") != NULL) {
1233                                                 int num = DEFAULT_FAKE_PARTITIONS_COUNT;
1234
1235                                                 dbg(rules->udev, "creation of partition nodes requested\n");
1236                                                 rule_add_token(&rule_tmp, TK_A_NUM_FAKE_PART, 0, NULL, &num);
1237                                         }
1238                                         if (strstr(attr, "ignore_remove") != NULL) {
1239                                                 dbg(rules->udev, "remove event should be ignored\n");
1240                                                 rule_add_token(&rule_tmp, TK_A_IGNORE_REMOVE, 0, NULL, NULL);
1241                                         }
1242                                 }
1243                         }
1244                         continue;
1245                 }
1246
1247                 if (strcasecmp(key, "SYMLINK") == 0) {
1248                         if (op < OP_MATCH_MAX)
1249                                 rule_add_token(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
1250                         else
1251                                 rule_add_token(&rule_tmp, TK_A_DEVLINK, op, value, NULL);
1252                         valid = 1;
1253                         continue;
1254                 }
1255
1256                 if (strcasecmp(key, "OWNER") == 0) {
1257                         uid_t uid;
1258                         char *endptr;
1259
1260                         uid = strtoul(value, &endptr, 10);
1261                         if (endptr[0] == '\0') {
1262                                 rule_add_token(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
1263                         } else if (rules->resolve_names && strchr("$%", value[0]) == NULL) {
1264                                 uid = add_uid(rules, value);
1265                                 rule_add_token(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
1266                         } else {
1267                                 rule_add_token(&rule_tmp, TK_A_OWNER, op, value, NULL);
1268                         }
1269                         valid = 1;
1270                         continue;
1271                 }
1272
1273                 if (strcasecmp(key, "GROUP") == 0) {
1274                         gid_t gid;
1275                         char *endptr;
1276
1277                         gid = strtoul(value, &endptr, 10);
1278                         if (endptr[0] == '\0') {
1279                                 rule_add_token(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
1280                         } else if (rules->resolve_names && strchr("$%", value[0]) == NULL) {
1281                                 gid = add_gid(rules, value);
1282                                 rule_add_token(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
1283                         } else {
1284                                 rule_add_token(&rule_tmp, TK_A_GROUP, op, value, NULL);
1285                         }
1286                         valid = 1;
1287                         continue;
1288                 }
1289
1290                 if (strcasecmp(key, "MODE") == 0) {
1291                         mode_t mode;
1292                         char *endptr;
1293
1294                         mode = strtol(value, &endptr, 8);
1295                         if (endptr[0] == '\0')
1296                                 rule_add_token(&rule_tmp, TK_A_MODE_ID, op, NULL, &mode);
1297                         else
1298                                 rule_add_token(&rule_tmp, TK_A_MODE, op, value, NULL);
1299                         valid = 1;
1300                         continue;
1301                 }
1302
1303                 if (strcasecmp(key, "OPTIONS") == 0) {
1304                         const char *pos;
1305
1306                         if (strstr(value, "last_rule") != NULL) {
1307                                 dbg(rules->udev, "last rule to be applied\n");
1308                                 rule_add_token(&rule_tmp, TK_A_LAST_RULE, 0, NULL, NULL);
1309                         }
1310                         if (strstr(value, "ignore_device") != NULL) {
1311                                 dbg(rules->udev, "device should be ignored\n");
1312                                 rule_add_token(&rule_tmp, TK_A_IGNORE_DEVICE, 0, NULL, NULL);
1313                         }
1314                         if (strstr(value, "ignore_remove") != NULL) {
1315                                 dbg(rules->udev, "remove event should be ignored\n");
1316                                 rule_add_token(&rule_tmp, TK_A_IGNORE_REMOVE, 0, NULL, NULL);
1317                         }
1318                         pos = strstr(value, "link_priority=");
1319                         if (pos != NULL) {
1320                                 int prio = atoi(&pos[strlen("link_priority=")]);
1321
1322                                 rule_add_token(&rule_tmp, TK_A_DEVLINK_PRIO, 0, NULL, &prio);
1323                                 dbg(rules->udev, "link priority=%i\n", prio);
1324                         }
1325                         pos = strstr(value, "event_timeout=");
1326                         if (pos != NULL) {
1327                                 int tout = atoi(&pos[strlen("event_timeout=")]);
1328
1329                                 rule_add_token(&rule_tmp, TK_A_EVENT_TIMEOUT, 0, NULL, &tout);
1330                                 dbg(rules->udev, "event timout=%i\n", tout);
1331                         }
1332                         pos = strstr(value, "string_escape=");
1333                         if (pos != NULL) {
1334                                 pos = &pos[strlen("string_escape=")];
1335                                 if (strncmp(pos, "none", strlen("none")) == 0)
1336                                         rule_add_token(&rule_tmp, TK_A_STRING_ESCAPE_NONE, 0, NULL, NULL);
1337                                 else if (strncmp(pos, "replace", strlen("replace")) == 0)
1338                                         rule_add_token(&rule_tmp, TK_A_STRING_ESCAPE_REPLACE, 0, NULL, NULL);
1339                         }
1340                         if (strstr(value, "all_partitions") != NULL) {
1341                                 int num = DEFAULT_FAKE_PARTITIONS_COUNT;
1342
1343                                 rule_add_token(&rule_tmp, TK_A_NUM_FAKE_PART, 0, NULL, &num);
1344                                 dbg(rules->udev, "creation of partition nodes requested\n");
1345                         }
1346                         valid = 1;
1347                         continue;
1348                 }
1349                 err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
1350         }
1351
1352         if (physdev)
1353                 err(rules->udev, "PHYSDEV* values are deprecated and not available on recent kernels, \n"
1354                     "please fix it in %s:%u", filename, lineno);
1355
1356         /* skip line if not any valid key was found */
1357         if (!valid)
1358                 goto invalid;
1359
1360         /* add rule token */
1361         if (add_token(rules, &rule_tmp.rule) != 0)
1362                 goto invalid;
1363
1364         /* add tokens to list, sorted by type */
1365         if (sort_token(rules, &rule_tmp) != 0)
1366                 goto invalid;
1367         return 0;
1368 invalid:
1369         err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
1370         return -1;
1371 }
1372
1373 static int parse_file(struct udev_rules *rules, const char *filename)
1374 {
1375         FILE *f;
1376         unsigned int filename_off;
1377         unsigned int first_token;
1378         char line[UTIL_LINE_SIZE];
1379         int line_nr = 0;
1380         unsigned int i;
1381
1382         info(rules->udev, "reading '%s' as rules file\n", filename);
1383
1384         f = fopen(filename, "r");
1385         if (f == NULL)
1386                 return -1;
1387
1388         filename_off = add_string(rules, filename);
1389         first_token = rules->token_cur;
1390
1391         while(fgets(line, sizeof(line), f) != NULL) {
1392                 char *key;
1393                 size_t len;
1394
1395                 /* skip whitespace */
1396                 line_nr++;
1397                 key = line;
1398                 while (isspace(key[0]))
1399                         key++;
1400
1401                 /* comment */
1402                 if (key[0] == '#')
1403                         continue;
1404
1405                 len = strlen(line);
1406                 if (len < 3)
1407                         continue;
1408
1409                 /* continue reading if backslash+newline is found */
1410                 while (line[len-2] == '\\') {
1411                         if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL)
1412                                 break;
1413                         line_nr++;
1414                         len = strlen(line);
1415                 }
1416
1417                 if (len+1 >= sizeof(line)) {
1418                         err(rules->udev, "line too long '%s':%u, ignored\n", filename, line_nr);
1419                         continue;
1420                 }
1421                 add_rule(rules, key, filename, filename_off, line_nr);
1422         }
1423         fclose(f);
1424
1425         /* link GOTOs to LABEL rules in this file to be able to fast-forward */
1426         for (i = first_token+1; i < rules->token_cur; i++) {
1427                 if (rules->tokens[i].type == TK_A_GOTO) {
1428                         char *label = &rules->buf[rules->tokens[i].key.value_off];
1429                         unsigned int j;
1430
1431                         for (j = i+1; j < rules->token_cur; j++) {
1432                                 if (rules->tokens[j].type != TK_RULE)
1433                                         continue;
1434                                 if (rules->tokens[j].rule.label_off == 0)
1435                                         continue;
1436                                 if (strcmp(label, &rules->buf[rules->tokens[j].rule.label_off]) != 0)
1437                                         continue;
1438                                 rules->tokens[i].key.rule_goto = j;
1439                         }
1440                         if (rules->tokens[i].key.rule_goto == 0)
1441                                 err(rules->udev, "GOTO '%s' has no matching label in: '%s'\n", label, filename);
1442                 }
1443         }
1444         return 0;
1445 }
1446
1447 static int add_matching_files(struct udev *udev, struct udev_list_node *file_list, const char *dirname, const char *suffix)
1448 {
1449         struct dirent *ent;
1450         DIR *dir;
1451         char filename[UTIL_PATH_SIZE];
1452
1453         dbg(udev, "open directory '%s'\n", dirname);
1454         dir = opendir(dirname);
1455         if (dir == NULL) {
1456                 err(udev, "unable to open '%s': %m\n", dirname);
1457                 return -1;
1458         }
1459
1460         while (1) {
1461                 ent = readdir(dir);
1462                 if (ent == NULL || ent->d_name[0] == '\0')
1463                         break;
1464
1465                 if ((ent->d_name[0] == '.') || (ent->d_name[0] == '#'))
1466                         continue;
1467
1468                 /* look for file matching with specified suffix */
1469                 if (suffix != NULL) {
1470                         const char *ext;
1471
1472                         ext = strrchr(ent->d_name, '.');
1473                         if (ext == NULL)
1474                                 continue;
1475                         if (strcmp(ext, suffix) != 0)
1476                                 continue;
1477                 }
1478                 dbg(udev, "put file '%s/%s' into list\n", dirname, ent->d_name);
1479
1480                 snprintf(filename, sizeof(filename), "%s/%s", dirname, ent->d_name);
1481                 filename[sizeof(filename)-1] = '\0';
1482                 udev_list_entry_add(udev, file_list, filename, NULL, 1, 1);
1483         }
1484
1485         closedir(dir);
1486         return 0;
1487 }
1488
1489 struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
1490 {
1491         struct udev_rules *rules;
1492         struct stat statbuf;
1493         char filename[PATH_MAX];
1494         struct udev_list_node file_list;
1495         struct udev_list_entry *file_loop, *file_tmp;
1496         unsigned int prev_rule;
1497         struct token end_token;
1498         unsigned int i;
1499
1500         rules = malloc(sizeof(struct udev_rules));
1501         if (rules == NULL)
1502                 return NULL;
1503         memset(rules, 0x00, sizeof(struct udev_rules));
1504         rules->udev = udev;
1505         rules->resolve_names = resolve_names;
1506         udev_list_init(&file_list);
1507
1508         /* init token array and string buffer */
1509         rules->tokens = malloc(PREALLOC_TOKEN * sizeof(struct token));
1510         if (rules->tokens == NULL)
1511                 return NULL;
1512         rules->token_max = PREALLOC_TOKEN;
1513         rules->buf = malloc(PREALLOC_STRBUF);
1514         if (rules->buf == NULL)
1515                 return NULL;
1516         rules->buf_max = PREALLOC_STRBUF;
1517         /* offset 0 is always '\0' */
1518         rules->buf[0] = '\0';
1519         rules->buf_cur = 1;
1520         info(udev, "prealloc %zu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
1521              rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
1522
1523         if (udev_get_rules_path(udev) != NULL) {
1524                 /* custom rules location for testing */
1525                 add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
1526         } else {
1527                 struct udev_list_node sort_list;
1528                 struct udev_list_entry *sort_loop, *sort_tmp;
1529
1530                 /* read user/custom rules */
1531                 add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules");
1532
1533                 /* read dynamic/temporary rules */
1534                 util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
1535                 util_strlcat(filename, "/.udev/rules.d", sizeof(filename));
1536                 if (stat(filename, &statbuf) != 0) {
1537                         util_create_path(udev, filename);
1538                         udev_selinux_setfscreatecon(udev, filename, S_IFDIR|0755);
1539                         mkdir(filename, 0755);
1540                         udev_selinux_resetfscreatecon(udev);
1541                 }
1542                 udev_list_init(&sort_list);
1543                 add_matching_files(udev, &sort_list, filename, ".rules");
1544
1545                 /* read default rules */
1546                 add_matching_files(udev, &sort_list, UDEV_PREFIX "/lib/udev/rules.d", ".rules");
1547
1548                 /* sort all rules files by basename into list of files */
1549                 udev_list_entry_foreach_safe(sort_loop, sort_tmp, udev_list_get_entry(&sort_list)) {
1550                         const char *sort_name = udev_list_entry_get_name(sort_loop);
1551                         const char *sort_base = strrchr(sort_name, '/');
1552
1553                         if (sort_base == NULL)
1554                                 continue;
1555
1556                         udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
1557                                 const char *file_name = udev_list_entry_get_name(file_loop);
1558                                 const char *file_base = strrchr(file_name, '/');
1559
1560                                 if (file_base == NULL)
1561                                         continue;
1562                                 if (strcmp(file_base, sort_base) == 0) {
1563                                         info(udev, "rule file basename '%s' already added, ignoring '%s'\n",
1564                                              file_name, sort_name);
1565                                         udev_list_entry_remove(sort_loop);
1566                                         sort_loop = NULL;
1567                                         break;
1568                                 }
1569                                 if (strcmp(file_base, sort_base) > 0)
1570                                         break;
1571                         }
1572                         if (sort_loop != NULL)
1573                                 udev_list_entry_move_before(sort_loop, file_loop);
1574                 }
1575         }
1576
1577         /* parse list of files */
1578         udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
1579                 const char *file_name = udev_list_entry_get_name(file_loop);
1580
1581                 if (stat(file_name, &statbuf) == 0 && statbuf.st_size > 0)
1582                         parse_file(rules, file_name);
1583                 else
1584                         info(udev, "can not read '%s'\n", file_name);
1585                 udev_list_entry_remove(file_loop);
1586         }
1587
1588         memset(&end_token, 0x00, sizeof(struct token));
1589         end_token.type = TK_END;
1590         add_token(rules, &end_token);
1591
1592         /* link all TK_RULE tokens to be able to fast-forward to next TK_RULE */
1593         prev_rule = 0;
1594         for (i = 1; i < rules->token_cur; i++) {
1595                 if (rules->tokens[i].type == TK_RULE) {
1596                         rules->tokens[prev_rule].rule.next_rule = i;
1597                         prev_rule = i;
1598                 }
1599         }
1600
1601         /* shrink allocated token and string buffer */
1602         if (rules->token_cur < rules->token_max) {
1603                 struct token *tokens;
1604
1605                 tokens = realloc(rules->tokens, rules->token_cur * sizeof(struct token));
1606                 if (tokens != NULL || rules->token_cur == 0) {
1607                         rules->tokens = tokens;
1608                         rules->token_max = rules->token_cur;
1609                 }
1610         }
1611         if (rules->buf_cur < rules->buf_max) {
1612                 char *buf;
1613
1614                 buf = realloc(rules->buf, rules->buf_cur);
1615                 if (buf != NULL || rules->buf_cur == 0) {
1616                         rules->buf = buf;
1617                         rules->buf_max = rules->buf_cur;
1618                 }
1619         }
1620         info(udev, "shrunk to %lu bytes tokens (%u * %zu bytes), %zu bytes buffer\n",
1621              rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->buf_max);
1622
1623         /* cleanup uid/gid cache */
1624         free(rules->uids);
1625         rules->uids = NULL;
1626         rules->uids_cur = 0;
1627         rules->uids_max = 0;
1628         free(rules->gids);
1629         rules->gids = NULL;
1630         rules->gids_cur = 0;
1631         rules->gids_max = 0;
1632
1633         dump_rules(rules);
1634         return rules;
1635 }
1636
1637 void udev_rules_unref(struct udev_rules *rules)
1638 {
1639         if (rules == NULL)
1640                 return;
1641         free(rules->tokens);
1642         free(rules->buf);
1643         free(rules->uids);
1644         free(rules->gids);
1645         free(rules);
1646 }
1647
1648 static int match_key(struct udev_rules *rules, struct token *token, const char *val)
1649 {
1650         const char *key_name = token_str[token->type];
1651         char *key_value = &rules->buf[token->key.value_off];
1652         char *pos;
1653         int match = 0;
1654
1655         if (val == NULL)
1656                 val = "";
1657
1658         /* look for a matching string, parts are separated by '|' */
1659         if (strchr(key_value, '|') != NULL) {
1660                 char value[UTIL_PATH_SIZE];
1661
1662                 util_strlcpy(value, &rules->buf[token->key.value_off], sizeof(value));
1663                 key_value = value;
1664                 while (key_value != NULL) {
1665                         pos = strchr(key_value, '|');
1666                         if (pos != NULL) {
1667                                 pos[0] = '\0';
1668                                 pos = &pos[1];
1669                         }
1670                         dbg(rules->udev, "match %s '%s' <-> '%s'\n", key_name, key_value, val);
1671                         match = (fnmatch(key_value, val, 0) == 0);
1672                         if (match)
1673                                 break;
1674                         key_value = pos;
1675                 }
1676         } else {
1677                 match = (fnmatch(key_value, val, 0) == 0);
1678         }
1679
1680         if (match && (token->key.op == OP_MATCH)) {
1681                 dbg(rules->udev, "%s is true (matching value)\n", key_name);
1682                 return 0;
1683         }
1684         if (!match && (token->key.op == OP_NOMATCH)) {
1685                 dbg(rules->udev, "%s is true (non-matching value)\n", key_name);
1686                 return 0;
1687         }
1688         dbg(rules->udev, "%s is not true\n", key_name);
1689         return -1;
1690 }
1691
1692 static int match_attr(struct udev_rules *rules, struct udev_device *dev, struct udev_event *event, struct token *cur)
1693 {
1694         char attr[UTIL_PATH_SIZE];
1695         const char *key_name = &rules->buf[cur->key.attr_off];
1696         const char *key_value = &rules->buf[cur->key.value_off];
1697         char value[UTIL_NAME_SIZE] = "";
1698         size_t len;
1699
1700         util_strlcpy(attr, key_name, sizeof(attr));
1701         util_resolve_subsys_kernel(event->udev, attr, value, sizeof(value), 1);
1702         if (value[0] == '\0') {
1703                 const char *val;
1704
1705                 val = udev_device_get_sysattr_value(dev, key_name);
1706                 if (val != NULL)
1707                         util_strlcpy(value, val, sizeof(value));
1708         }
1709         if (value[0]=='\0')
1710                 return -1;
1711
1712         /* strip trailing whitespace of value, if not asked to match for it */
1713         len = strlen(key_value);
1714         if (len > 0 && !isspace(key_value[len-1])) {
1715                 len = strlen(value);
1716                 while (len > 0 && isspace(value[--len]))
1717                         value[len] = '\0';
1718                 dbg(rules->udev, "removed trailing whitespace from '%s'\n", value);
1719         }
1720         return match_key(rules, cur, value);
1721 }
1722
1723 enum escape_type {
1724         ESCAPE_UNSET,
1725         ESCAPE_NONE,
1726         ESCAPE_REPLACE,
1727 };
1728
1729 int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event)
1730 {
1731         struct token *cur;
1732         struct token *rule;
1733
1734         if (rules->tokens == NULL)
1735                 return -1;
1736
1737         /* loop through token list, match, run actions or forward to next rule */
1738         cur = &rules->tokens[0];
1739         rule = cur;
1740         while (cur != NULL && cur->type != TK_END) {
1741                 enum escape_type esc = ESCAPE_UNSET;
1742                 unsigned int idx;
1743
1744                 dump_token(rules, cur);
1745                 switch (cur->type) {
1746                 case TK_RULE:
1747                         /* current rule */
1748                         rule = cur;
1749                         esc = ESCAPE_UNSET;
1750                         break;
1751                 case TK_M_ACTION:
1752                         if (match_key(rules, cur, udev_device_get_action(event->dev)) != 0)
1753                                 goto nomatch;
1754                         break;
1755                 case TK_M_DEVPATH:
1756                         if (match_key(rules, cur, udev_device_get_devpath(event->dev)) != 0)
1757                                 goto nomatch;
1758                         break;
1759                 case TK_M_KERNEL:
1760                         if (match_key(rules, cur, udev_device_get_sysname(event->dev)) != 0)
1761                                 goto nomatch;
1762                         break;
1763                 case TK_M_DEVLINK:
1764                         {
1765                                 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
1766                                 struct udev_list_entry *list_entry;
1767                                 int match = 0;
1768
1769                                 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(event->dev)) {
1770                                         const char *devlink;
1771
1772                                         devlink =  &udev_list_entry_get_name(list_entry)[devlen];
1773                                         if (match_key(rules, cur, devlink) == 0) {
1774                                                 match = 1;
1775                                                 break;
1776                                         }
1777                                 }
1778                                 if (!match)
1779                                         goto nomatch;
1780                                 break;
1781                         }
1782                 case TK_M_NAME:
1783                         if (match_key(rules, cur, event->name) != 0)
1784                                 goto nomatch;
1785                         break;
1786                 case TK_M_ENV:
1787                         {
1788                                 struct udev_list_entry *list_entry;
1789                                 const char *key_name = &rules->buf[cur->key.attr_off];
1790                                 const char *value;
1791
1792                                 list_entry = udev_device_get_properties_list_entry(event->dev);
1793                                 list_entry = udev_list_entry_get_by_name(list_entry, key_name);
1794                                 value = udev_list_entry_get_value(list_entry);
1795                                 if (value == NULL) {
1796                                         dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
1797                                         value = "";
1798                                 }
1799                                 if (match_key(rules, cur, value))
1800                                         goto nomatch;
1801                                 break;
1802                         }
1803                 case TK_M_SUBSYSTEM:
1804                         if (match_key(rules, cur, udev_device_get_subsystem(event->dev)) != 0)
1805                                 goto nomatch;
1806                         break;
1807                 case TK_M_DRIVER:
1808                         if (match_key(rules, cur, udev_device_get_driver(event->dev)) != 0)
1809                                 goto nomatch;
1810                         break;
1811                 case TK_M_WAITFOR:
1812                         {
1813                                 char filename[UTIL_PATH_SIZE];
1814                                 int found;
1815
1816                                 util_strlcpy(filename, &rules->buf[cur->key.value_off], sizeof(filename));
1817                                 udev_event_apply_format(event, filename, sizeof(filename));
1818                                 found = (wait_for_file(event->dev, filename, 10) == 0);
1819                                 if (!found && (cur->key.op != OP_NOMATCH))
1820                                         goto nomatch;
1821                                 break;
1822                         }
1823                 case TK_M_ATTR:
1824                         if (match_attr(rules, event->dev, event, cur) != 0)
1825                                 goto nomatch;
1826                         break;
1827                 case TK_M_KERNELS:
1828                 case TK_M_SUBSYSTEMS:
1829                 case TK_M_DRIVERS:
1830                 case TK_M_ATTRS:
1831                         {
1832                                 struct token *next;
1833
1834                                 /* get whole sequence of parent matches */
1835                                 next = cur;
1836                                 while (next->type < TK_M_PARENTS_MAX)
1837                                         next++;
1838
1839                                 /* loop over parents */
1840                                 event->dev_parent = event->dev;
1841                                 while (1) {
1842                                         struct token *key;
1843
1844                                         dbg(event->udev, "parent: '%s'\n", udev_device_get_syspath(event->dev_parent));
1845                                         /* loop over sequence of parent match keys */
1846                                         for (key = cur; key < next; key++ ) {
1847                                                 dump_token(rules, key);
1848                                                 switch(key->type) {
1849                                                 case TK_M_KERNELS:
1850                                                         if (match_key(rules, key, udev_device_get_sysname(event->dev_parent)) != 0)
1851                                                                 goto try_parent;
1852                                                         break;
1853                                                 case TK_M_SUBSYSTEMS:
1854                                                         if (match_key(rules, key, udev_device_get_subsystem(event->dev_parent)) != 0)
1855                                                                 goto try_parent;
1856                                                         break;
1857                                                 case TK_M_DRIVERS:
1858                                                         if (match_key(rules, key, udev_device_get_driver(event->dev_parent)) != 0)
1859                                                                 goto try_parent;
1860                                                         break;
1861                                                 case TK_M_ATTRS:
1862                                                         if (match_attr(rules, event->dev_parent, event, key) != 0)
1863                                                                 goto try_parent;
1864                                                         break;
1865                                                 default:
1866                                                         goto nomatch;
1867                                                 }
1868                                                 dbg(event->udev, "parent key matched\n");
1869                                         }
1870                                         dbg(event->udev, "all parent keys matched\n");
1871                                         /* all keys matched */
1872                                         break;
1873
1874                                 try_parent:
1875                                         event->dev_parent = udev_device_get_parent(event->dev_parent);
1876                                         if (event->dev_parent == NULL)
1877                                                 goto nomatch;
1878                                 }
1879                                 /* move behind our sequence of parent match keys */
1880                                 cur = next;
1881                                 continue;
1882                         }
1883                 case TK_M_TEST:
1884                         {
1885                                 char filename[UTIL_PATH_SIZE];
1886                                 struct stat statbuf;
1887                                 int match;
1888
1889                                 util_strlcpy(filename, &rules->buf[cur->key.value_off], sizeof(filename));
1890                                 udev_event_apply_format(event, filename, sizeof(filename));
1891                                 if (util_resolve_subsys_kernel(event->udev, NULL, filename, sizeof(filename), 0) != 0)
1892                                         if (filename[0] != '/') {
1893                                                 char tmp[UTIL_PATH_SIZE];
1894
1895                                                 util_strlcpy(tmp, udev_device_get_syspath(event->dev), sizeof(tmp));
1896                                                 util_strlcat(tmp, "/", sizeof(tmp));
1897                                                 util_strlcat(tmp, filename, sizeof(tmp));
1898                                                 util_strlcpy(filename, tmp, sizeof(filename));
1899                                         }
1900
1901                                 attr_subst_subdir(filename, sizeof(filename));
1902
1903                                 match = (stat(filename, &statbuf) == 0);
1904                                 info(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
1905                                 if (match && cur->key.mode > 0) {
1906                                         match = ((statbuf.st_mode & cur->key.mode) > 0);
1907                                         info(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
1908                                              match ? "matches" : "does not match", cur->key.mode);
1909                                 }
1910                                 if (match && cur->key.op == OP_NOMATCH)
1911                                         goto nomatch;
1912                                 if (!match && cur->key.op == OP_MATCH)
1913                                         goto nomatch;
1914                                 break;
1915                         }
1916                 case TK_M_PROGRAM:
1917                         {
1918                                 char program[UTIL_PATH_SIZE];
1919                                 char **envp;
1920                                 char result[UTIL_PATH_SIZE];
1921
1922                                 free(event->program_result);
1923                                 event->program_result = NULL;
1924                                 util_strlcpy(program, &rules->buf[cur->key.value_off], sizeof(program));
1925                                 udev_event_apply_format(event, program, sizeof(program));
1926                                 envp = udev_device_get_properties_envp(event->dev);
1927                                 if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL) != 0) {
1928                                         if (cur->key.op != OP_NOMATCH)
1929                                                 goto nomatch;
1930                                 } else {
1931                                         int count;
1932
1933                                         util_remove_trailing_chars(result, '\n');
1934                                         if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
1935                                                 count = util_replace_chars(result, ALLOWED_CHARS_INPUT);
1936                                                 if (count > 0)
1937                                                         info(event->udev, "%i character(s) replaced\n" , count);
1938                                         }
1939                                         event->program_result = strdup(result);
1940                                         dbg(event->udev, "storing result '%s'\n", event->program_result);
1941                                         if (cur->key.op == OP_NOMATCH)
1942                                                 goto nomatch;
1943                                 }
1944                                 break;
1945                         }
1946                 case TK_M_IMPORT_FILE:
1947                         {
1948                                 char import[UTIL_PATH_SIZE];
1949
1950                                 util_strlcpy(import, &rules->buf[cur->key.value_off], sizeof(import));
1951                                 udev_event_apply_format(event, import, sizeof(import));
1952                                 if (import_file_into_properties(event->dev, import) != 0)
1953                                         if (cur->key.op != OP_NOMATCH)
1954                                                 goto nomatch;
1955                                 break;
1956                         }
1957                 case TK_M_IMPORT_PROG:
1958                         {
1959                                 char import[UTIL_PATH_SIZE];
1960
1961                                 util_strlcpy(import, &rules->buf[cur->key.value_off], sizeof(import));
1962                                 udev_event_apply_format(event, import, sizeof(import));
1963                                 if (import_program_into_properties(event->dev, import) != 0)
1964                                         if (cur->key.op != OP_NOMATCH)
1965                                                 goto nomatch;
1966                                 break;
1967                         }
1968                 case TK_M_IMPORT_PARENT:
1969                         {
1970                                 char import[UTIL_PATH_SIZE];
1971
1972                                 util_strlcpy(import, &rules->buf[cur->key.value_off], sizeof(import));
1973                                 udev_event_apply_format(event, import, sizeof(import));
1974                                 if (import_parent_into_properties(event->dev, import) != 0)
1975                                         if (cur->key.op != OP_NOMATCH)
1976                                                 goto nomatch;
1977                                 break;
1978                         }
1979                 case TK_M_RESULT:
1980                         if (match_key(rules, cur, event->program_result) != 0)
1981                                 goto nomatch;
1982                         break;
1983
1984                 case TK_A_IGNORE_DEVICE:
1985                         event->ignore_device = 1;
1986                         return 0;
1987                         break;
1988                 case TK_A_STRING_ESCAPE_NONE:
1989                         esc = ESCAPE_NONE;
1990                         break;
1991                 case TK_A_STRING_ESCAPE_REPLACE:
1992                         esc = ESCAPE_REPLACE;
1993                         break;
1994                 case TK_A_NUM_FAKE_PART:
1995                         if (strcmp(udev_device_get_subsystem(event->dev), "block") != 0)
1996                                 break;
1997                         if (udev_device_get_sysnum(event->dev) != NULL)
1998                                 break;
1999                         udev_device_set_num_fake_partitions(event->dev, cur->key.num_fake_part);
2000                         break;
2001                 case TK_A_DEVLINK_PRIO:
2002                         udev_device_set_devlink_priority(event->dev, cur->key.devlink_prio);
2003                         break;
2004                 case TK_A_OWNER:
2005                         {
2006                                 char owner[UTIL_NAME_SIZE];
2007
2008                                 if (event->owner_final)
2009                                         break;
2010                                 if (cur->key.op == OP_ASSIGN_FINAL)
2011                                         event->owner_final = 1;
2012                                 util_strlcpy(owner,  &rules->buf[cur->key.value_off], sizeof(owner));
2013                                 udev_event_apply_format(event, owner, sizeof(owner));
2014                                 event->uid = util_lookup_user(event->udev, owner);
2015                                 break;
2016                         }
2017                 case TK_A_GROUP:
2018                         {
2019                                 char group[UTIL_NAME_SIZE];
2020
2021                                 if (event->group_final)
2022                                         break;
2023                                 if (cur->key.op == OP_ASSIGN_FINAL)
2024                                         event->group_final = 1;
2025                                 util_strlcpy(group, &rules->buf[cur->key.value_off], sizeof(group));
2026                                 udev_event_apply_format(event, group, sizeof(group));
2027                                 event->gid = util_lookup_group(event->udev, group);
2028                                 break;
2029                         }
2030                 case TK_A_MODE:
2031                         {
2032                                 char mode[UTIL_NAME_SIZE];
2033                                 char *endptr;
2034
2035                                 if (event->mode_final)
2036                                         break;
2037                                 if (cur->key.op == OP_ASSIGN_FINAL)
2038                                         event->mode_final = 1;
2039                                 util_strlcpy(mode, &rules->buf[cur->key.value_off], sizeof(mode));
2040                                 udev_event_apply_format(event, mode, sizeof(mode));
2041                                 event->mode = strtol(mode, &endptr, 8);
2042                                 if (endptr[0] != '\0') {
2043                                         err(event->udev, "invalide mode '%s' set default mode 0660\n", mode);
2044                                         event->mode = 0660;
2045                                 }
2046                                 break;
2047                         }
2048                 case TK_A_OWNER_ID:
2049                         if (event->owner_final)
2050                                 break;
2051                         if (cur->key.op == OP_ASSIGN_FINAL)
2052                                 event->owner_final = 1;
2053                         event->uid = cur->key.uid;
2054                         break;
2055                 case TK_A_GROUP_ID:
2056                         if (event->group_final)
2057                                 break;
2058                         if (cur->key.op == OP_ASSIGN_FINAL)
2059                                 event->group_final = 1;
2060                         event->gid = cur->key.gid;
2061                         break;
2062                 case TK_A_MODE_ID:
2063                         if (event->mode_final)
2064                                 break;
2065                         if (cur->key.op == OP_ASSIGN_FINAL)
2066                                 event->mode_final = 1;
2067                         event->mode = cur->key.mode;
2068                         break;
2069                 case TK_A_ENV:
2070                         {
2071                                 const char *name = &rules->buf[cur->key.attr_off];
2072                                 char *value = &rules->buf[cur->key.value_off];
2073
2074                                 if (value[0] != '\0') {
2075                                         char temp_value[UTIL_NAME_SIZE];
2076                                         struct udev_list_entry *entry;
2077
2078                                         util_strlcpy(temp_value, value, sizeof(temp_value));
2079                                         udev_event_apply_format(event, temp_value, sizeof(temp_value));
2080                                         entry = udev_device_add_property(event->dev, name, temp_value);
2081                                         /* store in db */
2082                                         udev_list_entry_set_flag(entry, 1);
2083                                 } else {
2084                                         udev_device_add_property(event->dev, name, NULL);
2085                                 }
2086                                 break;
2087                         }
2088                 case TK_A_NAME:
2089                         {
2090                                 const char *name  = &rules->buf[cur->key.value_off];
2091                                 char name_str[UTIL_PATH_SIZE];
2092                                 int count;
2093
2094                                 if (event->name_final)
2095                                         break;
2096                                 if (cur->key.op == OP_ASSIGN_FINAL)
2097                                         event->name_final = 1;
2098                                 if (name[0] == '\0') {
2099                                         free(event->name);
2100                                         event->name = NULL;
2101                                         break;
2102                                 }
2103                                 util_strlcpy(name_str, name, sizeof(name_str));
2104                                 udev_event_apply_format(event, name_str, sizeof(name_str));
2105                                 if (esc == ESCAPE_UNSET || esc == ESCAPE_REPLACE) {
2106                                         count = util_replace_chars(name_str, ALLOWED_CHARS_FILE);
2107                                         if (count > 0)
2108                                                 info(event->udev, "%i character(s) replaced\n", count);
2109                                         free(event->name);
2110                                         event->name = strdup(name_str);
2111                                 }
2112                                 break;
2113                         }
2114                 case TK_A_DEVLINK:
2115                         {
2116                                 char temp[UTIL_PATH_SIZE];
2117                                 char filename[UTIL_PATH_SIZE];
2118                                 char *pos, *next;
2119                                 int count = 0;
2120
2121                                 if (event->devlink_final)
2122                                         break;
2123                                 if (major(udev_device_get_devnum(event->dev)) == 0)
2124                                         break;
2125                                 if (cur->key.op == OP_ASSIGN_FINAL)
2126                                         event->devlink_final = 1;
2127                                 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2128                                         udev_device_cleanup_devlinks_list(event->dev);
2129
2130                                 /* allow  multiple symlinks separated by spaces */
2131                                 util_strlcpy(temp, &rules->buf[cur->key.value_off], sizeof(temp));
2132                                 udev_event_apply_format(event, temp, sizeof(temp));
2133                                 if (esc == ESCAPE_UNSET)
2134                                         count = util_replace_chars(temp, ALLOWED_CHARS_FILE " ");
2135                                 else if (esc == ESCAPE_REPLACE)
2136                                         count = util_replace_chars(temp, ALLOWED_CHARS_FILE);
2137                                 if (count > 0)
2138                                         info(event->udev, "%i character(s) replaced\n" , count);
2139                                 dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
2140                                 pos = temp;
2141                                 while (isspace(pos[0]))
2142                                         pos++;
2143                                 next = strchr(pos, ' ');
2144                                 while (next) {
2145                                         next[0] = '\0';
2146                                         info(event->udev, "add symlink '%s'\n", pos);
2147                                         util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
2148                                         util_strlcat(filename, "/", sizeof(filename));
2149                                         util_strlcat(filename, pos, sizeof(filename));
2150                                         udev_device_add_devlink(event->dev, filename);
2151                                         while (isspace(next[1]))
2152                                                 next++;
2153                                         pos = &next[1];
2154                                         next = strchr(pos, ' ');
2155                                 }
2156                                 if (pos[0] != '\0') {
2157                                         info(event->udev, "add symlink '%s'\n", pos);
2158                                         util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
2159                                         util_strlcat(filename, "/", sizeof(filename));
2160                                         util_strlcat(filename, pos, sizeof(filename));
2161                                         udev_device_add_devlink(event->dev, filename);
2162                                 }
2163                         }
2164                         break;
2165                 case TK_A_EVENT_TIMEOUT:
2166                         udev_device_set_event_timeout(event->dev, cur->key.event_timeout);
2167                         break;
2168                 case TK_A_IGNORE_REMOVE:
2169                         udev_device_set_ignore_remove(event->dev, 1);
2170                         break;
2171                 case TK_A_ATTR:
2172                         {
2173                                 const char *key_name = &rules->buf[cur->key.attr_off];
2174                                 char attr[UTIL_PATH_SIZE];
2175                                 char value[UTIL_NAME_SIZE];
2176                                 FILE *f;
2177
2178                                 util_strlcpy(attr, key_name, sizeof(attr));
2179                                 if (util_resolve_subsys_kernel(event->udev, key_name, attr, sizeof(attr), 0) != 0) {
2180                                         util_strlcpy(attr, udev_device_get_syspath(event->dev), sizeof(attr));
2181                                         util_strlcat(attr, "/", sizeof(attr));
2182                                         util_strlcat(attr, key_name, sizeof(attr));
2183                                 }
2184
2185                                 attr_subst_subdir(attr, sizeof(attr));
2186
2187                                 util_strlcpy(value, &rules->buf[cur->key.value_off], sizeof(value));
2188                                 udev_event_apply_format(event, value, sizeof(value));
2189                                 info(event->udev, "writing '%s' to sysfs file '%s'\n", value, attr);
2190                                 f = fopen(attr, "w");
2191                                 if (f != NULL) {
2192                                         if (!event->test)
2193                                                 if (fprintf(f, "%s", value) <= 0)
2194                                                         err(event->udev, "error writing ATTR{%s}: %m\n", attr);
2195                                         fclose(f);
2196                                 } else {
2197                                         err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
2198                                 }
2199                                 break;
2200                         }
2201                 case TK_A_RUN:
2202                         {
2203                                 struct udev_list_entry *list_entry;
2204
2205                                 if (cur->key.op == OP_ASSIGN || cur->key.op == OP_ASSIGN_FINAL)
2206                                         udev_list_cleanup_entries(event->udev, &event->run_list);
2207                                 list_entry = udev_list_entry_add(event->udev, &event->run_list,
2208                                                                  &rules->buf[cur->key.value_off], NULL, 1, 0);
2209                                 if (cur->key.ignore_error)
2210                                         udev_list_entry_set_flag(list_entry, 1);
2211                                 break;
2212                         }
2213                 case TK_A_GOTO:
2214                         cur = &rules->tokens[cur->key.rule_goto];
2215                         continue;
2216                 case TK_A_LAST_RULE:
2217                         break;
2218
2219                 case TK_M_PARENTS_MAX:
2220                 case TK_END:
2221                 case TK_UNDEF:
2222                         err(rules->udev, "wrong type %u\n", cur->type);
2223                         goto nomatch;
2224                 }
2225
2226                 cur++;
2227                 continue;
2228         nomatch:
2229                 /* fast-forward to next rule */
2230                 idx = rule->rule.next_rule;
2231                 if (idx == 0)
2232                         break;
2233                 dbg(rules->udev, "forward to rule: %u\n", idx);
2234                 cur = &rules->tokens[idx];
2235         }
2236         return 0;
2237 }