chiark / gitweb /
update IMPORT= file/stdout property parsing
[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 #include "udev-rules.h"
37
38 extern char **environ;
39
40 /* extract possible {attr} and move str behind it */
41 static char *get_format_attribute(struct udev *udev, char **str)
42 {
43         char *pos;
44         char *attr = NULL;
45
46         if (*str[0] == '{') {
47                 pos = strchr(*str, '}');
48                 if (pos == NULL) {
49                         err(udev, "missing closing brace for format\n");
50                         return NULL;
51                 }
52                 pos[0] = '\0';
53                 attr = *str+1;
54                 *str = pos+1;
55                 dbg(udev, "attribute='%s', str='%s'\n", attr, *str);
56         }
57         return attr;
58 }
59
60 /* extract possible format length and move str behind it*/
61 static int get_format_len(struct udev *udev, char **str)
62 {
63         int num;
64         char *tail;
65
66         if (isdigit(*str[0])) {
67                 num = (int) strtoul(*str, &tail, 10);
68                 if (num > 0) {
69                         *str = tail;
70                         dbg(udev, "format length=%i\n", num);
71                         return num;
72                 } else {
73                         err(udev, "format parsing error '%s'\n", *str);
74                 }
75         }
76         return -1;
77 }
78
79 static int run_program(struct udev_device *dev, const char *command,
80                        char *result, size_t ressize, size_t *reslen)
81 {
82         struct udev *udev = udev_device_get_udev(dev);
83         int status;
84         char **envp;
85         int outpipe[2] = {-1, -1};
86         int errpipe[2] = {-1, -1};
87         pid_t pid;
88         char arg[UTIL_PATH_SIZE];
89         char program[UTIL_PATH_SIZE];
90         char *argv[(sizeof(arg) / 2) + 1];
91         int devnull;
92         int i;
93         int err = 0;
94
95         /* build argv from command */
96         util_strlcpy(arg, command, sizeof(arg));
97         i = 0;
98         if (strchr(arg, ' ') != NULL) {
99                 char *pos = arg;
100
101                 while (pos != NULL && pos[0] != '\0') {
102                         if (pos[0] == '\'') {
103                                 /* do not separate quotes */
104                                 pos++;
105                                 argv[i] = strsep(&pos, "\'");
106                                 while (pos != NULL && pos[0] == ' ')
107                                         pos++;
108                         } else {
109                                 argv[i] = strsep(&pos, " ");
110                         }
111                         dbg(udev, "arg[%i] '%s'\n", i, argv[i]);
112                         i++;
113                 }
114                 argv[i] = NULL;
115         } else {
116                 argv[0] = arg;
117                 argv[1] = NULL;
118         }
119         info(udev, "'%s'\n", command);
120
121         /* prepare pipes from child to parent */
122         if (result != NULL || udev_get_log_priority(udev) >= LOG_INFO) {
123                 if (pipe(outpipe) != 0) {
124                         err(udev, "pipe failed: %m\n");
125                         return -1;
126                 }
127         }
128         if (udev_get_log_priority(udev) >= LOG_INFO) {
129                 if (pipe(errpipe) != 0) {
130                         err(udev, "pipe failed: %m\n");
131                         return -1;
132                 }
133         }
134
135         /* allow programs in /lib/udev/ to be called without the path */
136         if (strchr(argv[0], '/') == NULL) {
137                 util_strlcpy(program, UDEV_PREFIX "/lib/udev/", sizeof(program));
138                 util_strlcat(program, argv[0], sizeof(program));
139                 argv[0] = program;
140         }
141
142         envp = udev_device_get_properties_envp(dev);
143
144         pid = fork();
145         switch(pid) {
146         case 0:
147                 /* child closes parent ends of pipes */
148                 if (outpipe[READ_END] > 0)
149                         close(outpipe[READ_END]);
150                 if (errpipe[READ_END] > 0)
151                         close(errpipe[READ_END]);
152
153                 /* discard child output or connect to pipe */
154                 devnull = open("/dev/null", O_RDWR);
155                 if (devnull > 0) {
156                         dup2(devnull, STDIN_FILENO);
157                         if (outpipe[WRITE_END] < 0)
158                                 dup2(devnull, STDOUT_FILENO);
159                         if (errpipe[WRITE_END] < 0)
160                                 dup2(devnull, STDERR_FILENO);
161                         close(devnull);
162                 } else
163                         err(udev, "open /dev/null failed: %m\n");
164                 if (outpipe[WRITE_END] > 0) {
165                         dup2(outpipe[WRITE_END], STDOUT_FILENO);
166                         close(outpipe[WRITE_END]);
167                 }
168                 if (errpipe[WRITE_END] > 0) {
169                         dup2(errpipe[WRITE_END], STDERR_FILENO);
170                         close(errpipe[WRITE_END]);
171                 }
172                 execve(argv[0], argv, envp);
173                 if (errno == ENOENT || errno == ENOTDIR) {
174                         /* may be on a filesytem which is not mounted right now */
175                         info(udev, "program '%s' not found\n", argv[0]);
176                 } else {
177                         /* other problems */
178                         err(udev, "exec of program '%s' failed\n", argv[0]);
179                 }
180                 _exit(1);
181         case -1:
182                 err(udev, "fork of '%s' failed: %m\n", argv[0]);
183                 return -1;
184         default:
185                 /* read from child if requested */
186                 if (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
187                         ssize_t count;
188                         size_t respos = 0;
189
190                         /* parent closes child ends of pipes */
191                         if (outpipe[WRITE_END] > 0)
192                                 close(outpipe[WRITE_END]);
193                         if (errpipe[WRITE_END] > 0)
194                                 close(errpipe[WRITE_END]);
195
196                         /* read child output */
197                         while (outpipe[READ_END] > 0 || errpipe[READ_END] > 0) {
198                                 int fdcount;
199                                 fd_set readfds;
200
201                                 FD_ZERO(&readfds);
202                                 if (outpipe[READ_END] > 0)
203                                         FD_SET(outpipe[READ_END], &readfds);
204                                 if (errpipe[READ_END] > 0)
205                                         FD_SET(errpipe[READ_END], &readfds);
206                                 fdcount = select(UDEV_MAX(outpipe[READ_END], errpipe[READ_END])+1, &readfds, NULL, NULL, NULL);
207                                 if (fdcount < 0) {
208                                         if (errno == EINTR)
209                                                 continue;
210                                         err = -1;
211                                         break;
212                                 }
213
214                                 /* get stdout */
215                                 if (outpipe[READ_END] > 0 && FD_ISSET(outpipe[READ_END], &readfds)) {
216                                         char inbuf[1024];
217                                         char *pos;
218                                         char *line;
219
220                                         count = read(outpipe[READ_END], inbuf, sizeof(inbuf)-1);
221                                         if (count <= 0) {
222                                                 close(outpipe[READ_END]);
223                                                 outpipe[READ_END] = -1;
224                                                 if (count < 0) {
225                                                         err(udev, "stdin read failed: %m\n");
226                                                         err = -1;
227                                                 }
228                                                 continue;
229                                         }
230                                         inbuf[count] = '\0';
231
232                                         /* store result for rule processing */
233                                         if (result) {
234                                                 if (respos + count < ressize) {
235                                                         memcpy(&result[respos], inbuf, count);
236                                                         respos += count;
237                                                 } else {
238                                                         err(udev, "ressize %ld too short\n", (long)ressize);
239                                                         err = -1;
240                                                 }
241                                         }
242                                         pos = inbuf;
243                                         while ((line = strsep(&pos, "\n")))
244                                                 if (pos || line[0] != '\0')
245                                                         info(udev, "'%s' (stdout) '%s'\n", argv[0], line);
246                                 }
247
248                                 /* get stderr */
249                                 if (errpipe[READ_END] > 0 && FD_ISSET(errpipe[READ_END], &readfds)) {
250                                         char errbuf[1024];
251                                         char *pos;
252                                         char *line;
253
254                                         count = read(errpipe[READ_END], errbuf, sizeof(errbuf)-1);
255                                         if (count <= 0) {
256                                                 close(errpipe[READ_END]);
257                                                 errpipe[READ_END] = -1;
258                                                 if (count < 0)
259                                                         err(udev, "stderr read failed: %m\n");
260                                                 continue;
261                                         }
262                                         errbuf[count] = '\0';
263                                         pos = errbuf;
264                                         while ((line = strsep(&pos, "\n")))
265                                                 if (pos || line[0] != '\0')
266                                                         info(udev, "'%s' (stderr) '%s'\n", argv[0], line);
267                                 }
268                         }
269                         if (outpipe[READ_END] > 0)
270                                 close(outpipe[READ_END]);
271                         if (errpipe[READ_END] > 0)
272                                 close(errpipe[READ_END]);
273
274                         /* return the childs stdout string */
275                         if (result) {
276                                 result[respos] = '\0';
277                                 dbg(udev, "result='%s'\n", result);
278                                 if (reslen)
279                                         *reslen = respos;
280                         }
281                 }
282                 waitpid(pid, &status, 0);
283                 if (WIFEXITED(status)) {
284                         info(udev, "'%s' returned with status %i\n", argv[0], WEXITSTATUS(status));
285                         if (WEXITSTATUS(status) != 0)
286                                 err = -1;
287                 } else {
288                         err(udev, "'%s' abnormal exit\n", argv[0]);
289                         err = -1;
290                 }
291         }
292
293         return err;
294 }
295
296 static int import_property_from_string(struct udev_device *dev, char *line)
297 {
298         struct udev *udev = udev_device_get_udev(dev);
299         char *key;
300         char *val;
301         size_t len;
302
303         /* find key */
304         key = line;
305         while (isspace(key[0]))
306                 key++;
307
308         /* comment or empty line */
309         if (key[0] == '#' || key[0] == '\0')
310                 return -1;
311
312         /* split key/value */
313         val = strchr(key, '=');
314         if (val == NULL)
315                 return -1;
316         val[0] = '\0';
317         val++;
318
319         /* find value */
320         while (isspace(val[0]))
321                 val++;
322
323         /* terminate key */
324         len = strlen(key);
325         if (len == 0)
326                 return -1;
327         while (isspace(key[len-1]))
328                 len--;
329         key[len] = '\0';
330
331         /* terminate value */
332         len = strlen(val);
333         if (len == 0)
334                 return -1;
335         while (isspace(val[len-1]))
336                 len--;
337         val[len] = '\0';
338
339         if (len == 0)
340                 return -1;
341
342         /* unquote */
343         if (val[0] == '"' || val[0] == '\'') {
344                 if (val[len-1] != val[0]) {
345                         info(udev, "inconsistent quoting: '%s', skip\n", line);
346                         return -1;
347                 }
348                 val[len-1] = '\0';
349                 val++;
350         }
351
352         info(udev, "adding '%s'='%s'\n", key, val);
353
354         /* handle device, renamed by external tool, returning new path */
355         if (strcmp(key, "DEVPATH") == 0) {
356                 char syspath[UTIL_PATH_SIZE];
357
358                 info(udev, "updating devpath from '%s' to '%s'\n",
359                      udev_device_get_devpath(dev), val);
360                 util_strlcpy(syspath, udev_get_sys_path(udev), sizeof(syspath));
361                 util_strlcat(syspath, val, sizeof(syspath));
362                 udev_device_set_syspath(dev, syspath);
363         } else {
364                 struct udev_list_entry *entry;
365
366                 entry = udev_device_add_property(dev, key, val);
367                 /* store in db */
368                 udev_list_entry_set_flag(entry, 1);
369         }
370         return 0;
371 }
372
373 static int import_file_into_env(struct udev_device *dev, const char *filename)
374 {
375         FILE *f;
376         char line[UTIL_LINE_SIZE];
377
378         f = fopen(filename, "r");
379         if (f == NULL)
380                 return -1;
381         while (fgets(line, sizeof(line), f))
382                 import_property_from_string(dev, line);
383         fclose(f);
384         return 0;
385 }
386
387 static int import_program_into_env(struct udev_device *dev, const char *program)
388 {
389         char result[2048];
390         size_t reslen;
391         char *line;
392
393         if (run_program(dev, program, result, sizeof(result), &reslen) != 0)
394                 return -1;
395
396         line = result;
397         while (line != NULL) {
398                 char *pos;
399
400                 pos = strchr(line, '\n');
401                 if (pos != NULL) {
402                         pos[0] = '\0';
403                         pos = &pos[1];
404                 }
405                 import_property_from_string(dev, line);
406                 line = pos;
407         }
408         return 0;
409 }
410
411 static int import_parent_into_env(struct udev_device *dev, const char *filter)
412 {
413         struct udev *udev = udev_device_get_udev(dev);
414         struct udev_device *dev_parent;
415         struct udev_list_entry *list_entry;
416
417         dev_parent = udev_device_get_parent(dev);
418         if (dev_parent == NULL)
419                 return -1;
420
421         dbg(udev, "found parent '%s', get the node name\n", udev_device_get_syspath(dev_parent));
422         udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(dev_parent)) {
423                 const char *key = udev_list_entry_get_name(list_entry);
424                 const char *val = udev_list_entry_get_value(list_entry);
425
426                 if (fnmatch(filter, key, 0) == 0) {
427                         struct udev_list_entry *entry;
428
429                         dbg(udev, "import key '%s=%s'\n", key, val);
430                         entry = udev_device_add_property(dev, key, val);
431                         /* store in db */
432                         udev_list_entry_set_flag(entry, 1);
433                 }
434         }
435         return 0;
436 }
437
438 int udev_rules_run(struct udev_event *event)
439 {
440         struct udev_list_entry *list_entry;
441         int err = 0;
442
443         dbg(event->udev, "executing run list\n");
444         udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
445                 const char *cmd = udev_list_entry_get_name(list_entry);
446
447                 if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
448                         struct udev_monitor *monitor;
449
450                         monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
451                         if (monitor == NULL)
452                                 continue;
453                         udev_monitor_send_device(monitor, event->dev);
454                         udev_monitor_unref(monitor);
455                 } else {
456                         char program[UTIL_PATH_SIZE];
457
458                         util_strlcpy(program, cmd, sizeof(program));
459                         udev_rules_apply_format(event, program, sizeof(program));
460                         if (run_program(event->dev, program, NULL, 0, NULL) != 0) {
461                                 if (!udev_list_entry_get_flag(list_entry))
462                                         err = -1;
463                         }
464                 }
465         }
466         return err;
467 }
468
469 #define WAIT_LOOP_PER_SECOND            50
470 static int wait_for_file(struct udev_event *event, const char *file, int timeout)
471 {
472         char filepath[UTIL_PATH_SIZE];
473         char devicepath[UTIL_PATH_SIZE] = "";
474         struct stat stats;
475         int loop = timeout * WAIT_LOOP_PER_SECOND;
476
477         /* a relative path is a device attribute */
478         if (file[0] != '/') {
479                 util_strlcpy(devicepath, udev_get_sys_path(event->udev), sizeof(devicepath));
480                 util_strlcat(devicepath, udev_device_get_devpath(event->dev), sizeof(devicepath));
481
482                 util_strlcpy(filepath, devicepath, sizeof(filepath));
483                 util_strlcat(filepath, "/", sizeof(filepath));
484                 util_strlcat(filepath, file, sizeof(filepath));
485                 file = filepath;
486         }
487
488         dbg(event->udev, "will wait %i sec for '%s'\n", timeout, file);
489         while (--loop) {
490                 /* lookup file */
491                 if (stat(file, &stats) == 0) {
492                         info(event->udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
493                         return 0;
494                 }
495                 /* make sure, the device did not disappear in the meantime */
496                 if (devicepath[0] != '\0' && stat(devicepath, &stats) != 0) {
497                         info(event->udev, "device disappeared while waiting for '%s'\n", file);
498                         return -2;
499                 }
500                 info(event->udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
501                 usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
502         }
503         info(event->udev, "waiting for '%s' failed\n", file);
504         return -1;
505 }
506
507 /* handle "[$SUBSYSTEM/$KERNEL]<attribute>" lookup */
508 static int split_subsys_sysname(struct udev *udev, char *attrstr, char **subsys, char **sysname, char **attr)
509 {
510         char *pos;
511
512         if (attrstr[0] != '[')
513                 return -1;
514
515         *subsys = &attrstr[1];
516         pos = strchr(*subsys, ']');
517         if (pos == NULL)
518                 return -1;
519         pos[0] = '\0';
520         pos = &pos[1];
521
522         if (pos[0] == '/')
523                 pos = &pos[1];
524         if (pos[0] != '\0')
525                 *attr = pos;
526         else
527                 *attr = NULL;
528
529         pos = strchr(*subsys, '/');
530         if (pos == NULL)
531                 return -1;
532         pos[0] = '\0';
533         *sysname = &pos[1];
534         return 0;
535 }
536
537 static int attr_subst_subdir(char *attr, size_t len)
538 {
539         char *pos;
540         int found = 0;
541
542         pos = strstr(attr, "/*/");
543         if (pos != NULL) {
544                 char str[UTIL_PATH_SIZE];
545                 DIR *dir;
546
547                 pos[1] = '\0';
548                 util_strlcpy(str, &pos[2], sizeof(str));
549                 dir = opendir(attr);
550                 if (dir != NULL) {
551                         struct dirent *dent;
552
553                         for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
554                                 struct stat stats;
555
556                                 if (dent->d_name[0] == '.')
557                                         continue;
558                                 util_strlcat(attr, dent->d_name, len);
559                                 util_strlcat(attr, str, len);
560                                 if (stat(attr, &stats) == 0) {
561                                         found = 1;
562                                         break;
563                                 }
564                                 pos[1] = '\0';
565                         }
566                         closedir(dir);
567                 }
568                 if (!found)
569                         util_strlcat(attr, str, len);
570         }
571
572         return found;
573 }
574
575 void udev_rules_apply_format(struct udev_event *event, char *string, size_t maxsize)
576 {
577         struct udev_device *dev = event->dev;
578         char temp[UTIL_PATH_SIZE];
579         char temp2[UTIL_PATH_SIZE];
580         char *head, *tail, *cpos, *attr, *rest;
581         int len;
582         int i;
583         int count;
584         enum subst_type {
585                 SUBST_UNKNOWN,
586                 SUBST_DEVPATH,
587                 SUBST_KERNEL,
588                 SUBST_KERNEL_NUMBER,
589                 SUBST_ID,
590                 SUBST_DRIVER,
591                 SUBST_MAJOR,
592                 SUBST_MINOR,
593                 SUBST_RESULT,
594                 SUBST_ATTR,
595                 SUBST_PARENT,
596                 SUBST_TEMP_NODE,
597                 SUBST_NAME,
598                 SUBST_LINKS,
599                 SUBST_ROOT,
600                 SUBST_SYS,
601                 SUBST_ENV,
602         };
603         static const struct subst_map {
604                 char *name;
605                 char fmt;
606                 enum subst_type type;
607         } map[] = {
608                 { .name = "devpath",    .fmt = 'p',     .type = SUBST_DEVPATH },
609                 { .name = "number",     .fmt = 'n',     .type = SUBST_KERNEL_NUMBER },
610                 { .name = "kernel",     .fmt = 'k',     .type = SUBST_KERNEL },
611                 { .name = "id",         .fmt = 'b',     .type = SUBST_ID },
612                 { .name = "driver",     .fmt = 'd',     .type = SUBST_DRIVER },
613                 { .name = "major",      .fmt = 'M',     .type = SUBST_MAJOR },
614                 { .name = "minor",      .fmt = 'm',     .type = SUBST_MINOR },
615                 { .name = "result",     .fmt = 'c',     .type = SUBST_RESULT },
616                 { .name = "attr",       .fmt = 's',     .type = SUBST_ATTR },
617                 { .name = "sysfs",      .fmt = 's',     .type = SUBST_ATTR },
618                 { .name = "parent",     .fmt = 'P',     .type = SUBST_PARENT },
619                 { .name = "tempnode",   .fmt = 'N',     .type = SUBST_TEMP_NODE },
620                 { .name = "name",       .fmt = 'D',     .type = SUBST_NAME },
621                 { .name = "links",      .fmt = 'L',     .type = SUBST_LINKS },
622                 { .name = "root",       .fmt = 'r',     .type = SUBST_ROOT },
623                 { .name = "sys",        .fmt = 'S',     .type = SUBST_SYS },
624                 { .name = "env",        .fmt = 'E',     .type = SUBST_ENV },
625                 { NULL, '\0', 0 }
626         };
627         enum subst_type type;
628         const struct subst_map *subst;
629
630         head = string;
631         while (1) {
632                 len = -1;
633                 while (head[0] != '\0') {
634                         if (head[0] == '$') {
635                                 /* substitute named variable */
636                                 if (head[1] == '\0')
637                                         break;
638                                 if (head[1] == '$') {
639                                         util_strlcpy(temp, head+2, sizeof(temp));
640                                         util_strlcpy(head+1, temp, maxsize);
641                                         head++;
642                                         continue;
643                                 }
644                                 head[0] = '\0';
645                                 for (subst = map; subst->name; subst++) {
646                                         if (strncasecmp(&head[1], subst->name, strlen(subst->name)) == 0) {
647                                                 type = subst->type;
648                                                 tail = head + strlen(subst->name)+1;
649                                                 dbg(event->udev, "will substitute format name '%s'\n", subst->name);
650                                                 goto found;
651                                         }
652                                 }
653                                 head[0] = '$';
654                                 err(event->udev, "unknown format variable '%s'\n", head);
655                         } else if (head[0] == '%') {
656                                 /* substitute format char */
657                                 if (head[1] == '\0')
658                                         break;
659                                 if (head[1] == '%') {
660                                         util_strlcpy(temp, head+2, sizeof(temp));
661                                         util_strlcpy(head+1, temp, maxsize);
662                                         head++;
663                                         continue;
664                                 }
665                                 head[0] = '\0';
666                                 tail = head+1;
667                                 len = get_format_len(event->udev, &tail);
668                                 for (subst = map; subst->name; subst++) {
669                                         if (tail[0] == subst->fmt) {
670                                                 type = subst->type;
671                                                 tail++;
672                                                 dbg(event->udev, "will substitute format char '%c'\n", subst->fmt);
673                                                 goto found;
674                                         }
675                                 }
676                                 head[0] = '%';
677                                 err(event->udev, "unknown format char '%c'\n", tail[0]);
678                         }
679                         head++;
680                 }
681                 break;
682 found:
683                 attr = get_format_attribute(event->udev, &tail);
684                 util_strlcpy(temp, tail, sizeof(temp));
685                 dbg(event->udev, "format=%i, string='%s', tail='%s'\n", type ,string, tail);
686
687                 switch (type) {
688                 case SUBST_DEVPATH:
689                         util_strlcat(string, udev_device_get_devpath(dev), maxsize);
690                         dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev));
691                         break;
692                 case SUBST_KERNEL:
693                         util_strlcat(string, udev_device_get_sysname(dev), maxsize);
694                         dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev));
695                         break;
696                 case SUBST_KERNEL_NUMBER:
697                         if (udev_device_get_sysnum(dev) == NULL)
698                                 break;
699                         util_strlcat(string, udev_device_get_sysnum(dev), maxsize);
700                         dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev));
701                         break;
702                 case SUBST_ID:
703                         if (event->dev_parent != NULL) {
704                                 util_strlcat(string, udev_device_get_sysname(event->dev_parent), maxsize);
705                                 dbg(event->udev, "substitute id '%s'\n", udev_device_get_sysname(event->dev_parent));
706                         }
707                         break;
708                 case SUBST_DRIVER:
709                         if (event->dev_parent != NULL) {
710                                 const char *driver = udev_device_get_driver(event->dev_parent);
711
712                                 if (driver == NULL)
713                                         break;
714                                 util_strlcat(string, driver, maxsize);
715                                 dbg(event->udev, "substitute driver '%s'\n", driver);
716                         }
717                         break;
718                 case SUBST_MAJOR:
719                         sprintf(temp2, "%d", major(udev_device_get_devnum(dev)));
720                         util_strlcat(string, temp2, maxsize);
721                         dbg(event->udev, "substitute major number '%s'\n", temp2);
722                         break;
723                 case SUBST_MINOR:
724                         sprintf(temp2, "%d", minor(udev_device_get_devnum(dev)));
725                         util_strlcat(string, temp2, maxsize);
726                         dbg(event->udev, "substitute minor number '%s'\n", temp2);
727                         break;
728                 case SUBST_RESULT:
729                         if (event->program_result[0] == '\0')
730                                 break;
731                         /* get part part of the result string */
732                         i = 0;
733                         if (attr != NULL)
734                                 i = strtoul(attr, &rest, 10);
735                         if (i > 0) {
736                                 dbg(event->udev, "request part #%d of result string\n", i);
737                                 cpos = event->program_result;
738                                 while (--i) {
739                                         while (cpos[0] != '\0' && !isspace(cpos[0]))
740                                                 cpos++;
741                                         while (isspace(cpos[0]))
742                                                 cpos++;
743                                 }
744                                 if (i > 0) {
745                                         err(event->udev, "requested part of result string not found\n");
746                                         break;
747                                 }
748                                 util_strlcpy(temp2, cpos, sizeof(temp2));
749                                 /* %{2+}c copies the whole string from the second part on */
750                                 if (rest[0] != '+') {
751                                         cpos = strchr(temp2, ' ');
752                                         if (cpos)
753                                                 cpos[0] = '\0';
754                                 }
755                                 util_strlcat(string, temp2, maxsize);
756                                 dbg(event->udev, "substitute part of result string '%s'\n", temp2);
757                         } else {
758                                 util_strlcat(string, event->program_result, maxsize);
759                                 dbg(event->udev, "substitute result string '%s'\n", event->program_result);
760                         }
761                         break;
762                 case SUBST_ATTR:
763                         if (attr == NULL)
764                                 err(event->udev, "missing file parameter for attr\n");
765                         else {
766                                 char *subsys;
767                                 char *sysname;
768                                 char *attrib;
769                                 char value[UTIL_NAME_SIZE] = "";
770                                 size_t size;
771
772                                 if (split_subsys_sysname(event->udev, attr, &subsys, &sysname, &attrib) == 0) {
773                                         struct udev_device *d;
774                                         const char *val;
775
776                                         if (attrib == NULL)
777                                                 break;
778                                         d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
779                                         if (d == NULL)
780                                                 break;
781                                         val = udev_device_get_attr_value(d, attrib);
782                                         if (val != NULL)
783                                                 util_strlcpy(value, val, sizeof(value));
784                                         udev_device_unref(d);
785                                 }
786
787                                 /* try the current device, other matches may have selected */
788                                 if (value[0]=='\0' && event->dev_parent != NULL && event->dev_parent != event->dev) {
789                                         const char *val;
790
791                                         val = udev_device_get_attr_value(event->dev_parent, attr);
792                                         if (val != NULL)
793                                                 util_strlcpy(value, val, sizeof(value));
794                                 }
795
796                                 /* look at all devices along the chain of parents */
797                                 if (value[0]=='\0') {
798                                         struct udev_device *dev_parent = dev;
799                                         const char *val;
800
801                                         do {
802                                                 dbg(event->udev, "looking at '%s'\n", udev_device_get_syspath(dev_parent));
803                                                 val = udev_device_get_attr_value(dev_parent, attr);
804                                                 if (val != NULL) {
805                                                         util_strlcpy(value, val, sizeof(value));
806                                                         break;
807                                                 }
808                                                 dev_parent = udev_device_get_parent(dev_parent);
809                                         } while (dev_parent != NULL);
810                                 }
811
812                                 if (value[0]=='\0')
813                                         break;
814
815                                 /* strip trailing whitespace, and replace unwanted characters */
816                                 size = strlen(value);
817                                 while (size > 0 && isspace(value[--size]))
818                                         value[size] = '\0';
819                                 count = util_replace_chars(value, ALLOWED_CHARS_INPUT);
820                                 if (count > 0)
821                                         info(event->udev, "%i character(s) replaced\n" , count);
822                                 util_strlcat(string, value, maxsize);
823                                 dbg(event->udev, "substitute sysfs value '%s'\n", value);
824                         }
825                         break;
826                 case SUBST_PARENT:
827                         {
828                                 struct udev_device *dev_parent;
829                                 const char *devnode;
830
831                                 dev_parent = udev_device_get_parent(event->dev);
832                                 if (dev_parent == NULL)
833                                         break;
834                                 devnode = udev_device_get_devnode(dev_parent);
835                                 if (devnode != NULL) {
836                                         size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
837
838                                         util_strlcat(string, &devnode[devlen], maxsize);
839                                         dbg(event->udev, "found parent '%s', got node name '%s'\n",
840                                             udev_device_get_syspath(dev_parent), &devnode[devlen]);
841                                 }
842                         }
843                         break;
844                 case SUBST_TEMP_NODE:
845                         if (event->tmp_node[0] == '\0' && major(udev_device_get_devnum(dev)) > 0) {
846                                 dbg(event->udev, "create temporary device node for callout\n");
847                                 snprintf(event->tmp_node, sizeof(event->tmp_node), "%s/.tmp-%u-%u",
848                                          udev_get_dev_path(event->udev),
849                                          major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)));
850                                 udev_node_mknod(dev, event->tmp_node, makedev(0,0), 0600, 0, 0);
851                         }
852                         util_strlcat(string, event->tmp_node, maxsize);
853                         dbg(event->udev, "substitute temporary device node name '%s'\n", event->tmp_node);
854                         break;
855                 case SUBST_NAME:
856                         if (event->name != NULL) {
857                                 util_strlcat(string, event->name, maxsize);
858                                 dbg(event->udev, "substitute name '%s'\n", event->name);
859                         } else {
860                                 util_strlcat(string, udev_device_get_sysname(dev), maxsize);
861                                 dbg(event->udev, "substitute sysname '%s'\n", udev_device_get_sysname(dev));
862                         }
863                         break;
864                 case SUBST_LINKS:
865                         {
866                                 struct udev_list_entry *list_entry;
867
868                                 list_entry = udev_device_get_properties_list_entry(dev);
869                                 util_strlcpy(string, udev_list_entry_get_name(list_entry), maxsize);
870                                 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry)) {
871                                         util_strlcat(string, " ", maxsize);
872                                         util_strlcat(string, udev_list_entry_get_name(list_entry), maxsize);
873                                 }
874                         }
875                         break;
876                 case SUBST_ROOT:
877                         util_strlcat(string, udev_get_dev_path(event->udev), maxsize);
878                         dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev));
879                         break;
880                 case SUBST_SYS:
881                         util_strlcat(string, udev_get_sys_path(event->udev), maxsize);
882                         dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev));
883                         break;
884                 case SUBST_ENV:
885                         if (attr == NULL) {
886                                 dbg(event->udev, "missing attribute\n");
887                                 break;
888                         } else {
889                                 struct udev_list_entry *list_entry;
890                                 const char *value;
891
892                                 list_entry = udev_device_get_properties_list_entry(event->dev);
893                                 list_entry = udev_list_entry_get_by_name(list_entry, attr);
894                                 if (list_entry == NULL)
895                                         break;
896                                 value = udev_list_entry_get_value(list_entry);
897                                 dbg(event->udev, "substitute env '%s=%s'\n", attr, value);
898                                 util_strlcat(string, value, maxsize);
899                                 break;
900                         }
901                 default:
902                         err(event->udev, "unknown substitution type=%i\n", type);
903                         break;
904                 }
905                 /* possibly truncate to format-char specified length */
906                 if (len >= 0 && len < (int)strlen(head)) {
907                         head[len] = '\0';
908                         dbg(event->udev, "truncate to %i chars, subtitution string becomes '%s'\n", len, head);
909                 }
910                 util_strlcat(string, temp, maxsize);
911         }
912 }
913
914 static char *key_val(struct udev_rule *rule, struct key *key)
915 {
916         return rule->buf + key->val_off;
917 }
918
919 static char *key_pair_name(struct udev_rule *rule, struct key_pair *pair)
920 {
921         return rule->buf + pair->key_name_off;
922 }
923
924 static int match_key(struct udev *udev, const char *key_name, struct udev_rule *rule, struct key *key, const char *val)
925 {
926         char value[UTIL_PATH_SIZE];
927         char *key_value;
928         char *pos;
929         int match = 0;
930
931         if (key->operation != KEY_OP_MATCH &&
932             key->operation != KEY_OP_NOMATCH)
933                 return 0;
934
935         if (val == NULL)
936                 val = "";
937
938         /* look for a matching string, parts are separated by '|' */
939         util_strlcpy(value, rule->buf + key->val_off, sizeof(value));
940         key_value = value;
941         dbg(udev, "key %s value='%s'\n", key_name, key_value);
942         while (key_value != NULL) {
943                 pos = strchr(key_value, '|');
944                 if (pos != NULL) {
945                         pos[0] = '\0';
946                         pos = &pos[1];
947                 }
948
949                 dbg(udev, "match %s '%s' <-> '%s'\n", key_name, key_value, val);
950                 match = (fnmatch(key_value, val, 0) == 0);
951                 if (match)
952                         break;
953
954                 key_value = pos;
955         }
956
957         if (match && (key->operation == KEY_OP_MATCH)) {
958                 dbg(udev, "%s is true (matching value)\n", key_name);
959                 return 0;
960         }
961         if (!match && (key->operation == KEY_OP_NOMATCH)) {
962                 dbg(udev, "%s is true (non-matching value)\n", key_name);
963                 return 0;
964         }
965         return -1;
966 }
967
968 /* match a single rule against a given device and possibly its parent devices */
969 static int match_rule(struct udev_event *event, struct udev_rule *rule)
970 {
971         struct udev_device *dev = event->dev;
972         int i;
973
974         if (match_key(event->udev, "ACTION", rule, &rule->action, udev_device_get_action(dev)))
975                 goto nomatch;
976
977         if (match_key(event->udev, "KERNEL", rule, &rule->kernel, udev_device_get_sysname(dev)))
978                 goto nomatch;
979
980         if (match_key(event->udev, "SUBSYSTEM", rule, &rule->subsystem, udev_device_get_subsystem(dev)))
981                 goto nomatch;
982
983         if (match_key(event->udev, "DEVPATH", rule, &rule->devpath, udev_device_get_devpath(dev)))
984                 goto nomatch;
985
986         if (match_key(event->udev, "DRIVER", rule, &rule->driver, udev_device_get_driver(dev)))
987                 goto nomatch;
988
989         /* match NAME against a value assigned by an earlier rule */
990         if (match_key(event->udev, "NAME", rule, &rule->name, event->name))
991                 goto nomatch;
992
993         /* match against current list of symlinks */
994         if (rule->symlink_match.operation == KEY_OP_MATCH ||
995             rule->symlink_match.operation == KEY_OP_NOMATCH) {
996                 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
997                 struct udev_list_entry *list_entry;
998                 int match = 0;
999
1000                 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
1001                         const char *devlink;
1002
1003                         devlink =  &udev_list_entry_get_name(list_entry)[devlen];
1004                         if (match_key(event->udev, "SYMLINK", rule, &rule->symlink_match, devlink) == 0) {
1005                                 match = 1;
1006                                 break;
1007                         }
1008                 }
1009                 if (!match)
1010                         goto nomatch;
1011         }
1012
1013         for (i = 0; i < rule->env.count; i++) {
1014                 struct key_pair *pair = &rule->env.keys[i];
1015
1016                 /* we only check for matches, assignments will be handled later */
1017                 if (pair->key.operation == KEY_OP_MATCH ||
1018                     pair->key.operation == KEY_OP_NOMATCH) {
1019                         struct udev_list_entry *list_entry;
1020                         const char *key_name = key_pair_name(rule, pair);
1021                         const char *value;
1022
1023                         list_entry = udev_device_get_properties_list_entry(event->dev);
1024                         list_entry = udev_list_entry_get_by_name(list_entry, key_name);
1025                         value = udev_list_entry_get_value(list_entry);
1026                         if (value == NULL) {
1027                                 dbg(event->udev, "ENV{%s} is not set, treat as empty\n", key_name);
1028                                 value = "";
1029                         }
1030                         if (match_key(event->udev, "ENV", rule, &pair->key, value))
1031                                 goto nomatch;
1032                 }
1033         }
1034
1035         if (rule->test.operation == KEY_OP_MATCH ||
1036             rule->test.operation == KEY_OP_NOMATCH) {
1037                 char filename[UTIL_PATH_SIZE];
1038                 char *subsys;
1039                 char *sysname;
1040                 char *attrib;
1041                 struct stat statbuf;
1042                 int match;
1043
1044                 util_strlcpy(filename, key_val(rule, &rule->test), sizeof(filename));
1045                 udev_rules_apply_format(event, filename, sizeof(filename));
1046
1047                 if (split_subsys_sysname(event->udev, filename, &subsys, &sysname, &attrib) == 0) {
1048                         struct udev_device *d;
1049                         d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
1050                         if (d != NULL) {
1051                                 util_strlcpy(filename, udev_device_get_syspath(d), sizeof(filename));
1052                                 if (attrib != NULL) {
1053                                         util_strlcat(filename, "/", sizeof(filename));
1054                                         util_strlcat(filename, attrib, sizeof(filename));
1055                                 }
1056                                 udev_device_unref(d);
1057                         }
1058                 } else if (filename[0] != '/') {
1059                         char tmp[UTIL_PATH_SIZE];
1060
1061                         util_strlcpy(tmp, udev_device_get_syspath(dev), sizeof(tmp));
1062                         util_strlcat(tmp, "/", sizeof(tmp));
1063                         util_strlcat(tmp, filename, sizeof(tmp));
1064                         util_strlcpy(filename, tmp, sizeof(filename));
1065                 }
1066
1067                 attr_subst_subdir(filename, sizeof(filename));
1068
1069                 match = (stat(filename, &statbuf) == 0);
1070                 info(event->udev, "'%s' %s", filename, match ? "exists\n" : "does not exist\n");
1071                 if (match && rule->test_mode_mask > 0) {
1072                         match = ((statbuf.st_mode & rule->test_mode_mask) > 0);
1073                         info(event->udev, "'%s' has mode=%#o and %s %#o\n", filename, statbuf.st_mode,
1074                              match ? "matches" : "does not match",
1075                              rule->test_mode_mask);
1076                 }
1077                 if (match && rule->test.operation == KEY_OP_NOMATCH)
1078                         goto nomatch;
1079                 if (!match && rule->test.operation == KEY_OP_MATCH)
1080                         goto nomatch;
1081                 dbg(event->udev, "TEST key is true\n");
1082         }
1083
1084         if (rule->wait_for.operation != KEY_OP_UNSET) {
1085                 char filename[UTIL_PATH_SIZE];
1086                 int found;
1087
1088                 util_strlcpy(filename, key_val(rule, &rule->wait_for), sizeof(filename));
1089                 udev_rules_apply_format(event, filename, sizeof(filename));
1090                 found = (wait_for_file(event, filename, 10) == 0);
1091                 if (!found && (rule->wait_for.operation != KEY_OP_NOMATCH))
1092                         goto nomatch;
1093         }
1094
1095         /* check for matching sysfs attribute pairs */
1096         for (i = 0; i < rule->attr.count; i++) {
1097                 struct key_pair *pair = &rule->attr.keys[i];
1098
1099                 if (pair->key.operation == KEY_OP_MATCH ||
1100                     pair->key.operation == KEY_OP_NOMATCH) {
1101                         char attr[UTIL_PATH_SIZE];
1102                         const char *key_name = key_pair_name(rule, pair);
1103                         const char *key_value = key_val(rule, &pair->key);
1104                         char *subsys;
1105                         char *sysname;
1106                         char *attrib;
1107                         char value[UTIL_NAME_SIZE] = "";
1108                         size_t len;
1109
1110                         util_strlcpy(attr, key_name, sizeof(attr));
1111                         if (split_subsys_sysname(event->udev, attr, &subsys, &sysname, &attrib) == 0) {
1112                                 struct udev_device *d;
1113                                 const char *val;
1114
1115                                 if (attrib == NULL)
1116                                         goto nomatch;
1117                                 d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
1118                                 if (d == NULL)
1119                                         goto nomatch;
1120                                 val = udev_device_get_attr_value(d, attrib);
1121                                 if (val != NULL)
1122                                         util_strlcpy(value, val, sizeof(value));
1123                                 udev_device_unref(d);
1124                         }
1125
1126                         if (value[0]=='\0') {
1127                                 const char *val;
1128
1129                                 val = udev_device_get_attr_value(dev, key_name);
1130                                 if (val != NULL)
1131                                         util_strlcpy(value, val, sizeof(value));
1132                         }
1133
1134                         if (value[0]=='\0')
1135                                 goto nomatch;
1136
1137                         /* strip trailing whitespace of value, if not asked to match for it */
1138                         len = strlen(key_value);
1139                         if (len > 0 && !isspace(key_value[len-1])) {
1140                                 len = strlen(value);
1141                                 while (len > 0 && isspace(value[--len]))
1142                                         value[len] = '\0';
1143                                 dbg(event->udev, "removed trailing whitespace from '%s'\n", value);
1144                         }
1145
1146                         if (match_key(event->udev, "ATTR", rule, &pair->key, value))
1147                                 goto nomatch;
1148                 }
1149         }
1150
1151         /* walk up the chain of parent devices and find a match */
1152         event->dev_parent = dev;
1153         while (1) {
1154                 /* check for matching kernel device name */
1155                 if (match_key(event->udev, "KERNELS", rule,
1156                               &rule->kernels, udev_device_get_sysname(event->dev_parent)))
1157                         goto try_parent;
1158
1159                 /* check for matching subsystem value */
1160                 if (match_key(event->udev, "SUBSYSTEMS", rule,
1161                               &rule->subsystems, udev_device_get_subsystem(event->dev_parent)))
1162                         goto try_parent;
1163
1164                 /* check for matching driver */
1165                 if (match_key(event->udev, "DRIVERS", rule,
1166                               &rule->drivers, udev_device_get_driver(event->dev_parent)))
1167                         goto try_parent;
1168
1169                 /* check for matching sysfs attribute pairs */
1170                 for (i = 0; i < rule->attrs.count; i++) {
1171                         struct key_pair *pair = &rule->attrs.keys[i];
1172
1173                         if (pair->key.operation == KEY_OP_MATCH ||
1174                             pair->key.operation == KEY_OP_NOMATCH) {
1175                                 const char *key_name = key_pair_name(rule, pair);
1176                                 const char *key_value = key_val(rule, &pair->key);
1177                                 const char *val;
1178                                 char value[UTIL_NAME_SIZE];
1179                                 size_t len;
1180
1181                                 val = udev_device_get_attr_value(event->dev_parent, key_name);
1182                                 if (val == NULL)
1183                                         val = udev_device_get_attr_value(dev, key_name);
1184                                 if (val == NULL)
1185                                         goto try_parent;
1186                                 util_strlcpy(value, val, sizeof(value));
1187
1188                                 /* strip trailing whitespace of value, if not asked to match for it */
1189                                 len = strlen(key_value);
1190                                 if (len > 0 && !isspace(key_value[len-1])) {
1191                                         len = strlen(value);
1192                                         while (len > 0 && isspace(value[--len]))
1193                                                 value[len] = '\0';
1194                                         dbg(event->udev, "removed trailing whitespace from '%s'\n", value);
1195                                 }
1196
1197                                 if (match_key(event->udev, "ATTRS", rule, &pair->key, value))
1198                                         goto try_parent;
1199                         }
1200                 }
1201
1202                 /* found matching device  */
1203                 break;
1204 try_parent:
1205                 /* move to parent device */
1206                 dbg(event->udev, "try parent sysfs device\n");
1207                 event->dev_parent = udev_device_get_parent(event->dev_parent);
1208                 if (event->dev_parent == NULL)
1209                         goto nomatch;
1210                 dbg(event->udev, "looking at dev_parent->devpath='%s'\n",
1211                     udev_device_get_syspath(event->dev_parent));
1212         }
1213
1214         /* execute external program */
1215         if (rule->program.operation != KEY_OP_UNSET) {
1216                 char program[UTIL_PATH_SIZE];
1217                 char result[UTIL_PATH_SIZE];
1218
1219                 util_strlcpy(program, key_val(rule, &rule->program), sizeof(program));
1220                 udev_rules_apply_format(event, program, sizeof(program));
1221                 if (run_program(event->dev, program, result, sizeof(result), NULL) != 0) {
1222                         dbg(event->udev, "PROGRAM is false\n");
1223                         event->program_result[0] = '\0';
1224                         if (rule->program.operation != KEY_OP_NOMATCH)
1225                                 goto nomatch;
1226                 } else {
1227                         int count;
1228
1229                         dbg(event->udev, "PROGRAM matches\n");
1230                         util_remove_trailing_chars(result, '\n');
1231                         if (rule->string_escape == ESCAPE_UNSET ||
1232                             rule->string_escape == ESCAPE_REPLACE) {
1233                                 count = util_replace_chars(result, ALLOWED_CHARS_INPUT);
1234                                 if (count > 0)
1235                                         info(event->udev, "%i character(s) replaced\n" , count);
1236                         }
1237                         dbg(event->udev, "result is '%s'\n", result);
1238                         util_strlcpy(event->program_result, result, sizeof(event->program_result));
1239                         dbg(event->udev, "PROGRAM returned successful\n");
1240                         if (rule->program.operation == KEY_OP_NOMATCH)
1241                                 goto nomatch;
1242                 }
1243                 dbg(event->udev, "PROGRAM key is true\n");
1244         }
1245
1246         /* check for matching result of external program */
1247         if (match_key(event->udev, "RESULT", rule, &rule->result, event->program_result))
1248                 goto nomatch;
1249
1250         /* import variables returned from program or or file into environment */
1251         if (rule->import.operation != KEY_OP_UNSET) {
1252                 char import[UTIL_PATH_SIZE];
1253                 int rc = -1;
1254
1255                 util_strlcpy(import, key_val(rule, &rule->import), sizeof(import));
1256                 udev_rules_apply_format(event, import, sizeof(import));
1257                 dbg(event->udev, "check for IMPORT import='%s'\n", import);
1258                 if (rule->import_type == IMPORT_PROGRAM) {
1259                         rc = import_program_into_env(event->dev, import);
1260                 } else if (rule->import_type == IMPORT_FILE) {
1261                         dbg(event->udev, "import file import='%s'\n", import);
1262                         rc = import_file_into_env(event->dev, import);
1263                 } else if (rule->import_type == IMPORT_PARENT) {
1264                         dbg(event->udev, "import parent import='%s'\n", import);
1265                         rc = import_parent_into_env(event->dev, import);
1266                 }
1267                 if (rc != 0) {
1268                         dbg(event->udev, "IMPORT failed\n");
1269                         if (rule->import.operation != KEY_OP_NOMATCH)
1270                                 goto nomatch;
1271                 } else
1272                         dbg(event->udev, "IMPORT '%s' imported\n", key_val(rule, &rule->import));
1273                 dbg(event->udev, "IMPORT key is true\n");
1274         }
1275
1276         /* rule matches, if we have ENV assignments export it */
1277         for (i = 0; i < rule->env.count; i++) {
1278                 struct key_pair *pair = &rule->env.keys[i];
1279
1280                 if (pair->key.operation == KEY_OP_ASSIGN) {
1281                         char temp_value[UTIL_NAME_SIZE];
1282                         const char *key_name = key_pair_name(rule, pair);
1283                         const char *value = key_val(rule, &pair->key);
1284
1285                         /* make sure we don't write to the same string we possibly read from */
1286                         util_strlcpy(temp_value, value, sizeof(temp_value));
1287                         udev_rules_apply_format(event, temp_value, sizeof(temp_value));
1288
1289                         if (temp_value[0] != '\0') {
1290                                 struct udev_list_entry *entry;
1291
1292                                 info(event->udev, "set ENV '%s=%s'\n", key_name, temp_value);
1293                                 entry = udev_device_add_property(dev, key_name, temp_value);
1294                                 /* store in db */
1295                                 udev_list_entry_set_flag(entry, 1);
1296                         }
1297                 }
1298         }
1299
1300         /* if we have ATTR assignments, write value to sysfs file */
1301         for (i = 0; i < rule->attr.count; i++) {
1302                 struct key_pair *pair = &rule->attr.keys[i];
1303
1304                 if (pair->key.operation == KEY_OP_ASSIGN) {
1305                         const char *key_name = key_pair_name(rule, pair);
1306                         char *subsys;
1307                         char *sysname;
1308                         char *attrib;
1309                         char attr[UTIL_PATH_SIZE];
1310                         char value[UTIL_NAME_SIZE];
1311                         FILE *f;
1312
1313                         util_strlcpy(attr, key_name, sizeof(attr));
1314                         if (split_subsys_sysname(event->udev, attr, &subsys, &sysname, &attrib) == 0) {
1315                                 struct udev_device *d;
1316
1317                                 d = udev_device_new_from_subsystem_sysname(event->udev, subsys, sysname);
1318                                 if (d != NULL) {
1319                                         util_strlcpy(attr, udev_device_get_syspath(d), sizeof(attr));
1320                                         if (attrib != NULL) {
1321                                                 util_strlcat(attr, "/", sizeof(attr));
1322                                                 util_strlcat(attr, attrib, sizeof(attr));
1323                                         }
1324                                         udev_device_unref(d);
1325                                 }
1326                         } else {
1327                                 util_strlcpy(attr, udev_device_get_syspath(dev), sizeof(attr));
1328                                 util_strlcat(attr, "/", sizeof(attr));
1329                                 util_strlcat(attr, key_name, sizeof(attr));
1330                         }
1331
1332                         attr_subst_subdir(attr, sizeof(attr));
1333
1334                         util_strlcpy(value, key_val(rule, &pair->key), sizeof(value));
1335                         udev_rules_apply_format(event, value, sizeof(value));
1336                         info(event->udev, "writing '%s' to sysfs file '%s'\n", value, attr);
1337                         f = fopen(attr, "w");
1338                         if (f != NULL) {
1339                                 if (!event->test)
1340                                         if (fprintf(f, "%s", value) <= 0)
1341                                                 err(event->udev, "error writing ATTR{%s}: %m\n", attr);
1342                                 fclose(f);
1343                         } else
1344                                 err(event->udev, "error opening ATTR{%s} for writing: %m\n", attr);
1345                 }
1346         }
1347         return 0;
1348
1349 nomatch:
1350         return -1;
1351 }
1352
1353 int udev_rules_get_name(struct udev_rules *rules, struct udev_event *event)
1354 {
1355         struct udev_device *dev = event->dev;
1356         struct udev_rules_iter iter;
1357         struct udev_rule *rule;
1358         int name_set = 0;
1359
1360         dbg(event->udev, "device: '%s'\n", udev_device_get_syspath(dev));
1361
1362         /* look for a matching rule to apply */
1363         udev_rules_iter_init(&iter, rules);
1364         while (1) {
1365                 rule = udev_rules_iter_next(&iter);
1366                 if (rule == NULL)
1367                         break;
1368
1369                 if (name_set &&
1370                     (rule->name.operation == KEY_OP_ASSIGN ||
1371                      rule->name.operation == KEY_OP_ASSIGN_FINAL ||
1372                      rule->name.operation == KEY_OP_ADD)) {
1373                         dbg(event->udev, "node name already set, rule ignored\n");
1374                         continue;
1375                 }
1376
1377                 dbg(event->udev, "process rule\n");
1378                 if (match_rule(event, rule) == 0) {
1379                         /* apply options */
1380                         if (rule->ignore_device) {
1381                                 info(event->udev, "rule applied, '%s' is ignored\n", udev_device_get_sysname(dev));
1382                                 event->ignore_device = 1;
1383                                 return 0;
1384                         }
1385                         if (rule->ignore_remove) {
1386                                 udev_device_set_ignore_remove(dev, 1);
1387                                 dbg(event->udev, "remove event should be ignored\n");
1388                         }
1389                         if (rule->link_priority != 0) {
1390                                 udev_device_set_devlink_priority(dev, rule->link_priority);
1391                                 info(event->udev, "devlink_priority=%i\n", rule->link_priority);
1392                         }
1393                         if (rule->event_timeout >= 0) {
1394                                 udev_device_set_event_timeout(dev, rule->event_timeout);
1395                                 info(event->udev, "event_timeout=%i\n", rule->event_timeout);
1396                         }
1397                         /* apply all_partitions option only at a disk device */
1398                         if (rule->partitions > 0 &&
1399                             strcmp(udev_device_get_subsystem(dev), "block") == 0 &&
1400                             udev_device_get_sysnum(dev) == NULL) {
1401                                 udev_device_set_num_fake_partitions(dev, rule->partitions);
1402                                 dbg(event->udev, "creation of partition nodes requested\n");
1403                         }
1404
1405                         /* apply permissions */
1406                         if (!event->mode_final && rule->mode.operation != KEY_OP_UNSET) {
1407                                 if (rule->mode.operation == KEY_OP_ASSIGN_FINAL)
1408                                         event->mode_final = 1;
1409                                 char buf[20];
1410                                 util_strlcpy(buf, key_val(rule, &rule->mode), sizeof(buf));
1411                                 udev_rules_apply_format(event, buf, sizeof(buf));
1412                                 event->mode = strtol(buf, NULL, 8);
1413                                 dbg(event->udev, "applied mode=%#o to '%s'\n",
1414                                     event->mode, udev_device_get_sysname(dev));
1415                         }
1416                         if (!event->owner_final && rule->owner.operation != KEY_OP_UNSET) {
1417                                 if (rule->owner.operation == KEY_OP_ASSIGN_FINAL)
1418                                         event->owner_final = 1;
1419                                 util_strlcpy(event->owner, key_val(rule, &rule->owner), sizeof(event->owner));
1420                                 udev_rules_apply_format(event, event->owner, sizeof(event->owner));
1421                                 dbg(event->udev, "applied owner='%s' to '%s'\n",
1422                                     event->owner, udev_device_get_sysname(dev));
1423                         }
1424                         if (!event->group_final && rule->group.operation != KEY_OP_UNSET) {
1425                                 if (rule->group.operation == KEY_OP_ASSIGN_FINAL)
1426                                         event->group_final = 1;
1427                                 util_strlcpy(event->group, key_val(rule, &rule->group), sizeof(event->group));
1428                                 udev_rules_apply_format(event, event->group, sizeof(event->group));
1429                                 dbg(event->udev, "applied group='%s' to '%s'\n",
1430                                     event->group, udev_device_get_sysname(dev));
1431                         }
1432
1433                         /* collect symlinks */
1434                         if (!event->devlink_final &&
1435                             (rule->symlink.operation == KEY_OP_ASSIGN ||
1436                              rule->symlink.operation == KEY_OP_ASSIGN_FINAL ||
1437                              rule->symlink.operation == KEY_OP_ADD)) {
1438                                 char temp[UTIL_PATH_SIZE];
1439                                 char filename[UTIL_PATH_SIZE];
1440                                 char *pos, *next;
1441                                 int count = 0;
1442
1443                                 if (rule->symlink.operation == KEY_OP_ASSIGN_FINAL)
1444                                         event->devlink_final = 1;
1445                                 if (rule->symlink.operation == KEY_OP_ASSIGN ||
1446                                     rule->symlink.operation == KEY_OP_ASSIGN_FINAL) {
1447                                         info(event->udev, "reset symlink list\n");
1448                                         udev_device_cleanup_devlinks_list(dev);
1449                                 }
1450                                 /* allow  multiple symlinks separated by spaces */
1451                                 util_strlcpy(temp, key_val(rule, &rule->symlink), sizeof(temp));
1452                                 udev_rules_apply_format(event, temp, sizeof(temp));
1453                                 if (rule->string_escape == ESCAPE_UNSET)
1454                                         count = util_replace_chars(temp, ALLOWED_CHARS_FILE " ");
1455                                 else if (rule->string_escape == ESCAPE_REPLACE)
1456                                         count = util_replace_chars(temp, ALLOWED_CHARS_FILE);
1457                                 if (count > 0)
1458                                         info(event->udev, "%i character(s) replaced\n" , count);
1459                                 dbg(event->udev, "rule applied, added symlink(s) '%s'\n", temp);
1460                                 pos = temp;
1461                                 while (isspace(pos[0]))
1462                                         pos++;
1463                                 next = strchr(pos, ' ');
1464                                 while (next) {
1465                                         next[0] = '\0';
1466                                         info(event->udev, "add symlink '%s'\n", pos);
1467                                         util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
1468                                         util_strlcat(filename, "/", sizeof(filename));
1469                                         util_strlcat(filename, pos, sizeof(filename));
1470                                         udev_device_add_devlink(dev, filename);
1471                                         while (isspace(next[1]))
1472                                                 next++;
1473                                         pos = &next[1];
1474                                         next = strchr(pos, ' ');
1475                                 }
1476                                 if (pos[0] != '\0') {
1477                                         info(event->udev, "add symlink '%s'\n", pos);
1478                                         util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
1479                                         util_strlcat(filename, "/", sizeof(filename));
1480                                         util_strlcat(filename, pos, sizeof(filename));
1481                                         udev_device_add_devlink(dev, filename);
1482                                 }
1483                         }
1484
1485                         /* set name, later rules with name set will be ignored */
1486                         if (rule->name.operation == KEY_OP_ASSIGN ||
1487                             rule->name.operation == KEY_OP_ASSIGN_FINAL ||
1488                             rule->name.operation == KEY_OP_ADD) {
1489                                 int count;
1490
1491                                 name_set = 1;
1492                                 util_strlcpy(event->name, key_val(rule, &rule->name), sizeof(event->name));
1493                                 udev_rules_apply_format(event, event->name, sizeof(event->name));
1494                                 if (rule->string_escape == ESCAPE_UNSET ||
1495                                     rule->string_escape == ESCAPE_REPLACE) {
1496                                         count = util_replace_chars(event->name, ALLOWED_CHARS_FILE);
1497                                         if (count > 0)
1498                                                 info(event->udev, "%i character(s) replaced\n", count);
1499                                 }
1500
1501                                 info(event->udev, "rule applied, '%s' becomes '%s'\n",
1502                                      udev_device_get_sysname(dev), event->name);
1503                                 if (strcmp(udev_device_get_subsystem(dev), "net") != 0)
1504                                         dbg(event->udev, "'%s' owner='%s', group='%s', mode=%#o partitions=%i\n",
1505                                             event->name, event->owner, event->group, event->mode,
1506                                             udev_device_get_num_fake_partitions(dev));
1507                         }
1508
1509                         if (!event->run_final && rule->run.operation != KEY_OP_UNSET) {
1510                                 struct udev_list_entry *list_entry;
1511
1512                                 if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
1513                                         event->run_final = 1;
1514                                 if (rule->run.operation == KEY_OP_ASSIGN || rule->run.operation == KEY_OP_ASSIGN_FINAL) {
1515                                         info(event->udev, "reset run list\n");
1516                                         udev_list_cleanup(event->udev, &event->run_list);
1517                                 }
1518                                 dbg(event->udev, "add run '%s'\n", key_val(rule, &rule->run));
1519                                 list_entry = udev_list_entry_add(event->udev, &event->run_list,
1520                                                                  key_val(rule, &rule->run), NULL, 1, 0);
1521                                 if (rule->run_ignore_error && list_entry != NULL)
1522                                         udev_list_entry_set_flag(list_entry, 1);
1523                         }
1524
1525                         if (rule->last_rule) {
1526                                 dbg(event->udev, "last rule to be applied\n");
1527                                 break;
1528                         }
1529
1530                         if (rule->goto_label.operation != KEY_OP_UNSET) {
1531                                 dbg(event->udev, "moving forward to label '%s'\n", key_val(rule, &rule->goto_label));
1532                                 udev_rules_iter_goto(&iter, rule->goto_rule_off);
1533                         }
1534                 }
1535         }
1536
1537         if (!name_set) {
1538                 info(event->udev, "no node name set, will use kernel name '%s'\n",
1539                      udev_device_get_sysname(dev));
1540                 util_strlcpy(event->name, udev_device_get_sysname(dev), sizeof(event->name));
1541         }
1542
1543         if (event->tmp_node[0] != '\0') {
1544                 dbg(event->udev, "removing temporary device node\n");
1545                 unlink_secure(event->udev, event->tmp_node);
1546                 event->tmp_node[0] = '\0';
1547         }
1548         return 0;
1549 }
1550
1551 int udev_rules_get_run(struct udev_rules *rules, struct udev_event *event)
1552 {
1553         struct udev_device *dev = event->dev;
1554         struct udev_rules_iter iter;
1555         struct udev_rule *rule;
1556
1557         dbg(event->udev, "sysname: '%s'\n", udev_device_get_sysname(dev));
1558
1559         /* look for a matching rule to apply */
1560         udev_rules_iter_init(&iter, rules);
1561         while (1) {
1562                 rule = udev_rules_iter_next(&iter);
1563                 if (rule == NULL)
1564                         break;
1565
1566                 dbg(event->udev, "process rule\n");
1567                 if (rule->name.operation == KEY_OP_ASSIGN ||
1568                     rule->name.operation == KEY_OP_ASSIGN_FINAL ||
1569                     rule->name.operation == KEY_OP_ADD ||
1570                     rule->symlink.operation == KEY_OP_ASSIGN ||
1571                     rule->symlink.operation == KEY_OP_ASSIGN_FINAL ||
1572                     rule->symlink.operation == KEY_OP_ADD ||
1573                     rule->mode.operation != KEY_OP_UNSET ||
1574                     rule->owner.operation != KEY_OP_UNSET || rule->group.operation != KEY_OP_UNSET) {
1575                         dbg(event->udev, "skip rule that names a device\n");
1576                         continue;
1577                 }
1578
1579                 if (match_rule(event, rule) == 0) {
1580                         if (rule->ignore_device) {
1581                                 info(event->udev, "rule applied, '%s' is ignored\n", udev_device_get_sysname(dev));
1582                                 event->ignore_device = 1;
1583                                 return 0;
1584                         }
1585                         if (rule->ignore_remove) {
1586                                 udev_device_set_ignore_remove(dev, 1);
1587                                 dbg(event->udev, "remove event should be ignored\n");
1588                         }
1589
1590                         if (!event->run_final && rule->run.operation != KEY_OP_UNSET) {
1591                                 struct udev_list_entry *list_entry;
1592
1593                                 if (rule->run.operation == KEY_OP_ASSIGN ||
1594                                     rule->run.operation == KEY_OP_ASSIGN_FINAL) {
1595                                         info(event->udev, "reset run list\n");
1596                                         udev_list_cleanup(event->udev, &event->run_list);
1597                                 }
1598                                 dbg(event->udev, "add run '%s'\n", key_val(rule, &rule->run));
1599                                 list_entry = udev_list_entry_add(event->udev, &event->run_list,
1600                                                                  key_val(rule, &rule->run), NULL, 1, 0);
1601                                 if (rule->run_ignore_error && list_entry != NULL)
1602                                         udev_list_entry_set_flag(list_entry, 1);
1603                                 if (rule->run.operation == KEY_OP_ASSIGN_FINAL)
1604                                         break;
1605                         }
1606
1607                         if (rule->last_rule) {
1608                                 dbg(event->udev, "last rule to be applied\n");
1609                                 break;
1610                         }
1611
1612                         if (rule->goto_label.operation != KEY_OP_UNSET) {
1613                                 dbg(event->udev, "moving forward to label '%s'\n", key_val(rule, &rule->goto_label));
1614                                 udev_rules_iter_goto(&iter, rule->goto_rule_off);
1615                         }
1616                 }
1617         }
1618
1619         return 0;
1620 }