]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-udev.c
Merge pull request #10594 from poettering/env-reload-fix
[thirdparty/systemd.git] / src / test / test-udev.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 Copyright © 2003-2004 Greg Kroah-Hartman <greg@kroah.com>
4 ***/
5
6 #include <errno.h>
7 #include <sched.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/mount.h>
11 #include <sys/signalfd.h>
12 #include <unistd.h>
13
14 #include "device-private.h"
15 #include "fs-util.h"
16 #include "log.h"
17 #include "missing.h"
18 #include "selinux-util.h"
19 #include "signal-util.h"
20 #include "string-util.h"
21 #include "tests.h"
22 #include "udev.h"
23
24 static int fake_filesystems(void) {
25 static const struct fakefs {
26 const char *src;
27 const char *target;
28 const char *error;
29 bool ignore_mount_error;
30 } fakefss[] = {
31 { "test/tmpfs/sys", "/sys", "Failed to mount test /sys", false },
32 { "test/tmpfs/dev", "/dev", "Failed to mount test /dev", false },
33 { "test/run", "/run", "Failed to mount test /run", false },
34 { "test/run", "/etc/udev/rules.d", "Failed to mount empty /etc/udev/rules.d", true },
35 { "test/run", UDEVLIBEXECDIR "/rules.d", "Failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
36 };
37 unsigned i;
38
39 if (unshare(CLONE_NEWNS) < 0)
40 return log_error_errno(errno, "Failed to call unshare(): %m");
41
42 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
43 return log_error_errno(errno, "Failed to mount / as private: %m");
44
45 for (i = 0; i < ELEMENTSOF(fakefss); i++)
46 if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
47 log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
48 if (!fakefss[i].ignore_mount_error)
49 return -errno;
50 }
51
52 return 0;
53 }
54
55 int main(int argc, char *argv[]) {
56 _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL;
57 _cleanup_(udev_event_freep) struct udev_event *event = NULL;
58 _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
59 const char *devpath, *devname, *action;
60 int r;
61
62 test_setup_logging(LOG_INFO);
63
64 if (argc != 3) {
65 log_error("This program needs two arguments, %d given", argc - 1);
66 return EXIT_FAILURE;
67 }
68
69 if (fake_filesystems() < 0)
70 return EXIT_FAILURE;
71
72 log_debug("version %s", PACKAGE_VERSION);
73 mac_selinux_init();
74
75 action = argv[1];
76 devpath = argv[2];
77
78 rules = udev_rules_new(1);
79
80 const char *syspath = strjoina("/sys", devpath);
81 r = device_new_from_synthetic_event(&dev, syspath, action);
82 if (r < 0) {
83 log_debug_errno(r, "Failed to open device '%s'", devpath);
84 goto out;
85 }
86
87 assert_se(event = udev_event_new(dev, 0, NULL));
88
89 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
90
91 /* do what devtmpfs usually provides us */
92 if (sd_device_get_devname(dev, &devname) >= 0) {
93 const char *subsystem;
94 mode_t mode = 0600;
95
96 if (sd_device_get_subsystem(dev, &subsystem) >= 0 && streq(subsystem, "block"))
97 mode |= S_IFBLK;
98 else
99 mode |= S_IFCHR;
100
101 if (!streq(action, "remove")) {
102 dev_t devnum = makedev(0, 0);
103
104 (void) mkdir_parents_label(devname, 0755);
105 (void) sd_device_get_devnum(dev, &devnum);
106 assert_se(mknod(devname, mode, devnum) == 0);
107 } else {
108 assert_se(unlink(devname) == 0);
109 (void) rmdir_parents(devname, "/");
110 }
111 }
112
113 udev_event_execute_rules(event, 3 * USEC_PER_SEC, USEC_PER_SEC, NULL, rules);
114 udev_event_execute_run(event, 3 * USEC_PER_SEC, USEC_PER_SEC);
115 out:
116 mac_selinux_finish();
117
118 return EXIT_SUCCESS;
119 }