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