chiark / gitweb /
make struct udev_rules opaque
[elogind.git] / udev / udev-rules.c
1 /*
2  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
3  * Copyright (C) 2003-2008 Kay Sievers <kay.sievers@vrfy.org>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stddef.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <fcntl.h>
24 #include <ctype.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <syslog.h>
28 #include <dirent.h>
29 #include <fnmatch.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <sys/wait.h>
33 #include <sys/stat.h>
34
35 #include "udev.h"
36
37 struct udev_rules {
38         struct udev *udev;
39         char *buf;
40         size_t bufsize;
41         int resolve_names;
42 };
43
44 struct udev_rules_iter {
45         struct udev_rules *rules;
46         size_t current;
47 };
48
49 enum key_operation {
50         KEY_OP_UNSET,
51         KEY_OP_MATCH,
52         KEY_OP_NOMATCH,
53         KEY_OP_ADD,
54         KEY_OP_ASSIGN,
55         KEY_OP_ASSIGN_FINAL,
56 };
57
58 struct key {
59         enum key_operation operation;
60         size_t val_off;
61 };
62
63 struct key_pair {
64         struct key key;
65         size_t key_name_off;
66 };
67
68 #define PAIRS_MAX               5
69 struct key_pairs {
70         int count;
71         struct key_pair keys[PAIRS_MAX];
72 };
73
74 enum import_type {
75         IMPORT_UNSET,
76         IMPORT_PROGRAM,
77         IMPORT_FILE,
78         IMPORT_PARENT,
79 };
80
81 enum escape_type {
82         ESCAPE_UNSET,
83         ESCAPE_NONE,
84         ESCAPE_REPLACE,
85 };
86
87 struct udev_rule {
88         struct key action;
89         struct key devpath;
90         struct key kernel;
91         struct key subsystem;
92         struct key driver;
93         struct key_pairs attr;
94
95         struct key kernels;
96         struct key subsystems;
97         struct key drivers;
98         struct key_pairs attrs;
99
100         struct key_pairs env;
101         struct key program;
102         struct key result;
103         struct key import;
104         enum import_type import_type;
105         struct key test;
106         mode_t test_mode_mask;
107         struct key run;
108         struct key wait_for;
109         struct key label;
110         struct key goto_label;
111         size_t goto_rule_off;
112
113         struct key name;
114         struct key symlink;
115         struct key symlink_match;
116         struct key owner;
117         struct key group;
118         struct key mode;
119         enum escape_type string_escape;
120
121         unsigned int link_priority;
122         int event_timeout;
123         unsigned int partitions;
124         unsigned int last_rule:1,
125                      run_ignore_error:1,
126                      ignore_device:1,
127                      ignore_remove:1;
128
129         size_t bufsize;
130         char buf[];
131 };
132
133 static void udev_rules_iter_init(struct udev_rules_iter *iter, struct udev_rules *rules)
134 {
135         dbg(rules->udev, "bufsize=%zi\n", rules->bufsize);
136         iter->rules = rules;
137         iter->current = 0;
138 }
139
140 static struct udev_rule *udev_rules_iter_next(struct udev_rules_iter *iter)
141 {
142         struct udev_rules *rules;
143         struct udev_rule *rule;
144
145         rules = iter->rules;
146         if (!rules)
147                 return NULL;
148
149         dbg(rules->udev, "current=%zi\n", iter->current);
150         if (iter->current >= rules->bufsize) {
151                 dbg(rules->udev, "no more rules\n");
152                 return NULL;
153         }
154
155         /* get next rule */
156         rule = (struct udev_rule *) (rules->buf + iter->current);
157         iter->current += sizeof(struct udev_rule) + rule->bufsize;
158
159         return rule;
160 }
161
162 static struct udev_rule *udev_rules_iter_goto(struct udev_rules_iter *iter, size_t rule_off)
163 {
164         struct udev_rules *rules = iter->rules;
165         struct udev_rule *rule;
166
167         dbg(rules->udev, "current=%zi\n", iter->current);
168         iter->current = rule_off;
169         rule = (struct udev_rule *) (rules->buf + iter->current);
170
171         return rule;
172 }
173
174 static size_t find_label(const struct udev_rules_iter *iter, const char *label)
175 {
176         struct udev_rule *rule;
177         struct udev_rules *rules = iter->rules;
178         size_t current = iter->current;
179
180 next:
181         dbg(rules->udev, "current=%zi\n", current);
182         if (current >= rules->bufsize) {
183                 dbg(rules->udev, "LABEL='%s' not found\n", label);
184                 return 0;
185         }
186         rule = (struct udev_rule *) (rules->buf + current);
187
188         if (strcmp(&rule->buf[rule->label.val_off], label) != 0) {
189                 dbg(rules->udev, "moving forward, looking for label '%s'\n", label);
190                 current += sizeof(struct udev_rule) + rule->bufsize;
191                 goto next;
192         }
193
194         dbg(rules->udev, "found label '%s'\n", label);
195         return current;
196 }
197
198 /* extract possible {attr} and move str behind it */
199 static char *get_format_attribute(struct udev *udev, char **str)
200 {
201         char *pos;
202         char *attr = NULL;
203
204         if (*str[0] == '{') {
205                 pos = strchr(*str, '}');
206                 if (pos == NULL) {
207                         err(udev, "missing closing brace for format\n");
208                         return NULL;
209                 }
210                 pos[0] = '\0';
211                 attr = *str+1;
212                 *str = pos+1;
213                 dbg(udev, "attribute='%s', str='%s'\n", attr, *str);
214         }
215         return attr;
216 }
217
218 /* extract possible format length and move str behind it*/
219 static int get_format_len(struct udev *udev, char **str)
220 {
221         int num;
222         char *tail;
223
224         if (isdigit(*str[0])) {
225                 num = (int) strtoul(*str, &tail, 10);
226                 if (num > 0) {
227                         *str = tail;
228                         dbg(udev, "format length=%i\n", num);
229                         return num;
230                 } else {
231                         err(udev, "format parsing error '%s'\n", *str);
232                 }
233         }
234         return -1;
235 }
236
237 static int run_program(struct udev_device *dev, const char *command,
238                        char *result, size_t ressize, size_t *reslen)
239 {
240         struct udev *udev = udev_device_get_udev(dev);
241         int status;
242         char **envp;
243         int outpipe[2] = {-1, -1};
244         int errpipe[2] = {-1, -1};
245         pid_t pid;
246         char arg[UTIL_PATH_SIZE];
247         char program[UTIL_PATH_SIZE];
248         char *argv[(sizeof(arg) / 2) + 1];
249         int devnull;
250         int i;
251         int err = 0;
252
253         /* build argv from command */
254         util_strlcpy(arg, command, sizeof(arg));
255         i = 0;
256         if (strchr(arg, ' ') != NULL) {
257                 char *pos = arg;
258
259                 while (pos != NULL && pos[0] != '\0') {
260                         if (pos[0] == '\'') {
261                                 /* do not separate quotes */
262                                 pos++;
263                                 argv[i] = strsep(&pos, "\'");
264                                 while (pos != NULL && pos[0] == ' ')
265                                         pos++;
266                         } else {
267                                 argv[i] = strsep(&pos, " ");
268                         }
269                         dbg(udev, "arg[%i] '%s'\n", i, argv[i]);
270                         i++;
271                 }
272                 argv[i] = NULL;
273         } else {
274                 argv[0] = arg;
275                 argv[1] = NULL;
276         }
277         info(udev, "'%s'\n", command);
278
279         /* prepare pipes from child to parent */
280         if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) {
281                 if (pipe(outpipe) != 0) {
282                         err(udev, "pipe failed: %m\n");
283                         return -1;
284                 }
285         }
286         if (udev_get_log_priority(udev) >= LOG_INFO) {
287                 if (pipe(errpipe) != 0) {
288                         err(udev, "pipe failed: %m\n");
289                         return -1;
290                 }
291         }
292
293         /* allow programs in /lib/udev/ to be called without the path */
294         if (strchr(argv[0], '/') == NULL) {
295                 util_strlcpy(program, UDEV_PREFIX "/lib/udev/", sizeof(program));
296                 util_strlcat(program, argv[0], sizeof(program));
297                 argv[0] = program;
298         }
299
300         envp = udev_device_get_properties_envp(dev);
301
302         pid = fork();
303         switch(pid) {
304         case 0:
305                 /* child closes parent ends of pipes */
306                 if (outpipe[READ_END] > 0)
307                         close(outpipe[READ_END]);
308                 if (errpipe[READ_END] > 0)
309                         close(errpipe[READ_END]);
310
311                 /* discard child output or connect to pipe */
312                 devnull = open("/dev/null", O_RDWR);
313                 if (devnull > 0) {
314                         dup2(devnull, STDIN_FILENO);
315                         if (outpipe[WRITE_END] < 0)
316                                 dup2(devnull, STDOUT_FILENO);
317                         if (errpipe[WRITE_END] < 0)
318                                 dup2(devnull, STDERR_FILENO);
319                         close(devnull);
320                 } else
321                         err(udev, "open /dev/null failed: %m\n");
322                 if (outpipe[WRITE_END] > 0) {
323                         dup2(outpipe[WRITE_END], STDOUT_FILENO);
324                         close(outpipe[WRITE_END]);
325                 }
326                 if (errpipe[WRITE_END] > 0) {
327                         dup2(errpipe[WRITE_END], STDERR_FILENO);
328                         close(errpipe[WRITE_END]);
329                 }
330                 execve(argv[0], argv, envp);
331                 if (errno == ENOENT || errno == ENOTDIR) {
332                         /* may be on a filesytem which is not mounted right now */
333                         info(udev, "program '%s' not found\n", argv[0]);
334                 } else {
335                         /* other problems */
336                         err(udev, "exec of program '%s' failed\n", argv[0]);
337                 }
338                 _exit(1);
339         case -1:
340                 err(udev, "fork of '%s' failed: %m\n", argv[0]);
341                 return -1;
342         default:
343                 /* read from child if requested */
344                 if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
345                         ssize_t count;
346                         size_t respos = 0;
347
348                         /* parent closes child ends of pipes */
349                         if (outpipe[WRITE_END] > 0)
350                                 close(outpipe[WRITE_END]);
351                         if (errpipe[WRITE_END] > 0)
352                                 close(errpipe[WRITE_END]);
353
354                         /* read child output */
355                         while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
356                                 int fdcount;
357                                 fd_set readfds;
358
359                                 FD_ZERO(&readfds);
360                                 if (outpipe[READ_END] > 0)
361                                         FD_SET(outpipe[READ_END], &readfds);
362                                 if (errpipe[READ_END] > 0)
363                                         FD_SET(errpipe[READ_END], &readfds);
364                                 fdcount = select(UDEV_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL);
365                                 if (fdcount < 0) {
366                                         if (errno == EINTR)
367                                                 continue;
368                                         err = -1;
369                                         break;
370                                 }
371
372                                 /* get stdout */
373                                 if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) {
374                                         char inbuf[1024];
375                                         char *pos;
376                                         char *line;
377
378                                         count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1);
379                                         if (count <= 0) {
380                                                 close(outpipe[READ_END]);
381                                                 outpipe[READ_END] = -1;
382                                                 if (count < 0) {
383                                                         err(udev, "stdin read failed: %m\n");
384                                                         err = -1;
385                                                 }
386                                                 continue;
387                                         }
388                                         inbuf[count] = '\0';
389
390                                         /* store result for rule processing */
391                                         if (result) {
392                                                 if (respos + count < ressize) {
393                                                         memcpy(&result[respos], inbuf, count);
394                                                         respos += count;
395                                                 } else {
396                                                         err(udev, "ressize %ld too short\n", (long)ressize);
397                                                         err = -1;
398                                                 }
399                                         }
400                                         pos = inbuf;
401                                         while ((line = strsep(&pos, "\n")))
402                                                 if (pos || line[0] != '\0')
403                                                         info(udev, "'%s' (stdout) '%s'\n", argv[0], line);
404                                 }
405
406                                 /* get stderr */
407                                 if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) {
408                                         char errbuf[1024];
409                                         char *pos;
410                                         char *line;
411
412                                         count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1);
413                                         if (count <= 0) {
414                                                 close(errpipe[READ_END]);
415                                                 errpipe[READ_END] = -1;
416                                                 if (count < 0)
417                                                         err(udev, "stderr read failed: %m\n");
418                                                 continue;
419                                         }
420                                         errbuf[count] = '\0';
421                                         pos = errbuf;
422                                         while ((line = strsep(&pos, "\n")))
423                                                 if (pos || line[0] != '\0')
424                                                         info(udev, "'%s' (stderr) '%s'\n", argv[0], line);
425                                 }
426                         }
427                         if (outpipe[READ_END] > 0)
428                                 close(outpipe[READ_END]);
429                         if (errpipe[READ_END] > 0)
430                                 close(errpipe[READ_END]);
431
432                         /* return the childs stdout string */
433                         if (result) {
434                                 result[respos] = '\0';
435                                 dbg(udev, "result='%s'\n", result);
436                                 if (reslen)
437                                         *reslen = respos;
438                         }
439                 }
440                 waitpid(pid, &status, 0);
441                 if (WIFEXITED(status)) {
442                         info(udev, "'%s' returned with status %i\n", argv[0], WEXITSTATUS(status));
443                         if (WEXITSTATUS(status) != 0)
444                                 err = -1;
445                 } else {
446                         err(udev, "'%s' abnormal exit\n", argv[0]);
447                         err = -1;
448                 }
449         }
450
451         return err;
452 }
453
454 static int import_property_from_string(struct udev_device *dev, char *line)
455 {
456         struct udev *udev = udev_device_get_udev(dev);
457         char *key;
458         char *val;
459         size_t len;
460
461         /* find key */
462         key = line;
463         while (isspace(key[0]))
464                 key++;
465
466         /* comment or empty line */
467         if (key[0] == '#' || key[0] == '\0')
468                 return -1;
469
470         /* split key/value */
471         val = strchr(key, '=');
472         if (val == NULL)
473                 return -1;
474         val[0] = '\0';
475         val++;
476
477         /* find value */
478         while (isspace(val[0]))
479                 val++;
480
481         /* terminate key */
482         len = strlen(key);
483         if (len == 0)
484                 return -1;
485         while (isspace(key[len-1]))
486                 len--;
487         key[len] = '\0';
488
489         /* terminate value */
490         len = strlen(val);
491         if (len == 0)
492                 return -1;
493         while (isspace(val[len-1]))
494                 len--;
495         val[len] = '\0';
496
497         if (len == 0)
498                 return -1;
499
500         /* unquote */
501         if (val[0] == '"' || val[0] == '\'') {
502                 if (val[len-1] != val[0]) {
503                         info(udev, "inconsistent quoting: '%s', skip\n", line);
504                         return -1;
505                 }
506                 val[len-1] = '\0';
507                 val++;
508         }
509
510         info(udev, "adding '%s'='%s'\n", key, val);
511
512         /* handle device, renamed by external tool, returning new path */
513         if (strcmp(key, "DEVPATH") == 0) {
514                 char syspath[UTIL_PATH_SIZE];
515
516                 info(udev, "updating devpath from '%s' to '%s'\n",
517                      udev_device_get_devpath(dev), val);
518                 util_strlcpy(syspath, udev_get_sys_path(udev), sizeof(syspath));
519                 util_strlcat(syspath, val, sizeof(syspath));
520                 udev_device_set_syspath(dev, syspath);
521         } else {
522                 struct udev_list_entry *entry;
523
524                 entry = udev_device_add_property(dev, key, val);
525                 /* store in db */
526                 udev_list_entry_set_flag(entry, 1);
527         }
528         return 0;
529 }
530
531 static int import_file_into_env(struct udev_device *dev, const char *filename)
532 {
533         FILE *f;
534         char line[UTIL_LINE_SIZE];
535
536         f = fopen(filename, "r");
537         if (f == NULL)
538                 return -1;
539         while (fgets(line, sizeof(line), f) != NULL)
540                 import_property_from_string(dev, line);
541         fclose(f);
542         return 0;
543 }
544
545 static int import_program_into_env(struct udev_device *dev, const char *program)
546 {
547         char result[2048];
548         size_t reslen;
549         char *line;
550
551         if (run_program(dev, program, result, sizeof(result), &reslen) != 0)
552                 return -1;
553
554         line = result;
555         while (line != NULL) {
556                 char *pos;
557
558                 pos = strchr(line, '\n');
559                 if (pos != NULL) {
560                         pos[0] = '\0';
561                         pos = &pos[1];
562                 }
563                 import_property_from_string(dev, line);
564                 line = pos;
565         }
566         return 0;
567 }
568
569 static int import_parent_into_env(struct udev_device *dev, const char *filter)
570 {
571         struct udev *udev = udev_device_get_udev(dev);
572         struct udev_device *dev_parent;
573         struct udev_list_entry *list_entry;
574
575         dev_parent = udev_device_get_parent(dev);
576         if (dev_parent == NULL)
577                 return -1;
578
579         dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
580         udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) {
581                 const char *key = udev_list_entry_get_name(list_entry);
582                 const char *val = udev_list_entry_get_value(list_entry);
583
584                 if (fnmatch(filter, key, 0) == 0) {
585                         struct udev_list_entry *entry;
586
587                         dbg(udev, "import key '%s=%s'\n", key, val);
588                         entry = udev_device_add_property(dev, key, val);
589                         /* store in db */
590                         udev_list_entry_set_flag(entry, 1);
591                 }
592         }
593         return 0;
594 }
595
596 int udev_rules_run(struct udev_event *event)
597 {
598         struct udev_list_entry *list_entry;
599         int err = 0;
600
601         dbg(event->udev, "executing run list\n");
602         udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
603                 const char *cmd = udev_list_entry_get_name(list_entry);
604
605                 if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
606                         struct udev_monitor *monitor;
607
608                         monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
609                         if (monitor == NULL)
610                                 continue;
611                         udev_monitor_send_device(monitor, event->dev);
612                         udev_monitor_unref(monitor);
613                 } else {
614                         char program[UTIL_PATH_SIZE];
615
616                         util_strlcpy(program, cmd, sizeof(program));
617                         udev_rules_apply_format(event, program, sizeof(program));
618                         if (run_program(event->dev, program, NULL, 0, NULL) != 0) {
619                                 if (!udev_list_entry_get_flag(list_entry))
620                                         err = -1;
621                         }
622                 }
623         }
624         return err;
625 }
626
627 #define WAIT_LOOP_PER_SECOND            50
628 static int wait_for_file(struct udev_event *event, const char *file, int timeout)
629 {
630         char filepath[UTIL_PATH_SIZE];
631         char devicepath[UTIL_PATH_SIZE] = "";
632         struct stat stats;
633         int loop = timeout * WAIT_LOOP_PER_SECOND;
634
635         /* a relative path is a device attribute */
636         if (file[0] != '/') {
637                 util_strlcpy(devicepath, udev_get_sys_path(event->udev), sizeof(devicepath));
638                 util_strlcat(devicepath, udev_device_get_devpath(event->dev), sizeof(devicepath));
639
640                 util_strlcpy(filepath, devicepath, sizeof(filepath));
641                 util_strlcat(filepath, "/", sizeof(filepath));
642                 util_strlcat(filepath, file, sizeof(filepath));
643                 file = filepath;
644         }
645
646         dbg(event->udev, "will wait %i sec for '%s'\n", timeout, file);
647         while (--loop) {
648                 /* lookup file */
649                 if (stat(file, &stats) == 0) {
650                         info(event->udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
651                         return 0;
652                 }
653                 /* make sure, the device did not disappear in the meantime */
654                 if (devicepath[0] != '\0' && stat(devicepath, &stats) != 0) {
655                         info(event->udev, "device disappeared while waiting for '%s'\n", file);
656                         return -2;
657                 }
658                 info(event->udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
659                 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
660         }
661         info(event->udev, "waiting for '%s' failed\n", file);
662         return -1;
663 }
664
665 /* handle "[$SUBSYSTEM/$KERNEL]<attribute>" lookup */
666 static int split_subsys_sysname(struct udev *udev, char *attrstr, char **subsys, char **sysname, char **attr)
667 {
668         char *pos;
669
670         if (attrstr[0] != '[')
671                 return -1;
672
673         *subsys = &attrstr[1];
674         pos = strchr(*subsys, ']');
675         if (pos == NULL)
676                 return -1;
677         pos[0] = '\0';
678         pos = &pos[1];
679
680         if (pos[0] == '/')
681                 pos = &pos[1];
682         if (pos[0] != '\0')
683                 *attr = pos;
684         else
685                 *attr = NULL;
686
687         pos = strchr(*subsys, '/');
688         if (pos == NULL)
689                 return -1;
690         pos[0] = '\0';
691         *sysname = &pos[1];
692         return 0;
693 }
694
695 static int attr_subst_subdir(char *attr, size_t len)
696 {
697         char *pos;
698         int found = 0;
699
700         pos = strstr(attr, "/*/");
701         if (pos != NULL) {
702                 char str[UTIL_PATH_SIZE];
703                 DIR *dir;
704
705                 pos[1] = '\0';
706                 util_strlcpy(str, &pos[2], sizeof(str));
707                 dir = opendir(attr);
708                 if (dir != NULL) {
709                         struct dirent *dent;
710
711                         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
712                                 struct stat stats;
713
714                                 if (dent->d_name[0] == '.')
715                                         continue;
716                                 util_strlcat(attr, dent->d_name, len);
717                                 util_strlcat(attr, str, len);
718                                 if (stat(attr, &stats) == 0) {
719                                         found = 1;
720                                         break;
721                                 }
722                                 pos[1] = '\0';
723                         }
724                         closedir(dir);
725                 }
726                 if (!found)
727                         util_strlcat(attr, str, len);
728         }
729
730         return found;
731 }
732
733 void udev_rules_apply_format(struct udev_event *event, char *string, size_t maxsize)
734 {
735         struct udev_device *dev = event->dev;
736         char temp[UTIL_PATH_SIZE];
737         char temp2[UTIL_PATH_SIZE];
738         char *head, *tail, *cpos, *attr, *rest;
739         int len;
740         int i;
741         int count;
742         enum subst_type {
743                 SUBST_UNKNOWN,
744                 SUBST_DEVPATH,
745                 SUBST_KERNEL,
746                 SUBST_KERNEL_NUMBER,
747                 SUBST_ID,
748                 SUBST_DRIVER,
749                 SUBST_MAJOR,
750                 SUBST_MINOR,
751                 SUBST_RESULT,
752                 SUBST_ATTR,
753                 SUBST_PARENT,
754                 SUBST_TEMP_NODE,
755                 SUBST_NAME,
756                 SUBST_LINKS,
757                 SUBST_ROOT,
758                 SUBST_SYS,
759                 SUBST_ENV,
760         };
761         static const struct subst_map {
762                 char *name;
763                 char fmt;
764                 enum subst_type type;
765         } map[] = {
766                 { .name = "devpath",    .fmt = 'p',     .type = SUBST_DEVPATH },
767                 { .name = "number",     .fmt = 'n',     .type = SUBST_KERNEL_NUMBER },
768                 { .name = "kernel",     .fmt = 'k',     .type = SUBST_KERNEL },
769                 { .name = "id",         .fmt = 'b',     .type = SUBST_ID },
770                 { .name = "driver",     .fmt = 'd',     .type = SUBST_DRIVER },
771                 { .name = "major",      .fmt = 'M',     .type = SUBST_MAJOR },
772                 { .name = "minor",      .fmt = 'm',     .type = SUBST_MINOR },
773                 { .name = "result",     .fmt = 'c',     .type = SUBST_RESULT },
774                 { .name = "attr",       .fmt = 's',     .type = SUBST_ATTR },
775                 { .name = "sysfs",      .fmt = 's',     .type = SUBST_ATTR },
776                 { .name = "parent",     .fmt = 'P',     .type = SUBST_PARENT },
777                 { .name = "tempnode",   .fmt = 'N',     .type = SUBST_TEMP_NODE },
778                 { .name = "name",       .fmt = 'D',     .type = SUBST_NAME },
779                 { .name = "links",      .fmt = 'L',     .type = SUBST_LINKS },
780                 { .name = "root",       .fmt = 'r',     .type = SUBST_ROOT },
781                 { .name = "sys",        .fmt = 'S',     .type = SUBST_SYS },
782                 { .name = "env",        .fmt = 'E',     .type = SUBST_ENV },
783                 { NULL, '\0', 0 }
784         };
785         enum subst_type type;
786         const struct subst_map *subst;
787
788         head = string;
789         while (1) {
790                 len = -1;
791                 while (head[0] != '\0') {
792                         if (head[0] == '$') {
793                                 /* substitute named variable */
794                                 if (head[1] == '\0')
795                                         break;
796                                 if (head[1] == '$') {
797                                         util_strlcpy(temp, head+2, sizeof(temp));
798                                         util_strlcpy(head+1, temp, maxsize);
799                                         head++;
800                                         continue;
801                                 }
802                                 head[0] = '\0';
803                                 for (subst = map; subst->name; subst++) {
804                                         if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) {
805                                                 type = subst->type;
806                                                 tail = head + strlen(subst->name)+1;
807                                                 dbg(event->udev, "will substitute format name '%s'\n", subst->name);
808                                                 goto found;
809                                         }
810                                 }
811                                 head[0] = '$';
812                                 err(event->udev, "unknown format variable '%s'\n", head);
813                         } else if (head[0] == '%') {
814                                 /* substitute format char */
815                                 if (head[1] == '\0')
816                                         break;
817                                 if (head[1] == '%') {
818                                         util_strlcpy(temp, head+2, sizeof(temp));
819                                         util_strlcpy(head+1, temp, maxsize);
820                                         head++;
821                                         continue;
822                                 }
823                                 head[0] = '\0';
824                                 tail = head+1;
825                                 len = get_format_len(event->udev, &tail);
826                                 for (subst = map; subst->name; subst++) {
827                                         if (tail[0] == subst->fmt) {
828                                                 type = subst->type;
829                                                 tail++;
830                                                 dbg(event->udev, "will substitute format char '%c'\n", subst->fmt);
831                                                 goto found;
832                                         }
833                                 }
834                                 head[0] = '%';
835                                 err(event->udev, "unknown format char '%c'\n", tail[0]);
836                         }
837                         head++;
838                 }
839                 break;
840 found:
841                 attr = get_format_attribute(event->udev, &tail);
842                 util_strlcpy(temp, tail, sizeof(temp));
843                 dbg(event->udev, "format=%i, string='%s', tail='%s'\n", type ,string, tail);
844
845                 switch (type) {
846                 case SUBST_DEVPATH:
847                         util_strlcat(string, udev_device_get_devpath(dev), maxsize);
848                         dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev));
849                         break;
850                 case SUBST_KERNEL:
851                         util_strlcat(string, udev_device_get_sysname(dev), maxsize);
852                         dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev));
853                         break;
854                 case SUBST_KERNEL_NUMBER:
855                         if (udev_device_get_sysnum(dev) == NULL)
856                                 break;
857                         util_strlcat(string, udev_device_get_sysnum(dev), maxsize);
858                         dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev));
859                         break;
860                 case SUBST_ID:
861                         if (event->dev_parent != NULL) {
862                                 util_strlcat(string, udev_device_get_sysname(event->dev_parent), maxsize);
863                                 dbg(event->udev, "substitute id '%s'\n", udev_device_get_sysname(event->dev_parent));
864                         }
865                         break;
866                 case SUBST_DRIVER:
867                         if (event->dev_parent != NULL) {
868                                 const char *driver = udev_device_get_driver(event->dev_parent);
869
870                                 if (driver == NULL)
871                                         break;
872                                 util_strlcat(string, driver, maxsize);
873                                 dbg(event->udev, "substitute driver '%s'\n", driver);
874                         }
875                         break;
876                 case SUBST_MAJOR:
877                         sprintf(temp2, "%d", major(udev_device_get_devnum(dev)));
878                         util_strlcat(string, temp2, maxsize);
879                         dbg(event->udev, "substitute major number '%s'\n", temp2);
880                         break;
881                 case SUBST_MINOR:
882                         sprintf(temp2, "%d", minor(udev_device_get_devnum(dev)));
883                         util_strlcat(string, temp2, maxsize);
884                         dbg(event->udev, "substitute minor number '%s'\n", temp2);
885                         break;
886                 case SUBST_RESULT:
887                         if (event->program_result[0] == '\0')
888                                 break;
889                         /* get part part of the result string */
890                         i = 0;
891                         if (attr != NULL)
892                                 i = strtoul(attr, &rest, 10);
893                         if (i > 0) {
894                                 dbg(event->udev, "request part #%d of result string\n", i);
895                                 cpos = event->program_result;
896                                 while (--i) {
897                                         while (cpos[0] != '\0' && !isspace(cpos[0]))
898                                                 cpos++;
899                                         while (isspace(cpos[0]))
900                                                 cpos++;
901                                 }
902                                 if (i > 0) {
903                                         err(event->udev, "requested part of result string not found\n");
904                                         break;
905                                 }
906                                 util_strlcpy(temp2, cpos, sizeof(temp2));
907                                 /* %{2+}c copies the whole string from the second part on */
908                                 if (rest[0] != '+') {
909                                         cpos = strchr(temp2, ' ');
910                                         if (cpos)
911                                                 cpos[0] = '\0';
912                                 }
913                                 util_strlcat(string, temp2, maxsize);
914                                 dbg(event->udev, "substitute part of result string '%s'\n", temp2);
915                         } else {
916                                 util_strlcat(string, event->program_result, maxsize);
917                                 dbg(event->udev, "substitute result string '%s'\n", event->program_result);
918                         }
919                         break;
920                 case SUBST_ATTR:
921                         if (attr == NULL)
922                                 err(event->udev, "missing file parameter for attr\n");
923                         else {
924                                 char *subsys;
925                                 char *sysname;
926                                 char *attrib;
927                                 char value[UTIL_NAME_SIZE] = "";
928                                 size_t size;
929
930                                 if (split_subsys_sysname(event->udev, attr, &subsys, &sysname, &attrib) == 0) {
931                                         struct udev_device *d;
932                                         const char *val;
933
934                                         if (attrib == NULL)
935                                                 break;
936                                         d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
937                                         if (d == NULL)
938                                                 break;
939                                         val = udev_device_get_attr_value(d, attrib);
940                                         if (val != NULL)
941                                                 util_strlcpy(value, val, sizeof(value));
942                                         udev_device_unref(d);
943                                 }
944
945                                 /* try the current device, other matches may have selected */
946                                 if (value[0]=='\0' && event->dev_parent != NULL && event->dev_parent != event->dev) {
947                                         const char *val;
948
949                                         val = udev_device_get_attr_value(event->dev_parent, attr);
950                                         if (val != NULL)
951                                                 util_strlcpy(value, val, sizeof(value));
952                                 }
953
954                                 /* look at all devices along the chain of parents */
955                                 if (value[0]=='\0') {
956                                         struct udev_device *dev_parent = dev;
957                                         const char *val;
958
959                                         do {
960                                                 dbg(event->udev, "looking at '%s'\n", udev_device_get_syspath(dev_parent));
961                                                 val = udev_device_get_attr_value(dev_parent, attr);
962                                                 if (val != NULL) {
963                                                         util_strlcpy(value, val, sizeof(value));
964                                                         break;
965                                                 }
966                                                 dev_parent = udev_device_get_parent(dev_parent);
967                                         } while (dev_parent != NULL);
968                                 }
969
970                                 if (value[0]=='\0')
971                                         break;
972
973                                 /* strip trailing whitespace, and replace unwanted characters */
974                                 size = strlen(value);
975                                 while (size > 0 && isspace(value[--size]))
976                                         value[size] = '\0';
977                                 count = util_replace_chars(value, ALLOWED_CHARS_INPUT);
978                                 if (count > 0)
979                                         info(event->udev, "%i character(s) replaced\n" , count);
980                                 util_strlcat(string, value, maxsize);
981                                 dbg(event->udev, "substitute sysfs value '%s'\n", value);
982                         }
983                         break;
984                 case SUBST_PARENT:
985                         {
986                                 struct udev_device *dev_parent;
987                                 const char *devnode;
988
989                                 dev_parent = udev_device_get_parent(event->dev);
990                                 if (dev_parent == NULL)
991                                         break;
992                                 devnode = udev_device_get_devnode(dev_parent);
993                                 if (devnode != NULL) {
994                                         size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
995
996                                         util_strlcat(string, &devnode[devlen], maxsize);
997                                         dbg(event->udev, "found parent '%s', got node name '%s'\n",
998                                             udev_device_get_syspath(dev_parent), &devnode[devlen]);
999                                 }
1000                         }
1001                         break;
1002                 case SUBST_TEMP_NODE:
1003                         if (event->tmp_node[0] == '\0' && major(udev_device_get_devnum(dev)) > 0) {
1004                                 dbg(event->udev, "create temporary device node for callout\n");
1005                                 snprintf(event->tmp_node, sizeof(event->tmp_node), "%s/.tmp-%u-%u",
1006                                          udev_get_dev_path(event->udev),
1007                                          major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
1008                                 udev_node_mknod(dev, event->tmp_node, makedev(0,0), 0600, 0, 0);
1009                         }
1010                         util_strlcat(string, event->tmp_node, maxsize);
1011                         dbg(event->udev, "substitute temporary device node name '%s'\n", event->tmp_node);
1012                         break;
1013                 case SUBST_NAME:
1014                         if (event->name != NULL) {
1015                                 util_strlcat(string, event->name, maxsize);
1016                                 dbg(event->udev, "substitute name '%s'\n", event->name);
1017                         } else {
1018                                 util_strlcat(string, udev_device_get_sysname(dev), maxsize);
1019                                 dbg(event->udev, "substitute sysname '%s'\n", udev_device_get_sysname(dev));
1020                         }
1021                         break;
1022                 case SUBST_LINKS:
1023                         {
1024                                 struct udev_list_entry *list_entry;
1025
1026                                 list_entry = udev_device_get_properties_list_entry(dev);
1027                                 util_strlcpy(string, udev_list_entry_get_name(list_entry), maxsize);
1028                                 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) {
1029                                         util_strlcat(string, " ", maxsize);
1030                                         util_strlcat(string, udev_list_entry_get_name(list_entry), maxsize);
1031                                 }
1032                         }
1033                         break;
1034                 case SUBST_ROOT:
1035                         util_strlcat(string, udev_get_dev_path(event->udev), maxsize);
1036                         dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev));
1037                         break;
1038                 case SUBST_SYS:
1039                         util_strlcat(string, udev_get_sys_path(event->udev), maxsize);
1040                         dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev));
1041                         break;
1042                 case SUBST_ENV:
1043                         if (attr == NULL) {
1044                                 dbg(event->udev, "missing attribute\n");
1045                                 break;
1046                         } else {
1047                                 struct udev_list_entry *list_entry;
1048                                 const char *value;
1049
1050                                 list_entry = udev_device_get_properties_list_entry(event->dev);
1051                                 list_entry = udev_list_entry_get_by_name(list_entry, attr);
1052                                 if (list_entry == NULL)
1053                                         break;
1054                                 value = udev_list_entry_get_value(list_entry);
1055                                 dbg(event->udev, "substitute env '%s=%s'\n", attr, value);
1056                                 util_strlcat(string, value, maxsize);
1057                                 break;
1058                         }
1059                 default:
1060                         err(event->udev, "unknown substitution type=%i\n", type);
1061                         break;
1062                 }
1063                 /* possibly truncate to format-char specified length */
1064                 if (len >= 0 && len < (int)strlen(head)) {
1065                         head[len] = '\0';
1066                         dbg(event->udev, "truncate to %i chars, subtitution string becomes '%s'\n", len, head);
1067                 }
1068                 util_strlcat(string, temp, maxsize);
1069         }
1070 }
1071
1072 static char *key_val(struct udev_rule *rule, struct key *key)
1073 {
1074         return rule->buf + key->val_off;
1075 }
1076
1077 static char *key_pair_name(struct udev_rule *rule, struct key_pair *pair)
1078 {
1079         return rule->buf + pair->key_name_off;
1080 }
1081
1082 static int match_key(struct udev *udev, const char *key_name, struct udev_rule *rule, struct key *key, const char *val)
1083 {
1084         char value[UTIL_PATH_SIZE];
1085         char *key_value;
1086         char *pos;
1087         int match = 0;
1088
1089         if (key->operation != KEY_OP_MATCH &&
1090             key->operation != KEY_OP_NOMATCH)
1091                 return 0;
1092
1093         if (val == NULL)
1094                 val = "";
1095
1096         /* look for a matching string, parts are separated by '|' */
1097         util_strlcpy(value, rule->buf + key->val_off, sizeof(value));
1098         key_value = value;
1099         dbg(udev, "key %s value='%s'\n", key_name, key_value);
1100         while (key_value != NULL) {
1101                 pos = strchr(key_value, '|');
1102                 if (pos != NULL) {
1103                         pos[0] = '\0';
1104                         pos = &pos[1];
1105                 }
1106
1107                 dbg(udev, "match %s '%s' <-> '%s'\n", key_name, key_value, val);
1108                 match = (fnmatch(key_value, val, 0) == 0);
1109                 if (match)
1110                         break;
1111
1112                 key_value = pos;
1113         }
1114
1115         if (match && (key->operation == KEY_OP_MATCH)) {
1116                 dbg(udev, "%s is true (matching value)\n", key_name);
1117                 return 0;
1118         }
1119         if (!match && (key->operation == KEY_OP_NOMATCH)) {
1120                 dbg(udev, "%s is true (non-matching value)\n", key_name);
1121                 return 0;
1122         }
1123         return -1;
1124 }
1125
1126 /* match a single rule against a given device and possibly its parent devices */
1127 static int match_rule(struct udev_event *event, struct udev_rule *rule)
1128 {
1129         struct udev_device *dev = event->dev;
1130         int i;
1131
1132         if (match_key(event->udev, "ACTION", rule, &rule->action, udev_device_get_action(dev)))
1133                 goto nomatch;
1134
1135         if (match_key(event->udev, "KERNEL", rule, &rule->kernel, udev_device_get_sysname(dev)))
1136                 goto nomatch;
1137
1138         if (match_key(event->udev, "SUBSYSTEM", rule, &rule->subsystem, udev_device_get_subsystem(dev)))
1139                 goto nomatch;
1140
1141         if (match_key(event->udev, "DEVPATH", rule, &rule->devpath, udev_device_get_devpath(dev)))
1142                 goto nomatch;
1143
1144         if (match_key(event->udev, "DRIVER", rule, &rule->driver, udev_device_get_driver(dev)))
1145                 goto nomatch;
1146
1147         /* match NAME against a value assigned by an earlier rule */
1148         if (match_key(event->udev, "NAME", rule, &rule->name, event->name))
1149                 goto nomatch;
1150
1151         /* match against current list of symlinks */
1152         if (rule->symlink_match.operation == KEY_OP_MATCH ||
1153             rule->symlink_match.operation == KEY_OP_NOMATCH) {
1154                 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
1155                 struct udev_list_entry *list_entry;
1156                 int match = 0;
1157
1158                 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
1159                         const char *devlink;
1160
1161                         devlink =  &udev_list_entry_get_name(list_entry)[devlen];
1162                         if (match_key(event->udev, "SYMLINK", rule, &rule->symlink_match, devlink) == 0) {
1163                                 match = 1;
1164                                 break;
1165                         }
1166                 }
1167                 if (!match)
1168                         goto nomatch;
1169         }
1170
1171         for (i = 0; i < rule->env.count; i++) {
1172                 struct key_pair *pair = &rule->env.keys[i];
1173
1174                 /* we only check for matches, assignments will be handled later */
1175                 if (pair->key.operation == KEY_OP_MATCH ||
1176                     pair->key.operation == KEY_OP_NOMATCH) {
1177                         struct udev_list_entry *list_entry;
1178                         const char *key_name = key_pair_name(rule, pair);
1179                         const char *value;
1180
1181                         list_entry = udev_device_get_properties_list_entry(event->dev);
1182                         list_entry = udev_list_entry_get_by_name(list_entry, key_name);
1183                         value = udev_list_entry_get_value(list_entry);
1184                         if (value == NULL) {
1185                                 dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
1186                                 value = "";
1187                         }
1188                         if (match_key(event->udev, "ENV", rule, &pair->key, value))
1189                                 goto nomatch;
1190                 }
1191         }
1192
1193         if (rule->test.operation == KEY_OP_MATCH ||
1194             rule->test.operation == KEY_OP_NOMATCH) {
1195                 char filename[UTIL_PATH_SIZE];
1196                 char *subsys;
1197                 char *sysname;
1198                 char *attrib;
1199                 struct stat statbuf;
1200                 int match;
1201
1202                 util_strlcpy(filename, key_val(rule, &rule->test), sizeof(filename));
1203                 udev_rules_apply_format(event, filename, sizeof(filename));
1204
1205                 if (split_subsys_sysname(event->udev, filename, &subsys, &sysname, &attrib) == 0) {
1206                         struct udev_device *d;
1207                         d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
1208                         if (d != NULL) {
1209                                 util_strlcpy(filename, udev_device_get_syspath(d), sizeof(filename));
1210                                 if (attrib != NULL) {
1211                                         util_strlcat(filename, "/", sizeof(filename));
1212                                         util_strlcat(filename, attrib, sizeof(filename));
1213                                 }
1214                                 udev_device_unref(d);
1215                         }
1216                 } else if (filename[0] != '/') {
1217                         char tmp[UTIL_PATH_SIZE];
1218
1219                         util_strlcpy(tmp, udev_device_get_syspath(dev), sizeof(tmp));
1220                         util_strlcat(tmp, "/", sizeof(tmp));
1221                         util_strlcat(tmp, filename, sizeof(tmp));
1222                         util_strlcpy(filename, tmp, sizeof(filename));
1223                 }
1224
1225                 attr_subst_subdir(filename, sizeof(filename));
1226
1227                 match = (stat(filename, &statbuf) == 0);
1228                 info(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
1229                 if (match && rule->test_mode_mask > 0) {
1230                         match = ((statbuf.st_mode & rule->test_mode_mask) > 0);
1231                         info(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
1232                              match ? "matches" : "does not match",
1233                              rule->test_mode_mask);
1234                 }
1235                 if (match && rule->test.operation == KEY_OP_NOMATCH)
1236                         goto nomatch;
1237                 if (!match && rule->test.operation == KEY_OP_MATCH)
1238                         goto nomatch;
1239                 dbg(event->udev, "TEST key is true\n");
1240         }
1241
1242         if (rule->wait_for.operation != KEY_OP_UNSET) {
1243                 char filename[UTIL_PATH_SIZE];
1244                 int found;
1245
1246                 util_strlcpy(filename, key_val(rule, &rule->wait_for), sizeof(filename));
1247                 udev_rules_apply_format(event, filename, sizeof(filename));
1248                 found = (wait_for_file(event, filename, 10) == 0);
1249                 if (!found && (rule->wait_for.operation != KEY_OP_NOMATCH))
1250                         goto nomatch;
1251         }
1252
1253         /* check for matching sysfs attribute pairs */
1254         for (i = 0; i < rule->attr.count; i++) {
1255                 struct key_pair *pair = &rule->attr.keys[i];
1256
1257                 if (pair->key.operation == KEY_OP_MATCH ||
1258                     pair->key.operation == KEY_OP_NOMATCH) {
1259                         char attr[UTIL_PATH_SIZE];
1260                         const char *key_name = key_pair_name(rule, pair);
1261                         const char *key_value = key_val(rule, &pair->key);
1262                         char *subsys;
1263                         char *sysname;
1264                         char *attrib;
1265                         char value[UTIL_NAME_SIZE] = "";
1266                         size_t len;
1267
1268                         util_strlcpy(attr, key_name, sizeof(attr));
1269                         if (split_subsys_sysname(event->udev, attr, &subsys, &sysname, &attrib) == 0) {
1270                                 struct udev_device *d;
1271                                 const char *val;
1272
1273                                 if (attrib == NULL)
1274                                         goto nomatch;
1275                                 d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
1276                                 if (d == NULL)
1277                                         goto nomatch;
1278                                 val = udev_device_get_attr_value(d, attrib);
1279                                 if (val != NULL)
1280                                         util_strlcpy(value, val, sizeof(value));
1281                                 udev_device_unref(d);
1282                         }
1283
1284                         if (value[0]=='\0') {
1285                                 const char *val;
1286
1287                                 val = udev_device_get_attr_value(dev, key_name);
1288                                 if (val != NULL)
1289                                         util_strlcpy(value, val, sizeof(value));
1290                         }
1291
1292                         if (value[0]=='\0')
1293                                 goto nomatch;
1294
1295                         /* strip trailing whitespace of value, if not asked to match for it */
1296                         len = strlen(key_value);
1297                         if (len > 0 && !isspace(key_value[len-1])) {
1298                                 len = strlen(value);
1299                                 while (len > 0 && isspace(value[--len]))
1300                                         value[len] = '\0';
1301                                 dbg(event->udev, "removed trailing whitespace from '%s'\n", value);
1302                         }
1303
1304                         if (match_key(event->udev, "ATTR", rule, &pair->key, value))
1305                                 goto nomatch;
1306                 }
1307         }
1308
1309         /* walk up the chain of parent devices and find a match */
1310         event->dev_parent = dev;
1311         while (1) {
1312                 /* check for matching kernel device name */
1313                 if (match_key(event->udev, "KERNELS", rule,
1314                               &rule->kernels, udev_device_get_sysname(event->dev_parent)))
1315                         goto try_parent;
1316
1317                 /* check for matching subsystem value */
1318                 if (match_key(event->udev, "SUBSYSTEMS", rule,
1319                               &rule->subsystems, udev_device_get_subsystem(event->dev_parent)))
1320                         goto try_parent;
1321
1322                 /* check for matching driver */
1323                 if (match_key(event->udev, "DRIVERS", rule,
1324                               &rule->drivers, udev_device_get_driver(event->dev_parent)))
1325                         goto try_parent;
1326
1327                 /* check for matching sysfs attribute pairs */
1328                 for (i = 0; i < rule->attrs.count; i++) {
1329                         struct key_pair *pair = &rule->attrs.keys[i];
1330
1331                         if (pair->key.operation == KEY_OP_MATCH ||
1332                             pair->key.operation == KEY_OP_NOMATCH) {
1333                                 const char *key_name = key_pair_name(rule, pair);
1334                                 const char *key_value = key_val(rule, &pair->key);
1335                                 const char *val;
1336                                 char value[UTIL_NAME_SIZE];
1337                                 size_t len;
1338
1339                                 val = udev_device_get_attr_value(event->dev_parent, key_name);
1340                                 if (val == NULL)
1341                                         val = udev_device_get_attr_value(dev, key_name);
1342                                 if (val == NULL)
1343                                         goto try_parent;
1344                                 util_strlcpy(value, val, sizeof(value));
1345
1346                                 /* strip trailing whitespace of value, if not asked to match for it */
1347                                 len = strlen(key_value);
1348                                 if (len > 0 && !isspace(key_value[len-1])) {
1349                                         len = strlen(value);
1350                                         while (len > 0 && isspace(value[--len]))
1351                                                 value[len] = '\0';
1352                                         dbg(event->udev, "removed trailing whitespace from '%s'\n", value);
1353                                 }
1354
1355                                 if (match_key(event->udev, "ATTRS", rule, &pair->key, value))
1356                                         goto try_parent;
1357                         }
1358                 }
1359
1360                 /* found matching device  */
1361                 break;
1362 try_parent:
1363                 /* move to parent device */
1364                 dbg(event->udev, "try parent sysfs device\n");
1365                 event->dev_parent = udev_device_get_parent(event->dev_parent);
1366                 if (event->dev_parent == NULL)
1367                         goto nomatch;
1368                 dbg(event->udev, "looking at dev_parent->devpath='%s'\n",
1369                     udev_device_get_syspath(event->dev_parent));
1370         }
1371
1372         /* execute external program */
1373         if (rule->program.operation != KEY_OP_UNSET) {
1374                 char program[UTIL_PATH_SIZE];
1375                 char result[UTIL_PATH_SIZE];
1376
1377                 util_strlcpy(program, key_val(rule, &rule->program), sizeof(program));
1378                 udev_rules_apply_format(event, program, sizeof(program));
1379                 if (run_program(event->dev, program, result, sizeof(result), NULL) != 0) {
1380                         dbg(event->udev, "PROGRAM is false\n");
1381                         event->program_result[0] = '\0';
1382                         if (rule->program.operation != KEY_OP_NOMATCH)
1383                                 goto nomatch;
1384                 } else {
1385                         int count;
1386
1387                         dbg(event->udev, "PROGRAM matches\n");
1388                         util_remove_trailing_chars(result, '\n');
1389                         if (rule->string_escape == ESCAPE_UNSET ||
1390                             rule->string_escape == ESCAPE_REPLACE) {
1391                                 count = util_replace_chars(result, ALLOWED_CHARS_INPUT);
1392                                 if (count > 0)
1393                                         info(event->udev, "%i character(s) replaced\n" , count);
1394                         }
1395                         dbg(event->udev, "result is '%s'\n", result);
1396                         util_strlcpy(event->program_result, result, sizeof(event->program_result));
1397                         dbg(event->udev, "PROGRAM returned successful\n");
1398                         if (rule->program.operation == KEY_OP_NOMATCH)
1399                                 goto nomatch;
1400                 }
1401                 dbg(event->udev, "PROGRAM key is true\n");
1402         }
1403
1404         /* check for matching result of external program */
1405         if (match_key(event->udev, "RESULT", rule, &rule->result, event->program_result))
1406                 goto nomatch;
1407
1408         /* import variables returned from program or or file into properties */
1409         if (rule->import.operation != KEY_OP_UNSET) {
1410                 char import[UTIL_PATH_SIZE];
1411                 int rc = -1;
1412
1413                 util_strlcpy(import, key_val(rule, &rule->import), sizeof(import));
1414                 udev_rules_apply_format(event, import, sizeof(import));
1415                 dbg(event->udev, "check for IMPORT import='%s'\n", import);
1416                 if (rule->import_type == IMPORT_PROGRAM) {
1417                         rc = import_program_into_env(event->dev, import);
1418                 } else if (rule->import_type == IMPORT_FILE) {
1419                         dbg(event->udev, "import file import='%s'\n", import);
1420                         rc = import_file_into_env(event->dev, import);
1421                 } else if (rule->import_type == IMPORT_PARENT) {
1422                         dbg(event->udev, "import parent import='%s'\n", import);
1423                         rc = import_parent_into_env(event->dev, import);
1424                 }
1425                 if (rc != 0) {
1426                         dbg(event->udev, "IMPORT failed\n");
1427                         if (rule->import.operation != KEY_OP_NOMATCH)
1428                                 goto nomatch;
1429                 } else
1430                         dbg(event->udev, "IMPORT '%s' imported\n", key_val(rule, &rule->import));
1431                 dbg(event->udev, "IMPORT key is true\n");
1432         }
1433
1434         /* rule matches, if we have ENV assignments export it */
1435         for (i = 0; i < rule->env.count; i++) {
1436                 struct key_pair *pair = &rule->env.keys[i];
1437
1438                 if (pair->key.operation == KEY_OP_ASSIGN) {
1439                         char temp_value[UTIL_NAME_SIZE];
1440                         const char *key_name = key_pair_name(rule, pair);
1441                         const char *value = key_val(rule, &pair->key);
1442
1443                         /* make sure we don't write to the same string we possibly read from */
1444                         util_strlcpy(temp_value, value, sizeof(temp_value));
1445                         udev_rules_apply_format(event, temp_value, sizeof(temp_value));
1446
1447                         if (temp_value[0] != '\0') {
1448                                 struct udev_list_entry *entry;
1449
1450                                 info(event->udev, "set ENV '%s=%s'\n", key_name, temp_value);
1451                                 entry = udev_device_add_property(dev, key_name, temp_value);
1452                                 /* store in db */
1453                                 udev_list_entry_set_flag(entry, 1);
1454                         }
1455                 }
1456         }
1457
1458         /* if we have ATTR assignments, write value to sysfs file */
1459         for (i = 0; i < rule->attr.count; i++) {
1460                 struct key_pair *pair = &rule->attr.keys[i];
1461
1462                 if (pair->key.operation == KEY_OP_ASSIGN) {
1463                         const char *key_name = key_pair_name(rule, pair);
1464                         char *subsys;
1465                         char *sysname;
1466                         char *attrib;
1467                         char attr[UTIL_PATH_SIZE];
1468                         char value[UTIL_NAME_SIZE];
1469                         FILE *f;
1470
1471                         util_strlcpy(attr, key_name, sizeof(attr));
1472                         if (split_subsys_sysname(event->udev, attr, &subsys, &sysname, &attrib) == 0) {
1473                                 struct udev_device *d;
1474
1475                                 d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
1476                                 if (d != NULL) {
1477                                         util_strlcpy(attr, udev_device_get_syspath(d), sizeof(attr));
1478                                         if (attrib != NULL) {
1479                                                 util_strlcat(attr, "/", sizeof(attr));
1480                                                 util_strlcat(attr, attrib, sizeof(attr));
1481                                         }
1482                                         udev_device_unref(d);
1483                                 }
1484                         } else {
1485                                 util_strlcpy(attr, udev_device_get_syspath(dev), sizeof(attr));
1486                                 util_strlcat(attr, "/", sizeof(attr));
1487                                 util_strlcat(attr, key_name, sizeof(attr));
1488                         }
1489
1490                         attr_subst_subdir(attr, sizeof(attr));
1491
1492                         util_strlcpy(value, key_val(rule, &pair->key), sizeof(value));
1493                         udev_rules_apply_format(event, value, sizeof(value));
1494                         info(event->udev, "writing '%s' to sysfs file '%s'\n", value, attr);
1495                         f = fopen(attr, "w");
1496                         if (f != NULL) {
1497                                 if (!event->test)
1498                                         if (fprintf(f, "%s", value) <= 0)
1499                                                 err(event->udev, "error writing ATTR{%s}: %m\n", attr);
1500                                 fclose(f);
1501                         } else
1502                                 err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
1503                 }
1504         }
1505         return 0;
1506
1507 nomatch:
1508         return -1;
1509 }
1510
1511 int udev_rules_get_name(struct udev_rules *rules, struct udev_event *event)
1512 {
1513         struct udev_device *dev = event->dev;
1514         struct udev_rules_iter iter;
1515         struct udev_rule *rule;
1516         int name_set = 0;
1517
1518         dbg(event->udev, "device: '%s'\n", udev_device_get_syspath(dev));
1519
1520         /* look for a matching rule to apply */
1521         udev_rules_iter_init(&iter, rules);
1522         while (1) {
1523                 rule = udev_rules_iter_next(&iter);
1524                 if (rule == NULL)
1525                         break;
1526
1527                 if (name_set &&
1528                     (rule->name.operation == KEY_OP_ASSIGN ||
1529                      rule->name.operation == KEY_OP_ASSIGN_FINAL ||
1530                      rule->name.operation == KEY_OP_ADD)) {
1531                         dbg(event->udev, "node name already set, rule ignored\n");
1532                         continue;
1533                 }
1534
1535                 dbg(event->udev, "process rule\n");
1536                 if (match_rule(event, rule) == 0) {
1537                         /* apply options */
1538                         if (rule->ignore_device) {
1539                                 info(event->udev, "rule applied, '%s' is ignored\n", udev_device_get_sysname(dev));
1540                                 event->ignore_device = 1;
1541                                 return 0;
1542                         }
1543                         if (rule->ignore_remove) {
1544                                 udev_device_set_ignore_remove(dev, 1);
1545                                 dbg(event->udev, "remove event should be ignored\n");
1546                         }
1547                         if (rule->link_priority != 0) {
1548                                 udev_device_set_devlink_priority(dev, rule->link_priority);
1549                                 info(event->udev, "devlink_priority=%i\n", rule->link_priority);
1550                         }
1551                         if (rule->event_timeout >= 0) {
1552                                 udev_device_set_event_timeout(dev, rule->event_timeout);
1553                                 info(event->udev, "event_timeout=%i\n", rule->event_timeout);
1554                         }
1555                         /* apply all_partitions option only at a disk device */
1556                         if (rule->partitions > 0 &&
1557                             strcmp(udev_device_get_subsystem(dev), "block") == 0 &&
1558                             udev_device_get_sysnum(dev) == NULL) {
1559                                 udev_device_set_num_fake_partitions(dev, rule->partitions);
1560                                 dbg(event->udev, "creation of partition nodes requested\n");
1561                         }
1562
1563                         /* apply permissions */
1564                         if (!event->mode_final && rule->mode.operation != KEY_OP_UNSET) {
1565                                 if (rule->mode.operation == KEY_OP_ASSIGN_FINAL)
1566                                         event->mode_final = 1;
1567                                 char buf[20];
1568                                 util_strlcpy(buf, key_val(rule, &rule->mode), sizeof(buf));
1569                                 udev_rules_apply_format(event, buf, sizeof(buf));
1570                                 event->mode = strtol(buf, NULL, 8);
1571                                 dbg(event->udev, "applied mode=%#o to '%s'\n",
1572                                     event->mode, udev_device_get_sysname(dev));
1573                         }
1574                         if (!event->owner_final && rule->owner.operation != KEY_OP_UNSET) {
1575                                 if (rule->owner.operation == KEY_OP_ASSIGN_FINAL)
1576                                         event->owner_final = 1;
1577                                 util_strlcpy(event->owner, key_val(rule, &rule->owner), sizeof(event->owner));
1578                                 udev_rules_apply_format(event, event->owner, sizeof(event->owner));
1579                                 dbg(event->udev, "applied owner='%s' to '%s'\n",
1580                                     event->owner, udev_device_get_sysname(dev));
1581                         }
1582                         if (!event->group_final && rule->group.operation != KEY_OP_UNSET) {
1583                                 if (rule->group.operation == KEY_OP_ASSIGN_FINAL)
1584                                         event->group_final = 1;
1585                                 util_strlcpy(event->group, key_val(rule, &rule->group), sizeof(event->group));
1586                                 udev_rules_apply_format(event, event->group, sizeof(event->group));
1587                                 dbg(event->udev, "applied group='%s' to '%s'\n",
1588                                     event->group, udev_device_get_sysname(dev));
1589                         }
1590
1591                         /* collect symlinks */
1592                         if (!event->devlink_final &&
1593                             (rule->symlink.operation == KEY_OP_ASSIGN ||
1594                              rule->symlink.operation == KEY_OP_ASSIGN_FINAL ||
1595                              rule->symlink.operation == KEY_OP_ADD)) {
1596                                 char temp[UTIL_PATH_SIZE];
1597                                 char filename[UTIL_PATH_SIZE];
1598                                 char *pos, *next;
1599                                 int count = 0;
1600
1601                                 if (rule->symlink.operation == KEY_OP_ASSIGN_FINAL)
1602                                         event->devlink_final = 1;
1603                                 if (rule->symlink.operation == KEY_OP_ASSIGN ||
1604                                     rule->symlink.operation == KEY_OP_ASSIGN_FINAL) {
1605                                         info(event->udev, "reset symlink list\n");
1606                                         udev_device_cleanup_devlinks_list(dev);
1607                                 }
1608                                 /* allow  multiple symlinks separated by spaces */
1609                                 util_strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp));
1610                                 udev_rules_apply_format(event, temp, sizeof(temp));
1611                                 if (rule->string_escape == ESCAPE_UNSET)
1612                                         count = util_replace_chars(temp, ALLOWED_CHARS_FILE " ");
1613                                 else if (rule->string_escape == ESCAPE_REPLACE)
1614                                         count = util_replace_chars(temp, ALLOWED_CHARS_FILE);
1615                                 if (count > 0)
1616                                         info(event->udev, "%i character(s) replaced\n" , count);
1617                                 dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
1618                                 pos = temp;
1619                                 while (isspace(pos[0]))
1620                                         pos++;
1621                                 next = strchr(pos, ' ');
1622                                 while (next) {
1623                                         next[0] = '\0';
1624                                         info(event->udev, "add symlink '%s'\n", pos);
1625                                         util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
1626                                         util_strlcat(filename, "/", sizeof(filename));
1627                                         util_strlcat(filename, pos, sizeof(filename));
1628                                         udev_device_add_devlink(dev, filename);
1629                                         while (isspace(next[1]))
1630                                                 next++;
1631                                         pos = &next[1];
1632                                         next = strchr(pos, ' ');
1633                                 }
1634                                 if (pos[0] != '\0') {
1635                                         info(event->udev, "add symlink '%s'\n", pos);
1636                                         util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
1637                                         util_strlcat(filename, "/", sizeof(filename));
1638                                         util_strlcat(filename, pos, sizeof(filename));
1639                                         udev_device_add_devlink(dev, filename);
1640                                 }
1641                         }
1642
1643                         /* set name, later rules with name set will be ignored */
1644                         if (rule->name.operation == KEY_OP_ASSIGN ||
1645                             rule->name.operation == KEY_OP_ASSIGN_FINAL ||
1646                             rule->name.operation == KEY_OP_ADD) {
1647                                 int count;
1648
1649                                 name_set = 1;
1650                                 util_strlcpy(event->name, key_val(rule, &rule->name), sizeof(event->name));
1651                                 udev_rules_apply_format(event, event->name, sizeof(event->name));
1652                                 if (rule->string_escape == ESCAPE_UNSET ||
1653                                     rule->string_escape == ESCAPE_REPLACE) {
1654                                         count = util_replace_chars(event->name, ALLOWED_CHARS_FILE);
1655                                         if (count > 0)
1656                                                 info(event->udev, "%i character(s) replaced\n", count);
1657                                 }
1658
1659                                 info(event->udev, "rule applied, '%s' becomes '%s'\n",
1660                                      udev_device_get_sysname(dev), event->name);
1661                                 if (strcmp(udev_device_get_subsystem(dev), "net") != 0)
1662                                         dbg(event->udev, "'%s' owner='%s', group='%s', mode=%#o partitions=%i\n",
1663                                             event->name, event->owner, event->group, event->mode,
1664                                             udev_device_get_num_fake_partitions(dev));
1665                         }
1666
1667                         if (!event->run_final && rule->run.operation != KEY_OP_UNSET) {
1668                                 struct udev_list_entry *list_entry;
1669
1670                                 if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
1671                                         event->run_final = 1;
1672                                 if (rule->run.operation == KEY_OP_ASSIGN || rule->run.operation == KEY_OP_ASSIGN_FINAL) {
1673                                         info(event->udev, "reset run list\n");
1674                                         udev_list_cleanup(event->udev, &event->run_list);
1675                                 }
1676                                 dbg(event->udev, "add run '%s'\n", key_val(rule, &rule->run));
1677                                 list_entry = udev_list_entry_add(event->udev, &event->run_list,
1678                                                                  key_val(rule, &rule->run), NULL, 1, 0);
1679                                 if (rule->run_ignore_error && list_entry != NULL)
1680                                         udev_list_entry_set_flag(list_entry, 1);
1681                         }
1682
1683                         if (rule->last_rule) {
1684                                 dbg(event->udev, "last rule to be applied\n");
1685                                 break;
1686                         }
1687
1688                         if (rule->goto_label.operation != KEY_OP_UNSET) {
1689                                 dbg(event->udev, "moving forward to label '%s'\n", key_val(rule, &rule->goto_label));
1690                                 udev_rules_iter_goto(&iter, rule->goto_rule_off);
1691                         }
1692                 }
1693         }
1694
1695         if (!name_set) {
1696                 info(event->udev, "no node name set, will use kernel name '%s'\n",
1697                      udev_device_get_sysname(dev));
1698                 util_strlcpy(event->name, udev_device_get_sysname(dev), sizeof(event->name));
1699         }
1700
1701         if (event->tmp_node[0] != '\0') {
1702                 dbg(event->udev, "removing temporary device node\n");
1703                 unlink_secure(event->udev, event->tmp_node);
1704                 event->tmp_node[0] = '\0';
1705         }
1706         return 0;
1707 }
1708
1709 int udev_rules_get_run(struct udev_rules *rules, struct udev_event *event)
1710 {
1711         struct udev_device *dev = event->dev;
1712         struct udev_rules_iter iter;
1713         struct udev_rule *rule;
1714
1715         dbg(event->udev, "sysname: '%s'\n", udev_device_get_sysname(dev));
1716
1717         /* look for a matching rule to apply */
1718         udev_rules_iter_init(&iter, rules);
1719         while (1) {
1720                 rule = udev_rules_iter_next(&iter);
1721                 if (rule == NULL)
1722                         break;
1723
1724                 dbg(event->udev, "process rule\n");
1725                 if (rule->name.operation == KEY_OP_ASSIGN ||
1726                     rule->name.operation == KEY_OP_ASSIGN_FINAL ||
1727                     rule->name.operation == KEY_OP_ADD ||
1728                     rule->symlink.operation == KEY_OP_ASSIGN ||
1729                     rule->symlink.operation == KEY_OP_ASSIGN_FINAL ||
1730                     rule->symlink.operation == KEY_OP_ADD ||
1731                     rule->mode.operation != KEY_OP_UNSET ||
1732                     rule->owner.operation != KEY_OP_UNSET || rule->group.operation != KEY_OP_UNSET) {
1733                         dbg(event->udev, "skip rule that names a device\n");
1734                         continue;
1735                 }
1736
1737                 if (match_rule(event, rule) == 0) {
1738                         if (rule->ignore_device) {
1739                                 info(event->udev, "rule applied, '%s' is ignored\n", udev_device_get_sysname(dev));
1740                                 event->ignore_device = 1;
1741                                 return 0;
1742                         }
1743                         if (rule->ignore_remove) {
1744                                 udev_device_set_ignore_remove(dev, 1);
1745                                 dbg(event->udev, "remove event should be ignored\n");
1746                         }
1747
1748                         if (!event->run_final && rule->run.operation != KEY_OP_UNSET) {
1749                                 struct udev_list_entry *list_entry;
1750
1751                                 if (rule->run.operation == KEY_OP_ASSIGN ||
1752                                     rule->run.operation == KEY_OP_ASSIGN_FINAL) {
1753                                         info(event->udev, "reset run list\n");
1754                                         udev_list_cleanup(event->udev, &event->run_list);
1755                                 }
1756                                 dbg(event->udev, "add run '%s'\n", key_val(rule, &rule->run));
1757                                 list_entry = udev_list_entry_add(event->udev, &event->run_list,
1758                                                                  key_val(rule, &rule->run), NULL, 1, 0);
1759                                 if (rule->run_ignore_error && list_entry != NULL)
1760                                         udev_list_entry_set_flag(list_entry, 1);
1761                                 if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
1762                                         break;
1763                         }
1764
1765                         if (rule->last_rule) {
1766                                 dbg(event->udev, "last rule to be applied\n");
1767                                 break;
1768                         }
1769
1770                         if (rule->goto_label.operation != KEY_OP_UNSET) {
1771                                 dbg(event->udev, "moving forward to label '%s'\n", key_val(rule, &rule->goto_label));
1772                                 udev_rules_iter_goto(&iter, rule->goto_rule_off);
1773                         }
1774                 }
1775         }
1776
1777         return 0;
1778 }
1779
1780 static int get_key(struct udev_rules *rules, char **line, char **key, enum key_operation *operation, char **value)
1781 {
1782         char *linepos;
1783         char *temp;
1784
1785         linepos = *line;
1786         if (linepos == NULL && linepos[0] == '\0')
1787                 return -1;
1788
1789         /* skip whitespace */
1790         while (isspace(linepos[0]) || linepos[0] == ',')
1791                 linepos++;
1792
1793         /* get the key */
1794         if (linepos[0] == '\0')
1795                 return -1;
1796         *key = linepos;
1797
1798         while (1) {
1799                 linepos++;
1800                 if (linepos[0] == '\0')
1801                         return -1;
1802                 if (isspace(linepos[0]))
1803                         break;
1804                 if (linepos[0] == '=')
1805                         break;
1806                 if ((linepos[0] == '+') || (linepos[0] == '!') || (linepos[0] == ':'))
1807                         if (linepos[1] == '=')
1808                                 break;
1809         }
1810
1811         /* remember end of key */
1812         temp = linepos;
1813
1814         /* skip whitespace after key */
1815         while (isspace(linepos[0]))
1816                 linepos++;
1817         if (linepos[0] == '\0')
1818                 return -1;
1819
1820         /* get operation type */
1821         if (linepos[0] == '=' && linepos[1] == '=') {
1822                 *operation = KEY_OP_MATCH;
1823                 linepos += 2;
1824                 dbg(rules->udev, "match:\n");
1825         } else if (linepos[0] == '!' && linepos[1] == '=') {
1826                 *operation = KEY_OP_NOMATCH;
1827                 linepos += 2;
1828                 dbg(rules->udev, "nomatch:\n");
1829         } else if (linepos[0] == '+' && linepos[1] == '=') {
1830                 *operation = KEY_OP_ADD;
1831                 linepos += 2;
1832                 dbg(rules->udev, "add:\n");
1833         } else if (linepos[0] == '=') {
1834                 *operation = KEY_OP_ASSIGN;
1835                 linepos++;
1836                 dbg(rules->udev, "assign:\n");
1837         } else if (linepos[0] == ':' && linepos[1] == '=') {
1838                 *operation = KEY_OP_ASSIGN_FINAL;
1839                 linepos += 2;
1840                 dbg(rules->udev, "assign_final:\n");
1841         } else
1842                 return -1;
1843
1844         /* terminate key */
1845         temp[0] = '\0';
1846
1847         /* skip whitespace after operator */
1848         while (isspace(linepos[0]))
1849                 linepos++;
1850         if (linepos[0] == '\0')
1851                 return -1;
1852
1853         /* get the value*/
1854         if (linepos[0] == '"')
1855                 linepos++;
1856         else
1857                 return -1;
1858         *value = linepos;
1859
1860         temp = strchr(linepos, '"');
1861         if (!temp)
1862                 return -1;
1863         temp[0] = '\0';
1864         temp++;
1865         dbg(rules->udev, "'%s'-'%s'\n", *key, *value);
1866
1867         /* move line to next key */
1868         *line = temp;
1869         return 0;
1870 }
1871
1872 /* extract possible KEY{attr} */
1873 static char *get_key_attribute(struct udev_rules *rules, char *str)
1874 {
1875         char *pos;
1876         char *attr;
1877
1878         attr = strchr(str, '{');
1879         if (attr != NULL) {
1880                 attr++;
1881                 pos = strchr(attr, '}');
1882                 if (pos == NULL) {
1883                         err(rules->udev, "missing closing brace for format\n");
1884                         return NULL;
1885                 }
1886                 pos[0] = '\0';
1887                 dbg(rules->udev, "attribute='%s'\n", attr);
1888                 return attr;
1889         }
1890
1891         return NULL;
1892 }
1893
1894 static int add_rule_key(struct udev_rule *rule, struct key *key,
1895                         enum key_operation operation, const char *value)
1896 {
1897         size_t val_len = strnlen(value, UTIL_PATH_SIZE);
1898
1899         key->operation = operation;
1900
1901         key->val_off = rule->bufsize;
1902         util_strlcpy(rule->buf + rule->bufsize, value, val_len+1);
1903         rule->bufsize += val_len+1;
1904
1905         return 0;
1906 }
1907
1908 static int add_rule_key_pair(struct udev_rules *rules, struct udev_rule *rule, struct key_pairs *pairs,
1909                              enum key_operation operation, const char *key, const char *value)
1910 {
1911         size_t key_len = strnlen(key, UTIL_PATH_SIZE);
1912
1913         if (pairs->count >= PAIRS_MAX) {
1914                 err(rules->udev, "skip, too many keys of the same type in a single rule\n");
1915                 return -1;
1916         }
1917
1918         add_rule_key(rule, &pairs->keys[pairs->count].key, operation, value);
1919
1920         /* add the key-name of the pair */
1921         pairs->keys[pairs->count].key_name_off = rule->bufsize;
1922         util_strlcpy(rule->buf + rule->bufsize, key, key_len+1);
1923         rule->bufsize += key_len+1;
1924
1925         pairs->count++;
1926
1927         return 0;
1928 }
1929
1930 static int add_to_rules(struct udev_rules *rules, char *line, const char *filename, unsigned int lineno)
1931 {
1932         char buf[sizeof(struct udev_rule) + UTIL_LINE_SIZE];
1933         struct udev_rule *rule;
1934         size_t rule_size;
1935         int valid;
1936         char *linepos;
1937         char *attr;
1938         size_t padding;
1939         int physdev = 0;
1940
1941         memset(buf, 0x00, sizeof(buf));
1942         rule = (struct udev_rule *) buf;
1943         rule->event_timeout = -1;
1944         linepos = line;
1945         valid = 0;
1946
1947         /* get all the keys */
1948         while (1) {
1949                 char *key;
1950                 char *value;
1951                 enum key_operation operation = KEY_OP_UNSET;
1952
1953                 if (get_key(rules, &linepos, &key, &operation, &value) != 0)
1954                         break;
1955
1956                 if (strcasecmp(key, "ACTION") == 0) {
1957                         if (operation != KEY_OP_MATCH &&
1958                             operation != KEY_OP_NOMATCH) {
1959                                 err(rules->udev, "invalid ACTION operation\n");
1960                                 goto invalid;
1961                         }
1962                         add_rule_key(rule, &rule->action, operation, value);
1963                         valid = 1;
1964                         continue;
1965                 }
1966
1967                 if (strcasecmp(key, "DEVPATH") == 0) {
1968                         if (operation != KEY_OP_MATCH &&
1969                             operation != KEY_OP_NOMATCH) {
1970                                 err(rules->udev, "invalid DEVPATH operation\n");
1971                                 goto invalid;
1972                         }
1973                         add_rule_key(rule, &rule->devpath, operation, value);
1974                         valid = 1;
1975                         continue;
1976                 }
1977
1978                 if (strcasecmp(key, "KERNEL") == 0) {
1979                         if (operation != KEY_OP_MATCH &&
1980                             operation != KEY_OP_NOMATCH) {
1981                                 err(rules->udev, "invalid KERNEL operation\n");
1982                                 goto invalid;
1983                         }
1984                         add_rule_key(rule, &rule->kernel, operation, value);
1985                         valid = 1;
1986                         continue;
1987                 }
1988
1989                 if (strcasecmp(key, "SUBSYSTEM") == 0) {
1990                         if (operation != KEY_OP_MATCH &&
1991                             operation != KEY_OP_NOMATCH) {
1992                                 err(rules->udev, "invalid SUBSYSTEM operation\n");
1993                                 goto invalid;
1994                         }
1995                         /* bus, class, subsystem events should all be the same */
1996                         if (strcmp(value, "subsystem") == 0 ||
1997                             strcmp(value, "bus") == 0 ||
1998                             strcmp(value, "class") == 0) {
1999                                 if (strcmp(value, "bus") == 0 || strcmp(value, "class") == 0)
2000                                         err(rules->udev, "'%s' must be specified as 'subsystem' \n"
2001                                             "please fix it in %s:%u", value, filename, lineno);
2002                                 add_rule_key(rule, &rule->subsystem, operation, "subsystem|class|bus");
2003                         } else
2004                                 add_rule_key(rule, &rule->subsystem, operation, value);
2005                         valid = 1;
2006                         continue;
2007                 }
2008
2009                 if (strcasecmp(key, "DRIVER") == 0) {
2010                         if (operation != KEY_OP_MATCH &&
2011                             operation != KEY_OP_NOMATCH) {
2012                                 err(rules->udev, "invalid DRIVER operation\n");
2013                                 goto invalid;
2014                         }
2015                         add_rule_key(rule, &rule->driver, operation, value);
2016                         valid = 1;
2017                         continue;
2018                 }
2019
2020                 if (strncasecmp(key, "ATTR{", sizeof("ATTR{")-1) == 0) {
2021                         attr = get_key_attribute(rules, key + sizeof("ATTR")-1);
2022                         if (attr == NULL) {
2023                                 err(rules->udev, "error parsing ATTR attribute\n");
2024                                 goto invalid;
2025                         }
2026                         if (add_rule_key_pair(rules, rule, &rule->attr, operation, attr, value) != 0)
2027                                 goto invalid;
2028                         valid = 1;
2029                         continue;
2030                 }
2031
2032                 if (strcasecmp(key, "KERNELS") == 0 ||
2033                     strcasecmp(key, "ID") == 0) {
2034                         if (operation != KEY_OP_MATCH &&
2035                             operation != KEY_OP_NOMATCH) {
2036                                 err(rules->udev, "invalid KERNELS operation\n");
2037                                 goto invalid;
2038                         }
2039                         add_rule_key(rule, &rule->kernels, operation, value);
2040                         valid = 1;
2041                         continue;
2042                 }
2043
2044                 if (strcasecmp(key, "SUBSYSTEMS") == 0 ||
2045                     strcasecmp(key, "BUS") == 0) {
2046                         if (operation != KEY_OP_MATCH &&
2047                             operation != KEY_OP_NOMATCH) {
2048                                 err(rules->udev, "invalid SUBSYSTEMS operation\n");
2049                                 goto invalid;
2050                         }
2051                         add_rule_key(rule, &rule->subsystems, operation, value);
2052                         valid = 1;
2053                         continue;
2054                 }
2055
2056                 if (strcasecmp(key, "DRIVERS") == 0) {
2057                         if (operation != KEY_OP_MATCH &&
2058                             operation != KEY_OP_NOMATCH) {
2059                                 err(rules->udev, "invalid DRIVERS operation\n");
2060                                 goto invalid;
2061                         }
2062                         add_rule_key(rule, &rule->drivers, operation, value);
2063                         valid = 1;
2064                         continue;
2065                 }
2066
2067                 if (strncasecmp(key, "ATTRS{", sizeof("ATTRS{")-1) == 0 ||
2068                     strncasecmp(key, "SYSFS{", sizeof("SYSFS{")-1) == 0) {
2069                         if (operation != KEY_OP_MATCH &&
2070                             operation != KEY_OP_NOMATCH) {
2071                                 err(rules->udev, "invalid ATTRS operation\n");
2072                                 goto invalid;
2073                         }
2074                         attr = get_key_attribute(rules, key + sizeof("ATTRS")-1);
2075                         if (attr == NULL) {
2076                                 err(rules->udev, "error parsing ATTRS attribute\n");
2077                                 goto invalid;
2078                         }
2079                         if (strncmp(attr, "device/", 7) == 0)
2080                                 err(rules->udev, "the 'device' link may not be available in a future kernel, "
2081                                     "please fix it in %s:%u", filename, lineno);
2082                         else if (strstr(attr, "../") != NULL)
2083                                 err(rules->udev, "do not reference parent sysfs directories directly, "
2084                                     "it may break with a future kernel, please fix it in %s:%u", filename, lineno);
2085                         if (add_rule_key_pair(rules, rule, &rule->attrs, operation, attr, value) != 0)
2086                                 goto invalid;
2087                         valid = 1;
2088                         continue;
2089                 }
2090
2091                 if (strncasecmp(key, "ENV{", sizeof("ENV{")-1) == 0) {
2092                         attr = get_key_attribute(rules, key + sizeof("ENV")-1);
2093                         if (attr == NULL) {
2094                                 err(rules->udev, "error parsing ENV attribute\n");
2095                                 goto invalid;
2096                         }
2097                         if (strncmp(attr, "PHYSDEV", 7) == 0)
2098                                 physdev = 1;
2099                         if (add_rule_key_pair(rules, rule, &rule->env, operation, attr, value) != 0)
2100                                 goto invalid;
2101                         valid = 1;
2102                         continue;
2103                 }
2104
2105                 if (strcasecmp(key, "PROGRAM") == 0) {
2106                         add_rule_key(rule, &rule->program, operation, value);
2107                         valid = 1;
2108                         continue;
2109                 }
2110
2111                 if (strcasecmp(key, "RESULT") == 0) {
2112                         if (operation != KEY_OP_MATCH &&
2113                             operation != KEY_OP_NOMATCH) {
2114                                 err(rules->udev, "invalid RESULT operation\n");
2115                                 goto invalid;
2116                         }
2117                         add_rule_key(rule, &rule->result, operation, value);
2118                         valid = 1;
2119                         continue;
2120                 }
2121
2122                 if (strncasecmp(key, "IMPORT", sizeof("IMPORT")-1) == 0) {
2123                         attr = get_key_attribute(rules, key + sizeof("IMPORT")-1);
2124                         if (attr != NULL && strstr(attr, "program")) {
2125                                 dbg(rules->udev, "IMPORT will be executed\n");
2126                                 rule->import_type  = IMPORT_PROGRAM;
2127                         } else if (attr != NULL && strstr(attr, "file")) {
2128                                 dbg(rules->udev, "IMPORT will be included as file\n");
2129                                 rule->import_type  = IMPORT_FILE;
2130                         } else if (attr != NULL && strstr(attr, "parent")) {
2131                                 dbg(rules->udev, "IMPORT will include the parent values\n");
2132                                 rule->import_type = IMPORT_PARENT;
2133                         } else {
2134                                 /* figure it out if it is executable */
2135                                 char file[UTIL_PATH_SIZE];
2136                                 char *pos;
2137                                 struct stat statbuf;
2138
2139                                 util_strlcpy(file, value, sizeof(file));
2140                                 pos = strchr(file, ' ');
2141                                 if (pos)
2142                                         pos[0] = '\0';
2143
2144                                 /* allow programs in /lib/udev called without the path */
2145                                 if (strchr(file, '/') == NULL) {
2146                                         util_strlcpy(file, UDEV_PREFIX "/lib/udev/", sizeof(file));
2147                                         util_strlcat(file, value, sizeof(file));
2148                                         pos = strchr(file, ' ');
2149                                         if (pos)
2150                                                 pos[0] = '\0';
2151                                 }
2152
2153                                 dbg(rules->udev, "IMPORT auto mode for '%s'\n", file);
2154                                 if (!lstat(file, &statbuf) && (statbuf.st_mode & S_IXUSR)) {
2155                                         dbg(rules->udev, "IMPORT is executable, will be executed (autotype)\n");
2156                                         rule->import_type  = IMPORT_PROGRAM;
2157                                 } else {
2158                                         dbg(rules->udev, "IMPORT is not executable, will be included as file (autotype)\n");
2159                                         rule->import_type  = IMPORT_FILE;
2160                                 }
2161                         }
2162                         add_rule_key(rule, &rule->import, operation, value);
2163                         valid = 1;
2164                         continue;
2165                 }
2166
2167                 if (strncasecmp(key, "TEST", sizeof("TEST")-1) == 0) {
2168                         if (operation != KEY_OP_MATCH &&
2169                             operation != KEY_OP_NOMATCH) {
2170                                 err(rules->udev, "invalid TEST operation\n");
2171                                 goto invalid;
2172                         }
2173                         attr = get_key_attribute(rules, key + sizeof("TEST")-1);
2174                         if (attr != NULL)
2175                                 rule->test_mode_mask = strtol(attr, NULL, 8);
2176                         add_rule_key(rule, &rule->test, operation, value);
2177                         valid = 1;
2178                         continue;
2179                 }
2180
2181                 if (strncasecmp(key, "RUN", sizeof("RUN")-1) == 0) {
2182                         attr = get_key_attribute(rules, key + sizeof("RUN")-1);
2183                         if (attr != NULL) {
2184                                 if (strstr(attr, "ignore_error"))
2185                                         rule->run_ignore_error = 1;
2186                         }
2187                         add_rule_key(rule, &rule->run, operation, value);
2188                         valid = 1;
2189                         continue;
2190                 }
2191
2192                 if (strcasecmp(key, "WAIT_FOR") == 0 || strcasecmp(key, "WAIT_FOR_SYSFS") == 0) {
2193                         add_rule_key(rule, &rule->wait_for, operation, value);
2194                         valid = 1;
2195                         continue;
2196                 }
2197
2198                 if (strcasecmp(key, "LABEL") == 0) {
2199                         add_rule_key(rule, &rule->label, operation, value);
2200                         valid = 1;
2201                         continue;
2202                 }
2203
2204                 if (strcasecmp(key, "GOTO") == 0) {
2205                         add_rule_key(rule, &rule->goto_label, operation, value);
2206                         valid = 1;
2207                         continue;
2208                 }
2209
2210                 if (strncasecmp(key, "NAME", sizeof("NAME")-1) == 0) {
2211                         attr = get_key_attribute(rules, key + sizeof("NAME")-1);
2212                         if (attr != NULL) {
2213                                 if (strstr(attr, "all_partitions") != NULL) {
2214                                         dbg(rules->udev, "creation of partition nodes requested\n");
2215                                         rule->partitions = DEFAULT_FAKE_PARTITIONS_COUNT;
2216                                 }
2217                                 if (strstr(attr, "ignore_remove") != NULL) {
2218                                         dbg(rules->udev, "remove event should be ignored\n");
2219                                         rule->ignore_remove = 1;
2220                                 }
2221                         }
2222                         if (value[0] == '\0')
2223                                 dbg(rules->udev, "name empty, node creation supressed\n");
2224                         add_rule_key(rule, &rule->name, operation, value);
2225                         continue;
2226                 }
2227
2228                 if (strcasecmp(key, "SYMLINK") == 0) {
2229                         if (operation == KEY_OP_MATCH ||
2230                             operation == KEY_OP_NOMATCH)
2231                                 add_rule_key(rule, &rule->symlink_match, operation, value);
2232                         else
2233                                 add_rule_key(rule, &rule->symlink, operation, value);
2234                         valid = 1;
2235                         continue;
2236                 }
2237
2238                 if (strcasecmp(key, "OWNER") == 0) {
2239                         valid = 1;
2240                         if (rules->resolve_names && (!strchr(value, '$') && !strchr(value, '%'))) {
2241                                 char *endptr;
2242                                 strtoul(value, &endptr, 10);
2243                                 if (endptr[0] != '\0') {
2244                                         char owner[32];
2245                                         uid_t uid = lookup_user(rules->udev, value);
2246                                         dbg(rules->udev, "replacing username='%s' by id=%i\n", value, uid);
2247                                         sprintf(owner, "%u", (unsigned int) uid);
2248                                         add_rule_key(rule, &rule->owner, operation, owner);
2249                                         continue;
2250                                 }
2251                         }
2252
2253                         add_rule_key(rule, &rule->owner, operation, value);
2254                         continue;
2255                 }
2256
2257                 if (strcasecmp(key, "GROUP") == 0) {
2258                         valid = 1;
2259                         if (rules->resolve_names && (!strchr(value, '$') && !strchr(value, '%'))) {
2260                                 char *endptr;
2261                                 strtoul(value, &endptr, 10);
2262                                 if (endptr[0] != '\0') {
2263                                         char group[32];
2264                                         gid_t gid = lookup_group(rules->udev, value);
2265                                         dbg(rules->udev, "replacing groupname='%s' by id=%i\n", value, gid);
2266                                         sprintf(group, "%u", (unsigned int) gid);
2267                                         add_rule_key(rule, &rule->group, operation, group);
2268                                         continue;
2269                                 }
2270                         }
2271
2272                         add_rule_key(rule, &rule->group, operation, value);
2273                         continue;
2274                 }
2275
2276                 if (strcasecmp(key, "MODE") == 0) {
2277                         add_rule_key(rule, &rule->mode, operation, value);
2278                         valid = 1;
2279                         continue;
2280                 }
2281
2282                 if (strcasecmp(key, "OPTIONS") == 0) {
2283                         const char *pos;
2284
2285                         if (strstr(value, "last_rule") != NULL) {
2286                                 dbg(rules->udev, "last rule to be applied\n");
2287                                 rule->last_rule = 1;
2288                         }
2289                         if (strstr(value, "ignore_device") != NULL) {
2290                                 dbg(rules->udev, "device should be ignored\n");
2291                                 rule->ignore_device = 1;
2292                         }
2293                         if (strstr(value, "ignore_remove") != NULL) {
2294                                 dbg(rules->udev, "remove event should be ignored\n");
2295                                 rule->ignore_remove = 1;
2296                         }
2297                         pos = strstr(value, "link_priority=");
2298                         if (pos != NULL) {
2299                                 rule->link_priority = atoi(&pos[strlen("link_priority=")]);
2300                                 dbg(rules->udev, "link priority=%i\n", rule->link_priority);
2301                         }
2302                         pos = strstr(value, "event_timeout=");
2303                         if (pos != NULL) {
2304                                 rule->event_timeout = atoi(&pos[strlen("event_timeout=")]);
2305                                 dbg(rules->udev, "event timout=%i\n", rule->event_timeout);
2306                         }
2307                         pos = strstr(value, "string_escape=");
2308                         if (pos != NULL) {
2309                                 pos = &pos[strlen("string_escape=")];
2310                                 if (strncmp(pos, "none", strlen("none")) == 0)
2311                                         rule->string_escape = ESCAPE_NONE;
2312                                 else if (strncmp(pos, "replace", strlen("replace")) == 0)
2313                                         rule->string_escape = ESCAPE_REPLACE;
2314                         }
2315                         if (strstr(value, "all_partitions") != NULL) {
2316                                 dbg(rules->udev, "creation of partition nodes requested\n");
2317                                 rule->partitions = DEFAULT_FAKE_PARTITIONS_COUNT;
2318                         }
2319                         valid = 1;
2320                         continue;
2321                 }
2322
2323                 err(rules->udev, "unknown key '%s' in %s:%u\n", key, filename, lineno);
2324         }
2325
2326         if (physdev && rule->wait_for.operation == KEY_OP_UNSET)
2327                 err(rules->udev, "PHYSDEV* values are deprecated and will be removed from a future kernel, \n"
2328                     "please fix it in %s:%u", filename, lineno);
2329
2330         /* skip line if not any valid key was found */
2331         if (!valid)
2332                 goto invalid;
2333
2334         /* grow buffer and add rule */
2335         rule_size = sizeof(struct udev_rule) + rule->bufsize;
2336         padding = (sizeof(size_t) - rule_size % sizeof(size_t)) % sizeof(size_t);
2337         dbg(rules->udev, "add %zi padding bytes\n", padding);
2338         rule_size += padding;
2339         rule->bufsize += padding;
2340
2341         rules->buf = realloc(rules->buf, rules->bufsize + rule_size);
2342         if (!rules->buf) {
2343                 err(rules->udev, "realloc failed\n");
2344                 goto exit;
2345         }
2346         dbg(rules->udev, "adding rule to offset %zi\n", rules->bufsize);
2347         memcpy(rules->buf + rules->bufsize, rule, rule_size);
2348         rules->bufsize += rule_size;
2349 exit:
2350         return 0;
2351
2352 invalid:
2353         err(rules->udev, "invalid rule '%s:%u'\n", filename, lineno);
2354         return -1;
2355 }
2356
2357 static int parse_file(struct udev_rules *rules, const char *filename)
2358 {
2359         FILE *f;
2360         char line[UTIL_LINE_SIZE];
2361         size_t start;
2362         struct udev_rule *rule;
2363         struct udev_rules_iter iter;
2364
2365         start = rules->bufsize;
2366         info(rules->udev, "reading '%s' as rules file\n", filename);
2367
2368         f = fopen(filename, "r");
2369         if (f == NULL)
2370                 return -1;
2371
2372         while(fgets(line, sizeof(line), f) != NULL) {
2373                 int line_nr = 0;
2374                 char *key;
2375                 size_t len;
2376
2377                 /* skip whitespace */
2378                 line_nr++;
2379                 key = line;
2380                 while (isspace(key[0]))
2381                         key++;
2382
2383                 /* comment */
2384                 if (key[0] == '#')
2385                         continue;
2386
2387                 len = strlen(line);
2388                 if (len < 3)
2389                         continue;
2390
2391                 /* continue reading if backslash+newline is found */
2392                 while (line[len-2] == '\\') {
2393                         if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL)
2394                                 break;
2395                         line_nr++;
2396                         len = strlen(line);
2397                 }
2398
2399                 if (len+1 >= sizeof(line)) {
2400                         err(rules->udev, "line too long '%s':%u, ignored\n", filename, line_nr);
2401                         continue;
2402                 }
2403                 add_to_rules(rules, key, filename, line_nr);
2404         }
2405         fclose(f);
2406
2407         /* compute all goto targets within this file */
2408         udev_rules_iter_init(&iter, rules);
2409         udev_rules_iter_goto(&iter, start);
2410         while((rule = udev_rules_iter_next(&iter))) {
2411                 if (rule->goto_label.operation != KEY_OP_UNSET) {
2412                         char *goto_label = &rule->buf[rule->goto_label.val_off];
2413
2414                         dbg(rules->udev, "resolving goto label '%s'\n", goto_label);
2415                         rule->goto_rule_off = find_label(&iter, goto_label);
2416                         if (rule->goto_rule_off == 0) {
2417                                 err(rules->udev, "ignore goto to nonexistent label '%s' in '%s'\n",
2418                                     goto_label, filename);
2419                                 rule->goto_rule_off = iter.current;
2420                         }
2421                 }
2422         }
2423         return 0;
2424 }
2425
2426 static int add_matching_files(struct udev *udev, struct udev_list_node *file_list, const char *dirname, const char *suffix)
2427 {
2428         struct dirent *ent;
2429         DIR *dir;
2430         char filename[UTIL_PATH_SIZE];
2431
2432         dbg(udev, "open directory '%s'\n", dirname);
2433         dir = opendir(dirname);
2434         if (dir == NULL) {
2435                 err(udev, "unable to open '%s': %m\n", dirname);
2436                 return -1;
2437         }
2438
2439         while (1) {
2440                 ent = readdir(dir);
2441                 if (ent == NULL || ent->d_name[0] == '\0')
2442                         break;
2443
2444                 if ((ent->d_name[0] == '.') || (ent->d_name[0] == '#'))
2445                         continue;
2446
2447                 /* look for file matching with specified suffix */
2448                 if (suffix != NULL) {
2449                         const char *ext;
2450
2451                         ext = strrchr(ent->d_name, '.');
2452                         if (ext == NULL)
2453                                 continue;
2454                         if (strcmp(ext, suffix) != 0)
2455                                 continue;
2456                 }
2457                 dbg(udev, "put file '%s/%s' into list\n", dirname, ent->d_name);
2458
2459                 snprintf(filename, sizeof(filename), "%s/%s", dirname, ent->d_name);
2460                 filename[sizeof(filename)-1] = '\0';
2461                 udev_list_entry_add(udev, file_list, filename, NULL, 1, 1);
2462         }
2463
2464         closedir(dir);
2465         return 0;
2466 }
2467
2468 struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
2469 {
2470         struct udev_rules *rules;
2471         struct stat statbuf;
2472         char filename[PATH_MAX];
2473         struct udev_list_node file_list;
2474         struct udev_list_entry *file_loop, *file_tmp;
2475
2476         rules = malloc(sizeof(struct udev_rules));
2477         if (rules == NULL)
2478                 return rules;
2479         memset(rules, 0x00, sizeof(struct udev_rules));
2480         rules->udev = udev;
2481         rules->resolve_names = resolve_names;
2482         udev_list_init(&file_list);
2483
2484         if (udev_get_rules_path(udev) != NULL) {
2485                 /* custom rules location for testing */
2486                 add_matching_files(udev, &file_list, udev_get_rules_path(udev), ".rules");
2487         } else {
2488                 struct udev_list_node sort_list;
2489                 struct udev_list_entry *sort_loop, *sort_tmp;
2490
2491                 /* read user/custom rules */
2492                 add_matching_files(udev, &file_list, SYSCONFDIR "/udev/rules.d", ".rules");
2493
2494                 /* read dynamic/temporary rules */
2495                 util_strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
2496                 util_strlcat(filename, "/.udev/rules.d", sizeof(filename));
2497                 if (stat(filename, &statbuf) != 0) {
2498                         create_path(udev, filename);
2499                         udev_selinux_setfscreatecon(udev, filename, S_IFDIR|0755);
2500                         mkdir(filename, 0755);
2501                         udev_selinux_resetfscreatecon(udev);
2502                 }
2503                 udev_list_init(&sort_list);
2504                 add_matching_files(udev, &sort_list, filename, ".rules");
2505
2506                 /* read default rules */
2507                 add_matching_files(udev, &sort_list, UDEV_PREFIX "/lib/udev/rules.d", ".rules");
2508
2509                 /* sort all rules files by basename into list of files */
2510                 udev_list_entry_foreach_safe(sort_loop, sort_tmp, udev_list_get_entry(&sort_list)) {
2511                         const char *sort_name = udev_list_entry_get_name(sort_loop);
2512                         const char *sort_base = strrchr(sort_name, '/');
2513
2514                         if (sort_base == NULL)
2515                                 continue;
2516
2517                         udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
2518                                 const char *file_name = udev_list_entry_get_name(file_loop);
2519                                 const char *file_base = strrchr(file_name, '/');
2520
2521                                 if (file_base == NULL)
2522                                         continue;
2523                                 if (strcmp(file_base, sort_base) == 0) {
2524                                         info(udev, "rule file basename '%s' already added, ignoring '%s'\n",
2525                                              file_name, sort_name);
2526                                         udev_list_entry_remove(sort_loop);
2527                                         sort_loop = NULL;
2528                                         break;
2529                                 }
2530                                 if (strcmp(file_base, sort_base) > 0)
2531                                         break;
2532                         }
2533                         if (sort_loop != NULL)
2534                                 udev_list_entry_move_before(sort_loop, file_loop);
2535                 }
2536         }
2537
2538         /* parse list of files */
2539         udev_list_entry_foreach_safe(file_loop, file_tmp, udev_list_get_entry(&file_list)) {
2540                 const char *file_name = udev_list_entry_get_name(file_loop);
2541
2542                 if (stat(file_name, &statbuf) == 0 && statbuf.st_size > 0)
2543                         parse_file(rules, file_name);
2544                 else
2545                         info(udev, "can not read '%s'\n", file_name);
2546                 udev_list_entry_remove(file_loop);
2547         }
2548         return rules;
2549 }
2550
2551 void udev_rules_unref(struct udev_rules *rules)
2552 {
2553         if (rules == NULL)
2554                 return;
2555         if (rules->buf) {
2556                 free(rules->buf);
2557                 rules->buf = NULL;
2558         }
2559         free(rules);
2560 }