]> git.ipfire.org Git - thirdparty/systemd.git/blob - udev/udev-event.c
while (1) -> for (;;)
[thirdparty/systemd.git] / udev / udev-event.c
1 /*
2 * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org>
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <stddef.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <time.h>
27 #include <net/if.h>
28 #include <sys/ioctl.h>
29 #include <sys/socket.h>
30 #include <linux/sockios.h>
31
32 #include "udev.h"
33
34 struct udev_event *udev_event_new(struct udev_device *dev)
35 {
36 struct udev_event *event;
37
38 event = calloc(1, sizeof(struct udev_event));
39 if (event == NULL)
40 return NULL;
41 event->mode = 0600;
42 event->dev = dev;
43 event->udev = udev_device_get_udev(dev);
44 udev_list_init(&event->run_list);
45 dbg(event->udev, "allocated event %p\n", event);
46 return event;
47 }
48
49 void udev_event_unref(struct udev_event *event)
50 {
51 if (event == NULL)
52 return;
53 udev_list_cleanup_entries(event->udev, &event->run_list);
54 free(event->tmp_node);
55 free(event->program_result);
56 free(event->name);
57 dbg(event->udev, "free event %p\n", event);
58 free(event);
59 }
60
61 size_t udev_event_apply_format(struct udev_event *event, const char *src, char *dest, size_t size)
62 {
63 struct udev_device *dev = event->dev;
64 enum subst_type {
65 SUBST_UNKNOWN,
66 SUBST_TEMP_NODE,
67 SUBST_ATTR,
68 SUBST_ENV,
69 SUBST_KERNEL,
70 SUBST_KERNEL_NUMBER,
71 SUBST_DRIVER,
72 SUBST_DEVPATH,
73 SUBST_ID,
74 SUBST_MAJOR,
75 SUBST_MINOR,
76 SUBST_RESULT,
77 SUBST_PARENT,
78 SUBST_NAME,
79 SUBST_LINKS,
80 SUBST_ROOT,
81 SUBST_SYS,
82 };
83 static const struct subst_map {
84 char *name;
85 char fmt;
86 enum subst_type type;
87 } map[] = {
88 { .name = "tempnode", .fmt = 'N', .type = SUBST_TEMP_NODE },
89 { .name = "attr", .fmt = 's', .type = SUBST_ATTR },
90 { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR },
91 { .name = "env", .fmt = 'E', .type = SUBST_ENV },
92 { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL },
93 { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
94 { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER },
95 { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
96 { .name = "id", .fmt = 'b', .type = SUBST_ID },
97 { .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
98 { .name = "minor", .fmt = 'm', .type = SUBST_MINOR },
99 { .name = "result", .fmt = 'c', .type = SUBST_RESULT },
100 { .name = "parent", .fmt = 'P', .type = SUBST_PARENT },
101 { .name = "name", .fmt = 'D', .type = SUBST_NAME },
102 { .name = "links", .fmt = 'L', .type = SUBST_LINKS },
103 { .name = "root", .fmt = 'r', .type = SUBST_ROOT },
104 { .name = "sys", .fmt = 'S', .type = SUBST_SYS },
105 };
106 const char *from;
107 char *s;
108 size_t l;
109
110 from = src;
111 s = dest;
112 l = size;
113
114 for (;;) {
115 enum subst_type type = SUBST_UNKNOWN;
116 char attrbuf[UTIL_PATH_SIZE];
117 char *attr = NULL;
118
119 while (from[0] != '\0') {
120 if (from[0] == '$') {
121 /* substitute named variable */
122 unsigned int i;
123
124 if (from[1] == '$') {
125 from++;
126 goto copy;
127 }
128
129 for (i = 0; i < ARRAY_SIZE(map); i++) {
130 if (strncmp(&from[1], map[i].name, strlen(map[i].name)) == 0) {
131 type = map[i].type;
132 from += strlen(map[i].name)+1;
133 dbg(event->udev, "will substitute format name '%s'\n", map[i].name);
134 goto subst;
135 }
136 }
137 } else if (from[0] == '%') {
138 /* substitute format char */
139 unsigned int i;
140
141 if (from[1] == '%') {
142 from++;
143 goto copy;
144 }
145
146 for (i = 0; i < ARRAY_SIZE(map); i++) {
147 if (from[1] == map[i].fmt) {
148 type = map[i].type;
149 from += 2;
150 dbg(event->udev, "will substitute format char '%c'\n", map[i].fmt);
151 goto subst;
152 }
153 }
154 }
155 copy:
156 /* copy char */
157 if (l == 0)
158 goto out;
159 s[0] = from[0];
160 from++;
161 s++;
162 l--;
163 }
164
165 goto out;
166 subst:
167 /* extract possible $format{attr} */
168 if (from[0] == '{') {
169 unsigned int i;
170
171 from++;
172 for (i = 0; from[i] != '}'; i++) {
173 if (from[i] == '\0') {
174 err(event->udev, "missing closing brace for format '%s'\n", src);
175 goto out;
176 }
177 }
178 if (i >= sizeof(attrbuf))
179 goto out;
180 memcpy(attrbuf, from, i);
181 attrbuf[i] = '\0';
182 from += i+1;
183 attr = attrbuf;
184 } else {
185 attr = NULL;
186 }
187
188 switch (type) {
189 case SUBST_DEVPATH:
190 l = util_strpcpy(&s, l, udev_device_get_devpath(dev));
191 dbg(event->udev, "substitute devpath '%s'\n", udev_device_get_devpath(dev));
192 break;
193 case SUBST_KERNEL:
194 l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
195 dbg(event->udev, "substitute kernel name '%s'\n", udev_device_get_sysname(dev));
196 break;
197 case SUBST_KERNEL_NUMBER:
198 if (udev_device_get_sysnum(dev) == NULL)
199 break;
200 l = util_strpcpy(&s, l, udev_device_get_sysnum(dev));
201 dbg(event->udev, "substitute kernel number '%s'\n", udev_device_get_sysnum(dev));
202 break;
203 case SUBST_ID:
204 if (event->dev_parent == NULL)
205 break;
206 l = util_strpcpy(&s, l, udev_device_get_sysname(event->dev_parent));
207 dbg(event->udev, "substitute id '%s'\n", udev_device_get_sysname(event->dev_parent));
208 break;
209 case SUBST_DRIVER: {
210 const char *driver;
211
212 if (event->dev_parent == NULL)
213 break;
214
215 driver = udev_device_get_driver(event->dev_parent);
216 if (driver == NULL)
217 break;
218 l = util_strpcpy(&s, l, driver);
219 dbg(event->udev, "substitute driver '%s'\n", driver);
220 break;
221 }
222 case SUBST_MAJOR: {
223 char num[UTIL_PATH_SIZE];
224
225 sprintf(num, "%d", major(udev_device_get_devnum(dev)));
226 l = util_strpcpy(&s, l, num);
227 dbg(event->udev, "substitute major number '%s'\n", num);
228 break;
229 }
230 case SUBST_MINOR: {
231 char num[UTIL_PATH_SIZE];
232
233 sprintf(num, "%d", minor(udev_device_get_devnum(dev)));
234 l = util_strpcpy(&s, l, num);
235 dbg(event->udev, "substitute minor number '%s'\n", num);
236 break;
237 }
238 case SUBST_RESULT: {
239 char *rest;
240 int i;
241
242 if (event->program_result == NULL)
243 break;
244 /* get part part of the result string */
245 i = 0;
246 if (attr != NULL)
247 i = strtoul(attr, &rest, 10);
248 if (i > 0) {
249 char result[UTIL_PATH_SIZE];
250 char tmp[UTIL_PATH_SIZE];
251 char *cpos;
252
253 dbg(event->udev, "request part #%d of result string\n", i);
254 util_strscpy(result, sizeof(result), event->program_result);
255 cpos = result;
256 while (--i) {
257 while (cpos[0] != '\0' && !isspace(cpos[0]))
258 cpos++;
259 while (isspace(cpos[0]))
260 cpos++;
261 }
262 if (i > 0) {
263 err(event->udev, "requested part of result string not found\n");
264 break;
265 }
266 util_strscpy(tmp, sizeof(tmp), cpos);
267 /* %{2+}c copies the whole string from the second part on */
268 if (rest[0] != '+') {
269 cpos = strchr(tmp, ' ');
270 if (cpos)
271 cpos[0] = '\0';
272 }
273 l = util_strpcpy(&s, l, tmp);
274 dbg(event->udev, "substitute part of result string '%s'\n", tmp);
275 } else {
276 l = util_strpcpy(&s, l, event->program_result);
277 dbg(event->udev, "substitute result string '%s'\n", event->program_result);
278 }
279 break;
280 }
281 case SUBST_ATTR: {
282 const char *value = NULL;
283 char vbuf[UTIL_NAME_SIZE];
284 size_t len;
285 int count;
286
287 if (attr == NULL) {
288 err(event->udev, "missing file parameter for attr\n");
289 break;
290 }
291
292 /* try to read the value specified by "[dmi/id]product_name" */
293 if (util_resolve_subsys_kernel(event->udev, attr, vbuf, sizeof(vbuf), 1) == 0)
294 value = vbuf;
295
296 /* try to read the attribute the device */
297 if (value == NULL)
298 value = udev_device_get_sysattr_value(event->dev, attr);
299
300 /* try to read the attribute of the parent device, other matches have selected */
301 if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev)
302 value = udev_device_get_sysattr_value(event->dev_parent, attr);
303
304 if (value == NULL)
305 break;
306
307 /* strip trailing whitespace, and replace unwanted characters */
308 if (value != vbuf)
309 util_strscpy(vbuf, sizeof(vbuf), value);
310 len = strlen(vbuf);
311 while (len > 0 && isspace(vbuf[--len]))
312 vbuf[len] = '\0';
313 count = udev_util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
314 if (count > 0)
315 info(event->udev, "%i character(s) replaced\n" , count);
316 l = util_strpcpy(&s, l, vbuf);
317 dbg(event->udev, "substitute sysfs value '%s'\n", vbuf);
318 break;
319 }
320 case SUBST_PARENT: {
321 struct udev_device *dev_parent;
322 const char *devnode;
323
324 dev_parent = udev_device_get_parent(event->dev);
325 if (dev_parent == NULL)
326 break;
327 devnode = udev_device_get_devnode(dev_parent);
328 if (devnode != NULL) {
329 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
330
331 l = util_strpcpy(&s, l, &devnode[devlen]);
332 dbg(event->udev, "found parent '%s', got node name '%s'\n",
333 udev_device_get_syspath(dev_parent), &devnode[devlen]);
334 }
335 break;
336 }
337 case SUBST_TEMP_NODE: {
338 dev_t devnum;
339 struct stat statbuf;
340 char filename[UTIL_PATH_SIZE];
341 const char *devtype;
342
343 if (event->tmp_node != NULL) {
344 l = util_strpcpy(&s, l, event->tmp_node);
345 dbg(event->udev, "tempnode: return earlier created one\n");
346 break;
347 }
348 devnum = udev_device_get_devnum(dev);
349 if (major(devnum) == 0)
350 break;
351 /* lookup kernel provided node */
352 if (udev_device_get_knodename(dev) != NULL) {
353 util_strscpyl(filename, sizeof(filename),
354 udev_get_dev_path(event->udev), "/", udev_device_get_knodename(dev), NULL);
355 if (stat(filename, &statbuf) == 0 && statbuf.st_rdev == devnum) {
356 l = util_strpcpy(&s, l, filename);
357 dbg(event->udev, "tempnode: return kernel node\n");
358 break;
359 }
360 }
361 /* lookup /dev/{char,block}/<maj>:<min> */
362 if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
363 devtype = "block";
364 else
365 devtype = "char";
366 snprintf(filename, sizeof(filename), "%s/%s/%u:%u",
367 udev_get_dev_path(event->udev), devtype,
368 major(udev_device_get_devnum(dev)),
369 minor(udev_device_get_devnum(dev)));
370 if (stat(filename, &statbuf) == 0 && statbuf.st_rdev == devnum) {
371 l = util_strpcpy(&s, l, filename);
372 dbg(event->udev, "tempnode: return maj:min node\n");
373 break;
374 }
375 /* create temporary node */
376 dbg(event->udev, "tempnode: create temp node\n");
377 asprintf(&event->tmp_node, "%s/.tmp-%s-%u:%u",
378 udev_get_dev_path(event->udev), devtype,
379 major(udev_device_get_devnum(dev)),
380 minor(udev_device_get_devnum(dev)));
381 if (event->tmp_node == NULL)
382 break;
383 udev_node_mknod(dev, event->tmp_node, 0600, 0, 0);
384 l = util_strpcpy(&s, l, event->tmp_node);
385 break;
386 }
387 case SUBST_NAME:
388 if (event->name != NULL) {
389 l = util_strpcpy(&s, l, event->name);
390 dbg(event->udev, "substitute name '%s'\n", event->name);
391 } else {
392 l = util_strpcpy(&s, l, udev_device_get_sysname(dev));
393 dbg(event->udev, "substitute sysname '%s'\n", udev_device_get_sysname(dev));
394 }
395 break;
396 case SUBST_LINKS: {
397 size_t devlen = strlen(udev_get_dev_path(event->udev))+1;
398 struct udev_list_entry *list_entry;
399
400 list_entry = udev_device_get_devlinks_list_entry(dev);
401 if (list_entry == NULL)
402 break;
403 l = util_strpcpy(&s, l, &udev_list_entry_get_name(list_entry)[devlen]);
404 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
405 l = util_strpcpyl(&s, l, " ", &udev_list_entry_get_name(list_entry)[devlen], NULL);
406 break;
407 }
408 case SUBST_ROOT:
409 l = util_strpcpy(&s, l, udev_get_dev_path(event->udev));
410 dbg(event->udev, "substitute udev_root '%s'\n", udev_get_dev_path(event->udev));
411 break;
412 case SUBST_SYS:
413 l = util_strpcpy(&s, l, udev_get_sys_path(event->udev));
414 dbg(event->udev, "substitute sys_path '%s'\n", udev_get_sys_path(event->udev));
415 break;
416 case SUBST_ENV:
417 if (attr == NULL) {
418 dbg(event->udev, "missing attribute\n");
419 break;
420 } else {
421 const char *value;
422
423 value = udev_device_get_property_value(event->dev, attr);
424 if (value == NULL)
425 break;
426 dbg(event->udev, "substitute env '%s=%s'\n", attr, value);
427 l = util_strpcpy(&s, l, value);
428 break;
429 }
430 default:
431 err(event->udev, "unknown substitution type=%i\n", type);
432 break;
433 }
434 }
435
436 out:
437 s[0] = '\0';
438 dbg(event->udev, "'%s' -> '%s' (%zu)\n", src, dest, l);
439 return l;
440 }
441
442 static void rename_netif_kernel_log(struct ifreq ifr)
443 {
444 int klog;
445 FILE *f;
446
447 klog = open("/dev/kmsg", O_WRONLY);
448 if (klog < 0)
449 return;
450
451 f = fdopen(klog, "w");
452 if (f == NULL) {
453 close(klog);
454 return;
455 }
456
457 fprintf(f, "<6>udev: renamed network interface %s to %s\n",
458 ifr.ifr_name, ifr.ifr_newname);
459 fclose(f);
460 }
461
462 static int rename_netif(struct udev_event *event)
463 {
464 struct udev_device *dev = event->dev;
465 int sk;
466 struct ifreq ifr;
467 int err;
468
469 info(event->udev, "changing net interface name from '%s' to '%s'\n",
470 udev_device_get_sysname(dev), event->name);
471
472 sk = socket(PF_INET, SOCK_DGRAM, 0);
473 if (sk < 0) {
474 err(event->udev, "error opening socket: %m\n");
475 return -1;
476 }
477
478 memset(&ifr, 0x00, sizeof(struct ifreq));
479 util_strscpy(ifr.ifr_name, IFNAMSIZ, udev_device_get_sysname(dev));
480 util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
481 err = ioctl(sk, SIOCSIFNAME, &ifr);
482 if (err == 0)
483 rename_netif_kernel_log(ifr);
484 else {
485 int loop;
486
487 /* see if the destination interface name already exists */
488 if (errno != EEXIST) {
489 err(event->udev, "error changing netif name %s to %s: %m\n",
490 ifr.ifr_name, ifr.ifr_newname);
491 goto exit;
492 }
493
494 /* free our own name, another process may wait for us */
495 util_strscpyl(ifr.ifr_newname, IFNAMSIZ, udev_device_get_sysname(dev), "_rename", NULL);
496 err = ioctl(sk, SIOCSIFNAME, &ifr);
497 if (err != 0) {
498 err(event->udev, "error changing netif name %s to %s: %m\n",
499 ifr.ifr_name, ifr.ifr_newname);
500 goto exit;
501 }
502
503 /* wait 90 seconds for our target to become available */
504 util_strscpy(ifr.ifr_name, IFNAMSIZ, ifr.ifr_newname);
505 util_strscpy(ifr.ifr_newname, IFNAMSIZ, event->name);
506 loop = 90 * 20;
507 while (loop--) {
508 const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 };
509
510 err = ioctl(sk, SIOCSIFNAME, &ifr);
511 if (err == 0) {
512 rename_netif_kernel_log(ifr);
513 break;
514 }
515
516 if (errno != EEXIST) {
517 err(event->udev, "error changing net interface name %s to %s: %m\n",
518 ifr.ifr_name, ifr.ifr_newname);
519 break;
520 }
521 dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n",
522 event->name, (90 * 20) - loop);
523 nanosleep(&duration, NULL);
524 }
525 }
526 exit:
527 close(sk);
528 return err;
529 }
530
531 int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
532 {
533 struct udev_device *dev = event->dev;
534 int err = 0;
535
536 if (udev_device_get_sysname_old(dev) != NULL &&
537 strcmp(udev_device_get_sysname_old(dev), udev_device_get_sysname(dev)) != 0) {
538 udev_device_rename_db(dev);
539 info(event->udev, "moved database from '%s:%s' to '%s:%s'\n",
540 udev_device_get_subsystem(dev), udev_device_get_sysname_old(dev),
541 udev_device_get_subsystem(dev), udev_device_get_sysname(dev));
542 }
543
544 if (strcmp(udev_device_get_action(dev), "remove") == 0) {
545 udev_device_read_db(dev);
546 udev_device_delete_db(dev);
547 udev_device_tag_index(dev, NULL, false);
548
549 if (major(udev_device_get_devnum(dev)) != 0)
550 udev_watch_end(event->udev, dev);
551
552 udev_rules_apply_to_event(rules, event);
553
554 if (major(udev_device_get_devnum(dev)) != 0)
555 err = udev_node_remove(dev);
556 } else {
557 event->dev_db = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev));
558 if (event->dev_db != NULL) {
559 udev_device_read_db(event->dev_db);
560 udev_device_set_info_loaded(event->dev_db);
561
562 /* disable watch during event processing */
563 if (major(udev_device_get_devnum(dev)) != 0)
564 udev_watch_end(event->udev, event->dev_db);
565 }
566
567 udev_rules_apply_to_event(rules, event);
568
569 /* rename a new network interface, if needed */
570 if (strcmp(udev_device_get_subsystem(dev), "net") == 0 && strcmp(udev_device_get_action(dev), "add") == 0 &&
571 event->name != NULL && strcmp(event->name, udev_device_get_sysname(dev)) != 0) {
572 char syspath[UTIL_PATH_SIZE];
573 char *pos;
574
575 err = rename_netif(event);
576 if (err == 0) {
577 info(event->udev, "renamed netif to '%s'\n", event->name);
578
579 /* delete stale db file */
580 udev_device_delete_db(dev);
581 udev_device_tag_index(dev, NULL, false);
582
583 /* remember old name */
584 udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev));
585
586 /* now change the devpath, because the kernel device name has changed */
587 util_strscpy(syspath, sizeof(syspath), udev_device_get_syspath(dev));
588 pos = strrchr(syspath, '/');
589 if (pos != NULL) {
590 pos++;
591 util_strscpy(pos, sizeof(syspath) - (pos - syspath), event->name);
592 udev_device_set_syspath(event->dev, syspath);
593 udev_device_add_property(dev, "INTERFACE", udev_device_get_sysname(dev));
594 info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev));
595 }
596 }
597 }
598
599 if (major(udev_device_get_devnum(dev)) != 0) {
600 char filename[UTIL_PATH_SIZE];
601
602 if (event->tmp_node != NULL) {
603 info(event->udev, "cleanup temporary device node\n");
604 util_unlink_secure(event->udev, event->tmp_node);
605 free(event->tmp_node);
606 event->tmp_node = NULL;
607 }
608
609 /* no rule, use kernel provided name */
610 if (event->name == NULL) {
611 if (udev_device_get_knodename(dev) != NULL) {
612 event->name = strdup(udev_device_get_knodename(dev));
613 info(event->udev, "no node name set, will use kernel supplied name '%s'\n", event->name);
614 } else {
615 event->name = strdup(udev_device_get_sysname(event->dev));
616 info(event->udev, "no node name set, will use device name '%s'\n", event->name);
617 }
618 }
619
620 if (event->name == NULL || event->name[0] == '\0') {
621 udev_device_delete_db(dev);
622 udev_device_tag_index(dev, NULL, false);
623 udev_device_unref(event->dev_db);
624 err = -ENOMEM;
625 err(event->udev, "no node name, something went wrong, ignoring\n");
626 goto out;
627 }
628
629 if (udev_device_get_knodename(dev) != NULL && strcmp(udev_device_get_knodename(dev), event->name) != 0)
630 err(event->udev, "kernel-provided name '%s' and NAME= '%s' disagree, "
631 "please use SYMLINK+= or change the kernel to provide the proper name\n",
632 udev_device_get_knodename(dev), event->name);
633
634 /* set device node name */
635 util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", event->name, NULL);
636 udev_device_set_devnode(dev, filename);
637 }
638
639 udev_device_update_db(dev);
640 udev_device_tag_index(dev, event->dev_db, true);
641
642 if (major(udev_device_get_devnum(dev)) != 0) {
643 /* remove/update possible left-over symlinks from old database entry */
644 if (event->dev_db != NULL)
645 udev_node_update_old_links(dev, event->dev_db);
646
647 /* change default 0600 to 0660 if a group is assigned */
648 if (event->mode == 0600 && event->gid > 0)
649 event->mode = 0660;
650
651 err = udev_node_add(dev, event->mode, event->uid, event->gid);
652 }
653
654 udev_device_unref(event->dev_db);
655 event->dev_db = NULL;
656 }
657 out:
658 return err;
659 }
660
661 int udev_event_execute_run(struct udev_event *event, const sigset_t *sigmask)
662 {
663 struct udev_list_entry *list_entry;
664 int err = 0;
665
666 dbg(event->udev, "executing run list\n");
667 udev_list_entry_foreach(list_entry, udev_list_get_entry(&event->run_list)) {
668 const char *cmd = udev_list_entry_get_name(list_entry);
669
670 if (strncmp(cmd, "socket:", strlen("socket:")) == 0) {
671 struct udev_monitor *monitor;
672
673 monitor = udev_monitor_new_from_socket(event->udev, &cmd[strlen("socket:")]);
674 if (monitor == NULL)
675 continue;
676 udev_monitor_send_device(monitor, NULL, event->dev);
677 udev_monitor_unref(monitor);
678 } else {
679 char program[UTIL_PATH_SIZE];
680 char **envp;
681
682 udev_event_apply_format(event, cmd, program, sizeof(program));
683 envp = udev_device_get_properties_envp(event->dev);
684 if (util_run_program(event->udev, program, envp, NULL, 0, NULL, sigmask, true) != 0) {
685 if (udev_list_entry_get_flags(list_entry))
686 err = -1;
687 }
688 }
689 }
690 return err;
691 }