]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-udev.c
Merge pull request #9832 from yuwata/fix-9831
[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 "fs-util.h"
15 #include "log.h"
16 #include "missing.h"
17 #include "selinux-util.h"
18 #include "signal-util.h"
19 #include "string-util.h"
20 #include "udev.h"
21
22 static int fake_filesystems(void) {
23 static const struct fakefs {
24 const char *src;
25 const char *target;
26 const char *error;
27 bool ignore_mount_error;
28 } fakefss[] = {
29 { "test/tmpfs/sys", "/sys", "failed to mount test /sys", false },
30 { "test/tmpfs/dev", "/dev", "failed to mount test /dev", false },
31 { "test/run", "/run", "failed to mount test /run", false },
32 { "test/run", "/etc/udev/rules.d", "failed to mount empty /etc/udev/rules.d", true },
33 { "test/run", UDEVLIBEXECDIR "/rules.d", "failed to mount empty " UDEVLIBEXECDIR "/rules.d", true },
34 };
35 unsigned int i;
36
37 if (unshare(CLONE_NEWNS) < 0)
38 return log_error_errno(errno, "failed to call unshare(): %m");
39
40 if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
41 return log_error_errno(errno, "failed to mount / as private: %m");
42
43 for (i = 0; i < ELEMENTSOF(fakefss); i++) {
44 if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) {
45 log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error);
46 if (!fakefss[i].ignore_mount_error)
47 return -errno;
48 }
49 }
50
51 return 0;
52 }
53
54 int main(int argc, char *argv[]) {
55 _cleanup_(udev_unrefp) struct udev *udev = NULL;
56 _cleanup_(udev_event_unrefp) struct udev_event *event = NULL;
57 _cleanup_(udev_device_unrefp) struct udev_device *dev = NULL;
58 _cleanup_(udev_rules_unrefp) struct udev_rules *rules = NULL;
59 char syspath[UTIL_PATH_SIZE];
60 const char *devpath;
61 const char *action;
62 int err;
63
64 log_parse_environment();
65 log_open();
66
67 err = fake_filesystems();
68 if (err < 0)
69 return EXIT_FAILURE;
70
71 udev = udev_new();
72 if (udev == NULL)
73 return EXIT_FAILURE;
74
75 log_debug("version %s", PACKAGE_VERSION);
76 mac_selinux_init();
77
78 action = argv[1];
79 if (action == NULL) {
80 log_error("action missing");
81 goto out;
82 }
83
84 devpath = argv[2];
85 if (devpath == NULL) {
86 log_error("devpath missing");
87 goto out;
88 }
89
90 rules = udev_rules_new(udev, 1);
91
92 strscpyl(syspath, sizeof(syspath), "/sys", devpath, NULL);
93 dev = udev_device_new_from_synthetic_event(udev, syspath, action);
94 if (dev == NULL) {
95 log_debug("unknown device '%s'", devpath);
96 goto out;
97 }
98
99 event = udev_event_new(dev);
100
101 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0);
102
103 /* do what devtmpfs usually provides us */
104 if (udev_device_get_devnode(dev) != NULL) {
105 mode_t mode = 0600;
106
107 if (streq(udev_device_get_subsystem(dev), "block"))
108 mode |= S_IFBLK;
109 else
110 mode |= S_IFCHR;
111
112 if (!streq(action, "remove")) {
113 mkdir_parents_label(udev_device_get_devnode(dev), 0755);
114 mknod(udev_device_get_devnode(dev), mode, udev_device_get_devnum(dev));
115 } else {
116 unlink(udev_device_get_devnode(dev));
117 rmdir_parents(udev_device_get_devnode(dev), "/");
118 }
119 }
120
121 udev_event_execute_rules(event,
122 3 * USEC_PER_SEC, USEC_PER_SEC,
123 NULL,
124 rules);
125 udev_event_execute_run(event,
126 3 * USEC_PER_SEC, USEC_PER_SEC);
127 out:
128 mac_selinux_finish();
129
130 return err ? EXIT_FAILURE : EXIT_SUCCESS;
131 }