]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
1298001e | 2 | /*** |
96b2fb93 | 3 | Copyright © 2003-2004 Greg Kroah-Hartman <greg@kroah.com> |
1298001e | 4 | ***/ |
f0083e3d | 5 | |
c81b35c0 | 6 | #include <errno.h> |
4cb72937 | 7 | #include <sched.h> |
07630cea LP |
8 | #include <stdio.h> |
9 | #include <stdlib.h> | |
4cb72937 | 10 | #include <sys/mount.h> |
2181d30a | 11 | #include <sys/signalfd.h> |
07630cea | 12 | #include <unistd.h> |
85511f02 | 13 | |
681bd2c5 | 14 | #include "build.h" |
b74a0b6a | 15 | #include "device-private.h" |
f4f15635 | 16 | #include "fs-util.h" |
dbab702a | 17 | #include "log.h" |
8d38b8ad | 18 | #include "main-func.h" |
10efe2cd | 19 | #include "missing.h" |
5ea78a39 | 20 | #include "mkdir.h" |
d7b8eec7 | 21 | #include "selinux-util.h" |
8314de1d | 22 | #include "signal-util.h" |
07630cea | 23 | #include "string-util.h" |
465815aa | 24 | #include "tests.h" |
07630cea | 25 | #include "udev.h" |
f0083e3d | 26 | |
4cb72937 KS |
27 | static int fake_filesystems(void) { |
28 | static const struct fakefs { | |
29 | const char *src; | |
30 | const char *target; | |
31 | const char *error; | |
ad43ccb0 | 32 | bool ignore_mount_error; |
4cb72937 | 33 | } fakefss[] = { |
465815aa ZJS |
34 | { "test/tmpfs/sys", "/sys", "Failed to mount test /sys", false }, |
35 | { "test/tmpfs/dev", "/dev", "Failed to mount test /dev", false }, | |
36 | { "test/run", "/run", "Failed to mount test /run", false }, | |
37 | { "test/run", "/etc/udev/rules.d", "Failed to mount empty /etc/udev/rules.d", true }, | |
38 | { "test/run", UDEVLIBEXECDIR "/rules.d", "Failed to mount empty " UDEVLIBEXECDIR "/rules.d", true }, | |
4cb72937 | 39 | }; |
465815aa | 40 | unsigned i; |
4cb72937 | 41 | |
dbab702a | 42 | if (unshare(CLONE_NEWNS) < 0) |
465815aa | 43 | return log_error_errno(errno, "Failed to call unshare(): %m"); |
04eaa668 | 44 | |
74bf45bb | 45 | if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) |
465815aa | 46 | return log_error_errno(errno, "Failed to mount / as private: %m"); |
4cb72937 | 47 | |
465815aa | 48 | for (i = 0; i < ELEMENTSOF(fakefss); i++) |
dbab702a EV |
49 | if (mount(fakefss[i].src, fakefss[i].target, NULL, MS_BIND, NULL) < 0) { |
50 | log_full_errno(fakefss[i].ignore_mount_error ? LOG_DEBUG : LOG_ERR, errno, "%s: %m", fakefss[i].error); | |
ad43ccb0 | 51 | if (!fakefss[i].ignore_mount_error) |
dbab702a | 52 | return -errno; |
4cb72937 | 53 | } |
dbab702a EV |
54 | |
55 | return 0; | |
4cb72937 KS |
56 | } |
57 | ||
8d38b8ad | 58 | static int run(int argc, char *argv[]) { |
9a07157d | 59 | _cleanup_(udev_rules_freep) UdevRules *rules = NULL; |
2e088715 | 60 | _cleanup_(udev_event_freep) UdevEvent *event = NULL; |
b74a0b6a YW |
61 | _cleanup_(sd_device_unrefp) sd_device *dev = NULL; |
62 | const char *devpath, *devname, *action; | |
63 | int r; | |
4cb72937 | 64 | |
465815aa | 65 | test_setup_logging(LOG_INFO); |
dbab702a | 66 | |
110a1320 EV |
67 | if (!IN_SET(argc, 2, 3)) { |
68 | log_error("This program needs one or two arguments, %d given", argc - 1); | |
8d38b8ad | 69 | return -EINVAL; |
ac1a3726 ZJS |
70 | } |
71 | ||
8d38b8ad ZJS |
72 | r = fake_filesystems(); |
73 | if (r < 0) | |
74 | return r; | |
912541b0 | 75 | |
acc1bc99 YW |
76 | if (argc == 2) { |
77 | if (!streq(argv[1], "check")) { | |
78 | log_error("Unknown argument: %s", argv[1]); | |
8d38b8ad | 79 | return -EINVAL; |
acc1bc99 YW |
80 | } |
81 | ||
8d38b8ad | 82 | return 0; |
acc1bc99 | 83 | } |
110a1320 | 84 | |
681bd2c5 | 85 | log_debug("version %s", GIT_VERSION); |
c3dacc8b | 86 | mac_selinux_init(); |
912541b0 | 87 | |
912541b0 | 88 | action = argv[1]; |
912541b0 | 89 | devpath = argv[2]; |
912541b0 | 90 | |
1d791281 | 91 | assert_se(udev_rules_new(&rules, RESOLVE_NAME_EARLY) == 0); |
912541b0 | 92 | |
465815aa | 93 | const char *syspath = strjoina("/sys", devpath); |
b74a0b6a | 94 | r = device_new_from_synthetic_event(&dev, syspath, action); |
8d38b8ad ZJS |
95 | if (r < 0) |
96 | return log_debug_errno(r, "Failed to open device '%s'", devpath); | |
912541b0 | 97 | |
b74a0b6a | 98 | assert_se(event = udev_event_new(dev, 0, NULL)); |
912541b0 | 99 | |
72c0a2c2 | 100 | assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0); |
912541b0 KS |
101 | |
102 | /* do what devtmpfs usually provides us */ | |
b74a0b6a YW |
103 | if (sd_device_get_devname(dev, &devname) >= 0) { |
104 | const char *subsystem; | |
83cd6b75 | 105 | mode_t mode = 0600; |
912541b0 | 106 | |
b74a0b6a | 107 | if (sd_device_get_subsystem(dev, &subsystem) >= 0 && streq(subsystem, "block")) |
912541b0 KS |
108 | mode |= S_IFBLK; |
109 | else | |
110 | mode |= S_IFCHR; | |
111 | ||
090be865 | 112 | if (!streq(action, "remove")) { |
b74a0b6a YW |
113 | dev_t devnum = makedev(0, 0); |
114 | ||
115 | (void) mkdir_parents_label(devname, 0755); | |
116 | (void) sd_device_get_devnum(dev, &devnum); | |
a680beb2 AB |
117 | if (mknod(devname, mode, devnum) < 0) |
118 | return log_error_errno(errno, "mknod() failed for '%s': %m", devname); | |
912541b0 | 119 | } else { |
a680beb2 AB |
120 | if (unlink(devname) < 0) |
121 | return log_error_errno(errno, "unlink('%s') failed: %m", devname); | |
b74a0b6a | 122 | (void) rmdir_parents(devname, "/"); |
912541b0 KS |
123 | } |
124 | } | |
125 | ||
66f737b4 ZJS |
126 | udev_event_execute_rules(event, 3 * USEC_PER_SEC, NULL, rules); |
127 | udev_event_execute_run(event, 3 * USEC_PER_SEC); | |
1ca208fb | 128 | |
8d38b8ad | 129 | return 0; |
f0083e3d | 130 | } |
8d38b8ad ZJS |
131 | |
132 | DEFINE_MAIN_FUNCTION(run); |