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