]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udev-event.c
udev-event: add more assert()
[thirdparty/systemd.git] / src / udev / udev-event.c
CommitLineData
e7145211 1/* SPDX-License-Identifier: GPL-2.0+ */
d46f37fd 2
d46f37fd 3#include <ctype.h>
07630cea
LP
4#include <errno.h>
5#include <fcntl.h>
959e8b5d 6#include <net/if.h>
07630cea
LP
7#include <stddef.h>
8#include <stdio.h>
9#include <stdlib.h>
07630cea 10#include <unistd.h>
d46f37fd 11
e81c3a4c
YW
12#include "sd-event.h"
13
b5efdb8a 14#include "alloc-util.h"
947ce772 15#include "device-private.h"
e9343893 16#include "device-util.h"
3ffd4af2 17#include "fd-util.h"
f97b34a6 18#include "format-util.h"
70068602 19#include "libudev-device-internal.h"
07630cea 20#include "netlink-util.h"
feaa6db7 21#include "path-util.h"
8128f229 22#include "process-util.h"
24882e06 23#include "signal-util.h"
07630cea 24#include "string-util.h"
07a26e42 25#include "udev-builtin.h"
a2554ace 26#include "udev-node.h"
70068602 27#include "udev-watch.h"
24882e06 28#include "udev.h"
8128f229
TG
29
30typedef struct Spawn {
31 const char *cmd;
32 pid_t pid;
e81c3a4c
YW
33 usec_t timeout_warn_usec;
34 usec_t timeout_usec;
35 usec_t event_birth_usec;
53318514 36 bool accept_failure;
e81c3a4c
YW
37 int fd_stdout;
38 int fd_stderr;
39 char *result;
40 size_t result_size;
41 size_t result_len;
8128f229 42} Spawn;
d46f37fd 43
9ec6e95b 44struct udev_event *udev_event_new(struct udev_device *dev) {
912541b0
KS
45 struct udev_event *event;
46
955d98c9 47 event = new0(struct udev_event, 1);
912541b0
KS
48 if (event == NULL)
49 return NULL;
50 event->dev = dev;
3285baa8 51 event->birth_usec = now(CLOCK_MONOTONIC);
912541b0 52 return event;
aa8734ff
KS
53}
54
9ec6e95b 55void udev_event_unref(struct udev_event *event) {
29448498
YW
56 void *p;
57
912541b0
KS
58 if (event == NULL)
59 return;
1c4baffc 60 sd_netlink_unref(event->rtnl);
29448498
YW
61 while ((p = hashmap_steal_first_key(event->run_list)))
62 free(p);
d838e145 63 hashmap_free_free_free(event->seclabel_list);
912541b0
KS
64 free(event->program_result);
65 free(event->name);
912541b0 66 free(event);
aa8734ff
KS
67}
68
0d53705b
DS
69enum subst_type {
70 SUBST_UNKNOWN,
71 SUBST_DEVNODE,
72 SUBST_ATTR,
73 SUBST_ENV,
74 SUBST_KERNEL,
75 SUBST_KERNEL_NUMBER,
76 SUBST_DRIVER,
77 SUBST_DEVPATH,
78 SUBST_ID,
79 SUBST_MAJOR,
80 SUBST_MINOR,
81 SUBST_RESULT,
82 SUBST_PARENT,
83 SUBST_NAME,
84 SUBST_LINKS,
85 SUBST_ROOT,
86 SUBST_SYS,
87};
88
a368732b 89static size_t subst_format_var(struct udev_event *event,
0d53705b 90 enum subst_type type, char *attr,
be452683 91 char *dest, size_t l) {
a368732b 92 struct udev_device *dev = event->dev;
be452683 93 char *s = dest;
0d53705b
DS
94
95 switch (type) {
96 case SUBST_DEVPATH:
97 l = strpcpy(&s, l, udev_device_get_devpath(dev));
98 break;
99 case SUBST_KERNEL:
100 l = strpcpy(&s, l, udev_device_get_sysname(dev));
101 break;
102 case SUBST_KERNEL_NUMBER:
103 if (udev_device_get_sysnum(dev) == NULL)
104 break;
105 l = strpcpy(&s, l, udev_device_get_sysnum(dev));
106 break;
107 case SUBST_ID:
108 if (event->dev_parent == NULL)
109 break;
110 l = strpcpy(&s, l, udev_device_get_sysname(event->dev_parent));
111 break;
112 case SUBST_DRIVER: {
113 const char *driver;
114
115 if (event->dev_parent == NULL)
116 break;
117
118 driver = udev_device_get_driver(event->dev_parent);
119 if (driver == NULL)
120 break;
121 l = strpcpy(&s, l, driver);
122 break;
123 }
124 case SUBST_MAJOR: {
125 char num[UTIL_PATH_SIZE];
126
127 sprintf(num, "%u", major(udev_device_get_devnum(dev)));
128 l = strpcpy(&s, l, num);
129 break;
130 }
131 case SUBST_MINOR: {
132 char num[UTIL_PATH_SIZE];
133
134 sprintf(num, "%u", minor(udev_device_get_devnum(dev)));
135 l = strpcpy(&s, l, num);
136 break;
137 }
138 case SUBST_RESULT: {
139 char *rest;
140 int i;
141
142 if (event->program_result == NULL)
143 break;
144 /* get part of the result string */
145 i = 0;
146 if (attr != NULL)
147 i = strtoul(attr, &rest, 10);
148 if (i > 0) {
149 char result[UTIL_PATH_SIZE];
150 char tmp[UTIL_PATH_SIZE];
151 char *cpos;
152
153 strscpy(result, sizeof(result), event->program_result);
154 cpos = result;
155 while (--i) {
156 while (cpos[0] != '\0' && !isspace(cpos[0]))
157 cpos++;
158 while (isspace(cpos[0]))
159 cpos++;
160 if (cpos[0] == '\0')
161 break;
162 }
163 if (i > 0) {
164 log_error("requested part of result string not found");
165 break;
166 }
167 strscpy(tmp, sizeof(tmp), cpos);
168 /* %{2+}c copies the whole string from the second part on */
169 if (rest[0] != '+') {
170 cpos = strchr(tmp, ' ');
171 if (cpos)
172 cpos[0] = '\0';
173 }
174 l = strpcpy(&s, l, tmp);
175 } else {
176 l = strpcpy(&s, l, event->program_result);
177 }
178 break;
179 }
180 case SUBST_ATTR: {
181 const char *value = NULL;
182 char vbuf[UTIL_NAME_SIZE];
183 size_t len;
184 int count;
185
186 if (attr == NULL) {
187 log_error("missing file parameter for attr");
188 break;
189 }
190
191 /* try to read the value specified by "[dmi/id]product_name" */
755c3fe9 192 if (util_resolve_subsys_kernel(attr, vbuf, sizeof(vbuf), 1) == 0)
0d53705b
DS
193 value = vbuf;
194
195 /* try to read the attribute the device */
196 if (value == NULL)
197 value = udev_device_get_sysattr_value(event->dev, attr);
198
199 /* try to read the attribute of the parent device, other matches have selected */
200 if (value == NULL && event->dev_parent != NULL && event->dev_parent != event->dev)
201 value = udev_device_get_sysattr_value(event->dev_parent, attr);
202
203 if (value == NULL)
204 break;
205
206 /* strip trailing whitespace, and replace unwanted characters */
207 if (value != vbuf)
208 strscpy(vbuf, sizeof(vbuf), value);
209 len = strlen(vbuf);
210 while (len > 0 && isspace(vbuf[--len]))
211 vbuf[len] = '\0';
212 count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
213 if (count > 0)
214 log_debug("%i character(s) replaced" , count);
215 l = strpcpy(&s, l, vbuf);
216 break;
217 }
218 case SUBST_PARENT: {
219 struct udev_device *dev_parent;
220 const char *devnode;
221
222 dev_parent = udev_device_get_parent(event->dev);
223 if (dev_parent == NULL)
224 break;
225 devnode = udev_device_get_devnode(dev_parent);
226 if (devnode != NULL)
fbd0b64f 227 l = strpcpy(&s, l, devnode + STRLEN("/dev/"));
0d53705b
DS
228 break;
229 }
230 case SUBST_DEVNODE:
231 if (udev_device_get_devnode(dev) != NULL)
232 l = strpcpy(&s, l, udev_device_get_devnode(dev));
233 break;
234 case SUBST_NAME:
235 if (event->name != NULL)
236 l = strpcpy(&s, l, event->name);
237 else if (udev_device_get_devnode(dev) != NULL)
fbd0b64f
LP
238 l = strpcpy(&s, l,
239 udev_device_get_devnode(dev) + STRLEN("/dev/"));
0d53705b
DS
240 else
241 l = strpcpy(&s, l, udev_device_get_sysname(dev));
242 break;
243 case SUBST_LINKS: {
244 struct udev_list_entry *list_entry;
245
246 list_entry = udev_device_get_devlinks_list_entry(dev);
247 if (list_entry == NULL)
248 break;
fbd0b64f
LP
249 l = strpcpy(&s, l,
250 udev_list_entry_get_name(list_entry) + STRLEN("/dev/"));
0d53705b 251 udev_list_entry_foreach(list_entry, udev_list_entry_get_next(list_entry))
fbd0b64f
LP
252 l = strpcpyl(&s, l, " ",
253 udev_list_entry_get_name(list_entry) + STRLEN("/dev/"),
254 NULL);
0d53705b
DS
255 break;
256 }
257 case SUBST_ROOT:
258 l = strpcpy(&s, l, "/dev");
259 break;
260 case SUBST_SYS:
261 l = strpcpy(&s, l, "/sys");
262 break;
263 case SUBST_ENV:
264 if (attr == NULL) {
265 break;
266 } else {
267 const char *value;
268
269 value = udev_device_get_property_value(event->dev, attr);
270 if (value == NULL)
271 break;
272 l = strpcpy(&s, l, value);
273 break;
274 }
275 default:
276 log_error("unknown substitution type=%i", type);
277 break;
278 }
279
be452683 280 return s - dest;
0d53705b
DS
281}
282
e20a9171
DS
283size_t udev_event_apply_format(struct udev_event *event,
284 const char *src, char *dest, size_t size,
285 bool replace_whitespace) {
912541b0 286 static const struct subst_map {
04a9d3a0
KS
287 const char *name;
288 const char fmt;
912541b0
KS
289 enum subst_type type;
290 } map[] = {
3fd0c4c6
KS
291 { .name = "devnode", .fmt = 'N', .type = SUBST_DEVNODE },
292 { .name = "tempnode", .fmt = 'N', .type = SUBST_DEVNODE },
293 { .name = "attr", .fmt = 's', .type = SUBST_ATTR },
294 { .name = "sysfs", .fmt = 's', .type = SUBST_ATTR },
295 { .name = "env", .fmt = 'E', .type = SUBST_ENV },
296 { .name = "kernel", .fmt = 'k', .type = SUBST_KERNEL },
297 { .name = "number", .fmt = 'n', .type = SUBST_KERNEL_NUMBER },
298 { .name = "driver", .fmt = 'd', .type = SUBST_DRIVER },
299 { .name = "devpath", .fmt = 'p', .type = SUBST_DEVPATH },
300 { .name = "id", .fmt = 'b', .type = SUBST_ID },
301 { .name = "major", .fmt = 'M', .type = SUBST_MAJOR },
302 { .name = "minor", .fmt = 'm', .type = SUBST_MINOR },
303 { .name = "result", .fmt = 'c', .type = SUBST_RESULT },
304 { .name = "parent", .fmt = 'P', .type = SUBST_PARENT },
305 { .name = "name", .fmt = 'D', .type = SUBST_NAME },
306 { .name = "links", .fmt = 'L', .type = SUBST_LINKS },
307 { .name = "root", .fmt = 'r', .type = SUBST_ROOT },
308 { .name = "sys", .fmt = 'S', .type = SUBST_SYS },
912541b0
KS
309 };
310 const char *from;
311 char *s;
312 size_t l;
313
a368732b
YW
314 assert(event);
315 assert(event->dev);
316 assert(src);
317 assert(dest);
318 assert(size > 0);
3b64e4d4 319
912541b0
KS
320 from = src;
321 s = dest;
322 l = size;
323
324 for (;;) {
325 enum subst_type type = SUBST_UNKNOWN;
be452683
DS
326 char attrbuf[UTIL_PATH_SIZE];
327 char *attr = NULL;
328 size_t subst_len;
912541b0
KS
329
330 while (from[0] != '\0') {
331 if (from[0] == '$') {
332 /* substitute named variable */
14cb109d 333 unsigned i;
912541b0
KS
334
335 if (from[1] == '$') {
336 from++;
337 goto copy;
338 }
339
8fef0ff2 340 for (i = 0; i < ELEMENTSOF(map); i++) {
33502ffe 341 if (startswith(&from[1], map[i].name)) {
912541b0
KS
342 type = map[i].type;
343 from += strlen(map[i].name)+1;
912541b0
KS
344 goto subst;
345 }
346 }
347 } else if (from[0] == '%') {
348 /* substitute format char */
14cb109d 349 unsigned i;
912541b0
KS
350
351 if (from[1] == '%') {
352 from++;
353 goto copy;
354 }
355
8fef0ff2 356 for (i = 0; i < ELEMENTSOF(map); i++) {
912541b0
KS
357 if (from[1] == map[i].fmt) {
358 type = map[i].type;
359 from += 2;
912541b0
KS
360 goto subst;
361 }
362 }
363 }
065db052 364copy:
912541b0 365 /* copy char */
79a695f2 366 if (l < 2) /* need space for this char and the terminating NUL */
912541b0
KS
367 goto out;
368 s[0] = from[0];
369 from++;
370 s++;
371 l--;
372 }
373
374 goto out;
065db052 375subst:
912541b0
KS
376 /* extract possible $format{attr} */
377 if (from[0] == '{') {
14cb109d 378 unsigned i;
912541b0
KS
379
380 from++;
79a695f2 381 for (i = 0; from[i] != '}'; i++)
912541b0 382 if (from[i] == '\0') {
9f6445e3 383 log_error("missing closing brace for format '%s'", src);
912541b0
KS
384 goto out;
385 }
79a695f2 386
912541b0
KS
387 if (i >= sizeof(attrbuf))
388 goto out;
389 memcpy(attrbuf, from, i);
390 attrbuf[i] = '\0';
391 from += i+1;
392 attr = attrbuf;
393 } else {
394 attr = NULL;
395 }
396
a368732b 397 subst_len = subst_format_var(event, type, attr, s, l);
e20a9171 398
be452683
DS
399 /* SUBST_RESULT handles spaces itself */
400 if (replace_whitespace && type != SUBST_RESULT)
401 /* util_replace_whitespace can replace in-place,
402 * and does nothing if subst_len == 0
403 */
404 subst_len = util_replace_whitespace(s, s, subst_len);
e20a9171 405
be452683
DS
406 s += subst_len;
407 l -= subst_len;
912541b0 408 }
065db052
KS
409
410out:
79a695f2 411 assert(l >= 1);
912541b0 412 s[0] = '\0';
912541b0 413 return l;
f1128767
KS
414}
415
e81c3a4c
YW
416static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
417 Spawn *spawn = userdata;
418 char buf[4096], *p;
419 size_t size;
420 ssize_t l;
912541b0 421
e81c3a4c
YW
422 assert(spawn);
423 assert(fd == spawn->fd_stdout || fd == spawn->fd_stderr);
424 assert(!spawn->result || spawn->result_len < spawn->result_size);
425
426 if (fd == spawn->fd_stdout && spawn->result) {
427 p = spawn->result + spawn->result_len;
428 size = spawn->result_size - spawn->result_len;
429 } else {
430 p = buf;
431 size = sizeof(buf);
912541b0
KS
432 }
433
e81c3a4c
YW
434 l = read(fd, p, size - 1);
435 if (l < 0) {
436 if (errno != EAGAIN)
437 log_error_errno(errno, "Failed to read stdout of '%s': %m", spawn->cmd);
912541b0 438
e81c3a4c 439 return 0;
912541b0
KS
440 }
441
e81c3a4c
YW
442 p[l] = '\0';
443 if (fd == spawn->fd_stdout && spawn->result)
444 spawn->result_len += l;
912541b0 445
e81c3a4c
YW
446 /* Log output only if we watch stderr. */
447 if (l > 0 && spawn->fd_stderr >= 0) {
448 _cleanup_strv_free_ char **v = NULL;
449 char **q;
912541b0 450
e81c3a4c
YW
451 v = strv_split_newlines(p);
452 if (!v)
453 return 0;
912541b0 454
e81c3a4c
YW
455 STRV_FOREACH(q, v)
456 log_debug("'%s'(%s) '%s'", spawn->cmd,
457 fd == spawn->fd_stdout ? "out" : "err", *q);
912541b0
KS
458 }
459
e81c3a4c 460 return 0;
2181d30a
KS
461}
462
8128f229
TG
463static int on_spawn_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
464 Spawn *spawn = userdata;
465 char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
912541b0 466
8128f229 467 assert(spawn);
912541b0 468
8128f229 469 kill_and_sigcont(spawn->pid, SIGKILL);
912541b0 470
5ca3dbc9 471 log_error("Spawned process '%s' ["PID_FMT"] timed out after %s, killing", spawn->cmd, spawn->pid,
e81c3a4c 472 format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout_usec));
912541b0 473
8128f229
TG
474 return 1;
475}
67117413 476
8128f229
TG
477static int on_spawn_timeout_warning(sd_event_source *s, uint64_t usec, void *userdata) {
478 Spawn *spawn = userdata;
479 char timeout[FORMAT_TIMESTAMP_RELATIVE_MAX];
912541b0 480
8128f229 481 assert(spawn);
67117413 482
5ca3dbc9 483 log_warning("Spawned process '%s' ["PID_FMT"] is taking longer than %s to complete", spawn->cmd, spawn->pid,
e81c3a4c 484 format_timestamp_relative(timeout, sizeof(timeout), spawn->timeout_warn_usec));
8128f229
TG
485
486 return 1;
487}
488
489static int on_spawn_sigchld(sd_event_source *s, const siginfo_t *si, void *userdata) {
490 Spawn *spawn = userdata;
491
492 assert(spawn);
493
494 switch (si->si_code) {
495 case CLD_EXITED:
53318514
TG
496 if (si->si_status == 0) {
497 log_debug("Process '%s' succeeded.", spawn->cmd);
8128f229
TG
498 sd_event_exit(sd_event_source_get_event(s), 0);
499
500 return 1;
4e57ad35 501 }
912541b0 502
4e57ad35
YW
503 log_full(spawn->accept_failure ? LOG_DEBUG : LOG_WARNING,
504 "Process '%s' failed with exit code %i.", spawn->cmd, si->si_status);
8128f229
TG
505 break;
506 case CLD_KILLED:
507 case CLD_DUMPED:
53318514 508 log_warning("Process '%s' terminated by signal %s.", spawn->cmd, signal_to_string(si->si_status));
912541b0 509
8128f229
TG
510 break;
511 default:
53318514 512 log_error("Process '%s' failed due to unknown reason.", spawn->cmd);
8128f229 513 }
912541b0 514
8128f229
TG
515 sd_event_exit(sd_event_source_get_event(s), -EIO);
516
517 return 1;
518}
519
e81c3a4c 520static int spawn_wait(Spawn *spawn) {
4afd3348 521 _cleanup_(sd_event_unrefp) sd_event *e = NULL;
8128f229
TG
522 int r, ret;
523
e81c3a4c
YW
524 assert(spawn);
525
8128f229
TG
526 r = sd_event_new(&e);
527 if (r < 0)
528 return r;
529
e81c3a4c 530 if (spawn->timeout_usec > 0) {
8128f229
TG
531 usec_t usec, age_usec;
532
3285baa8 533 usec = now(CLOCK_MONOTONIC);
e81c3a4c
YW
534 age_usec = usec - spawn->event_birth_usec;
535 if (age_usec < spawn->timeout_usec) {
536 if (spawn->timeout_warn_usec > 0 &&
537 spawn->timeout_warn_usec < spawn->timeout_usec &&
538 spawn->timeout_warn_usec > age_usec) {
539 spawn->timeout_warn_usec -= age_usec;
8128f229 540
3285baa8 541 r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC,
e81c3a4c
YW
542 usec + spawn->timeout_warn_usec, USEC_PER_SEC,
543 on_spawn_timeout_warning, spawn);
8128f229
TG
544 if (r < 0)
545 return r;
912541b0 546 }
8128f229 547
e81c3a4c 548 spawn->timeout_usec -= age_usec;
8128f229 549
3285baa8 550 r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC,
e81c3a4c 551 usec + spawn->timeout_usec, USEC_PER_SEC, on_spawn_timeout, spawn);
8128f229
TG
552 if (r < 0)
553 return r;
912541b0
KS
554 }
555 }
8128f229 556
e81c3a4c
YW
557 r = sd_event_add_io(e, NULL, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn);
558 if (r < 0)
559 return r;
560
561 r = sd_event_add_io(e, NULL, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn);
562 if (r < 0)
563 return r;
564
565 r = sd_event_add_child(e, NULL, spawn->pid, WEXITED, on_spawn_sigchld, spawn);
8128f229
TG
566 if (r < 0)
567 return r;
568
569 r = sd_event_loop(e);
570 if (r < 0)
571 return r;
572
573 r = sd_event_get_exit_code(e, &ret);
574 if (r < 0)
575 return r;
576
577 return ret;
2181d30a
KS
578}
579
580int udev_event_spawn(struct udev_event *event,
dd5eddd2 581 usec_t timeout_usec,
67117413 582 usec_t timeout_warn_usec,
53318514 583 bool accept_failure,
bbf35206 584 const char *cmd,
dd5eddd2 585 char *result, size_t ressize) {
feaa6db7
YW
586 _cleanup_close_pair_ int outpipe[2] = {-1, -1}, errpipe[2] = {-1, -1};
587 _cleanup_strv_free_ char **argv = NULL;
947ce772 588 char **envp = NULL;
e81c3a4c 589 Spawn spawn;
912541b0 590 pid_t pid;
feaa6db7 591 int r;
912541b0 592
dc8aec36
YW
593 assert(event);
594 assert(event->dev);
e81c3a4c
YW
595 assert(result || ressize == 0);
596
912541b0 597 /* pipes from child to parent */
2e48548f 598 if (result || log_get_max_level() >= LOG_INFO)
f71e8ec1 599 if (pipe2(outpipe, O_NONBLOCK|O_CLOEXEC) != 0)
feaa6db7 600 return log_error_errno(errno, "Failed to create pipe for command '%s': %m", cmd);
912541b0 601
feaa6db7 602 if (log_get_max_level() >= LOG_INFO)
f71e8ec1 603 if (pipe2(errpipe, O_NONBLOCK|O_CLOEXEC) != 0)
feaa6db7
YW
604 return log_error_errno(errno, "Failed to create pipe for command '%s': %m", cmd);
605
606 argv = strv_split_full(cmd, NULL, SPLIT_QUOTES|SPLIT_RELAX);
607 if (!argv)
608 return log_oom();
609
dc8aec36
YW
610 if (isempty(argv[0])) {
611 log_error("Invalid command '%s'", cmd);
612 return -EINVAL;
613 }
614
feaa6db7
YW
615 /* allow programs in /usr/lib/udev/ to be called without the path */
616 if (!path_is_absolute(argv[0])) {
617 char *program;
618
619 program = path_join(NULL, UDEVLIBEXECDIR, argv[0]);
620 if (!program)
621 return log_oom();
bbf35206 622
feaa6db7
YW
623 free_and_replace(argv[0], program);
624 }
625
947ce772
YW
626 r = device_get_properties_strv(event->dev->device, &envp);
627 if (r < 0)
e9343893 628 return log_device_error_errno(event->dev->device, r, "Failed to get device properties");
947ce772 629
3ad4d482
YW
630 log_debug("Starting '%s'", cmd);
631
6ce075a2 632 r = safe_fork("(spawn)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
feaa6db7
YW
633 if (r < 0)
634 return log_error_errno(r, "Failed to fork() to execute command '%s': %m", cmd);
635 if (r == 0) {
84b1ccb9
YW
636 if (rearrange_stdio(-1, outpipe[WRITE_END], errpipe[WRITE_END]) < 0)
637 _exit(EXIT_FAILURE);
912541b0 638
84b1ccb9 639 (void) close_all_fds(NULL, 0);
912541b0 640
947ce772 641 execve(argv[0], argv, envp);
84b1ccb9 642 _exit(EXIT_FAILURE);
bbf35206 643 }
912541b0 644
4c253ed1
LP
645 /* parent closed child's ends of pipes */
646 outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
647 errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
912541b0 648
e81c3a4c
YW
649 spawn = (Spawn) {
650 .cmd = cmd,
651 .pid = pid,
652 .accept_failure = accept_failure,
653 .timeout_warn_usec = timeout_warn_usec,
654 .timeout_usec = timeout_usec,
655 .event_birth_usec = event->birth_usec,
656 .fd_stdout = outpipe[READ_END],
657 .fd_stderr = errpipe[READ_END],
658 .result = result,
659 .result_size = ressize,
660 };
661 r = spawn_wait(&spawn);
feaa6db7
YW
662 if (r < 0)
663 return log_error_errno(r, "Failed to wait spawned command '%s': %m", cmd);
2181d30a 664
e81c3a4c
YW
665 if (result)
666 result[spawn.result_len] = '\0';
667
feaa6db7 668 return r;
2181d30a
KS
669}
670
9ec6e95b 671static int rename_netif(struct udev_event *event) {
912541b0 672 struct udev_device *dev = event->dev;
16d26d55
TG
673 char name[IFNAMSIZ];
674 const char *oldname;
675 int r;
676
677 oldname = udev_device_get_sysname(dev);
912541b0 678
16d26d55 679 strscpy(name, IFNAMSIZ, event->name);
912541b0 680
4c83d994 681 r = rtnl_set_link_name(&event->rtnl, udev_device_get_ifindex(dev), name);
f647962d
MS
682 if (r < 0)
683 return log_error_errno(r, "Error changing net interface name '%s' to '%s': %m", oldname, name);
16d26d55 684
ff49bc32 685 log_debug("renamed network interface '%s' to '%s'", oldname, name);
16d26d55 686
4c83d994 687 return 0;
d46f37fd
KS
688}
689
dd5eddd2 690void udev_event_execute_rules(struct udev_event *event,
adeba500 691 usec_t timeout_usec, usec_t timeout_warn_usec,
9b5150b6 692 Hashmap *properties_list,
8314de1d 693 struct udev_rules *rules) {
912541b0 694 struct udev_device *dev = event->dev;
912541b0
KS
695
696 if (udev_device_get_subsystem(dev) == NULL)
1ea97217 697 return;
912541b0 698
090be865 699 if (streq(udev_device_get_action(dev), "remove")) {
107f2e25
TG
700 udev_device_read_db(dev);
701 udev_device_tag_index(dev, NULL, false);
702 udev_device_delete_db(dev);
703
912541b0 704 if (major(udev_device_get_devnum(dev)) != 0)
70068602 705 udev_watch_end(dev->device);
912541b0 706
adeba500
KS
707 udev_rules_apply_to_event(rules, event,
708 timeout_usec, timeout_warn_usec,
8314de1d 709 properties_list);
912541b0
KS
710
711 if (major(udev_device_get_devnum(dev)) != 0)
a2554ace 712 udev_node_remove(dev->device);
912541b0 713 } else {
8f0f13f0 714 event->dev_db = udev_device_clone_with_db(dev);
912541b0 715 if (event->dev_db != NULL) {
912541b0
KS
716 /* disable watch during event processing */
717 if (major(udev_device_get_devnum(dev)) != 0)
70068602 718 udev_watch_end(event->dev_db->device);
912541b0 719
9eba69df
ZJS
720 if (major(udev_device_get_devnum(dev)) == 0 &&
721 streq(udev_device_get_action(dev), "move"))
722 udev_device_copy_properties(dev, event->dev_db);
723 }
b081b27e 724
adeba500
KS
725 udev_rules_apply_to_event(rules, event,
726 timeout_usec, timeout_warn_usec,
8314de1d 727 properties_list);
912541b0
KS
728
729 /* rename a new network interface, if needed */
090be865
TA
730 if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") &&
731 event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) {
1ea97217 732 int r;
912541b0 733
1ea97217 734 r = rename_netif(event);
243d1825
TG
735 if (r < 0)
736 log_warning_errno(r, "could not rename interface '%d' from '%s' to '%s': %m", udev_device_get_ifindex(dev),
737 udev_device_get_sysname(dev), event->name);
738 else {
243d1825
TG
739 r = udev_device_rename(dev, event->name);
740 if (r < 0)
741 log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m",
742 udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name);
3738cc85 743 else
9f6445e3 744 log_debug("changed devpath to '%s'", udev_device_get_devpath(dev));
912541b0
KS
745 }
746 }
747
b0a00806 748 if (major(udev_device_get_devnum(dev)) > 0) {
9a8ae49d
KS
749 bool apply;
750
912541b0
KS
751 /* remove/update possible left-over symlinks from old database entry */
752 if (event->dev_db != NULL)
a2554ace 753 udev_node_update_old_links(dev->device, event->dev_db->device);
912541b0 754
1edefa4f
KS
755 if (!event->owner_set)
756 event->uid = udev_device_get_devnode_uid(dev);
757
758 if (!event->group_set)
759 event->gid = udev_device_get_devnode_gid(dev);
760
912541b0
KS
761 if (!event->mode_set) {
762 if (udev_device_get_devnode_mode(dev) > 0) {
763 /* kernel supplied value */
764 event->mode = udev_device_get_devnode_mode(dev);
765 } else if (event->gid > 0) {
766 /* default 0660 if a group is assigned */
767 event->mode = 0660;
768 } else {
769 /* default 0600 */
770 event->mode = 0600;
771 }
772 }
773
9a8ae49d 774 apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set;
d838e145 775 udev_node_add(dev->device, apply, event->mode, event->uid, event->gid, event->seclabel_list);
912541b0
KS
776 }
777
778 /* preserve old, or get new initialization timestamp */
1b14c3cf 779 udev_device_ensure_usec_initialized(event->dev, event->dev_db);
912541b0
KS
780
781 /* (re)write database file */
912541b0 782 udev_device_tag_index(dev, event->dev_db, true);
353f6058 783 udev_device_update_db(dev);
912541b0
KS
784 udev_device_set_is_initialized(dev);
785
353f6058 786 event->dev_db = udev_device_unref(event->dev_db);
912541b0 787 }
d46f37fd 788}
2d73813e 789
8314de1d 790void udev_event_execute_run(struct udev_event *event, usec_t timeout_usec, usec_t timeout_warn_usec) {
29448498
YW
791 const char *cmd;
792 void *val;
793 Iterator i;
912541b0 794
29448498
YW
795 HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) {
796 enum udev_builtin_cmd builtin_cmd = PTR_TO_INT(val);
bbf35206 797 char command[UTIL_PATH_SIZE];
83cd6b75 798
e20a9171 799 udev_event_apply_format(event, cmd, command, sizeof(command), false);
912541b0 800
c45b369d 801 if (builtin_cmd >= 0 && builtin_cmd < _UDEV_BUILTIN_MAX)
3d6194e8 802 udev_builtin_run(event->dev->device, builtin_cmd, command, false);
bbf35206 803 else {
912541b0 804 if (event->exec_delay > 0) {
bbf35206 805 log_debug("delay execution of '%s'", command);
912541b0
KS
806 sleep(event->exec_delay);
807 }
808
bbf35206 809 udev_event_spawn(event, timeout_usec, timeout_warn_usec, false, command, NULL, 0);
912541b0
KS
810 }
811 }
2d73813e 812}