]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-aux-scope.c
pidfd: properly detect if libc offers pidfd syscalls and make use of them then
[thirdparty/systemd.git] / src / test / test-aux-scope.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <errno.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #if HAVE_PIDFD_OPEN
7 #include <sys/pidfd.h>
8 #endif
9 #include <sys/wait.h>
10
11 #include "sd-event.h"
12
13 #include "bus-error.h"
14 #include "bus-message.h"
15 #include "bus-wait-for-jobs.h"
16 #include "daemon-util.h"
17 #include "fd-util.h"
18 #include "log.h"
19 #include "missing_syscall.h"
20 #include "process-util.h"
21 #include "tests.h"
22
23 static int on_sigusr1(sd_event_source *s, const struct signalfd_siginfo *ssi, void *userdata) {
24 _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL, *reply = NULL;
25 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
26 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
27 _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
28 PidRef *pids = (PidRef *) userdata;
29 const char *job;
30 int r;
31
32 assert(pids);
33
34 r = sd_bus_open_system(&bus);
35 if (r < 0)
36 return log_error_errno(r, "Failed to acquire bus: %m");
37
38 r = sd_bus_message_new_method_call(bus, &message,
39 "org.freedesktop.systemd1",
40 "/org/freedesktop/systemd1",
41 "org.freedesktop.systemd1.Manager",
42 "StartAuxiliaryScope");
43 if (r < 0)
44 return log_error_errno(r, "Failed to create bus message: %m");
45
46 r = sd_bus_message_append_basic(message, 's', "test-aux-scope.scope");
47 if (r < 0)
48 return log_error_errno(r, "Failed to attach scope name: %m");
49
50 r = sd_bus_message_open_container(message, 'a', "h");
51 if (r < 0)
52 return log_error_errno(r, "Failed to create array of FDs: %m");
53
54 for (size_t i = 0; i < 10; i++) {
55 r = sd_bus_message_append_basic(message, 'h', &pids[i].fd);
56 if (r < 0)
57 return log_error_errno(r, "Failed to append PIDFD to message: %m");
58 }
59
60 r = sd_bus_message_close_container(message);
61 if (r < 0)
62 return log_error_errno(r, "Failed to close container: %m");
63
64 r = sd_bus_message_append(message, "ta(sv)", UINT64_C(0), 1, "Description", "s", "Test auxiliary scope");
65 if (r < 0)
66 return log_error_errno(r, "Failed to append unit properties: %m");
67
68 r = sd_bus_call(bus, message, 0, &error, &reply);
69 if (r < 0)
70 return log_error_errno(r, "Failed to start auxiliary scope: %s", bus_error_message(&error, r));
71
72 r = sd_bus_message_read(reply, "o", &job);
73 if (r < 0)
74 return log_error_errno(r, "Failed to read reply: %m");
75
76 r = bus_wait_for_jobs_new(bus, &w);
77 if (r < 0)
78 return log_error_errno(r, "Could not watch jobs: %m");
79
80 r = bus_wait_for_jobs_one(w, job, false, NULL);
81 if (r < 0)
82 return r;
83
84 return 0;
85 }
86
87 static void destroy_pidrefs(PidRef *pids, size_t npids) {
88 assert(pids || npids == 0);
89
90 for (size_t i = 0; i < npids; i++)
91 pidref_done(&pids[i]);
92
93 free(pids);
94 }
95
96 int main(int argc, char *argv[]) {
97 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
98 PidRef *pids = NULL;
99 size_t npids = 0;
100 int r, fd;
101
102 CLEANUP_ARRAY(pids, npids, destroy_pidrefs);
103
104 test_setup_logging(LOG_INFO);
105
106 fd = pidfd_open(getpid_cached(), 0);
107 if (fd < 0 && (ERRNO_IS_NOT_SUPPORTED(errno) || ERRNO_IS_PRIVILEGE(errno)))
108 return log_tests_skipped("pidfds are not available");
109 else if (fd < 0) {
110 log_error_errno(errno, "pidfd_open() failed: %m");
111 return EXIT_FAILURE;
112 }
113 safe_close(fd);
114
115 r = sd_event_new(&event);
116 if (r < 0) {
117 log_error_errno(r, "Failed to allocate event loop: %m");
118 return EXIT_FAILURE;
119 }
120
121 npids = 10;
122 pids = new0(PidRef, npids);
123 assert(pids);
124
125 r = sd_event_add_signal(event, NULL, SIGUSR1|SD_EVENT_SIGNAL_PROCMASK, on_sigusr1, pids);
126 if (r < 0) {
127 log_error_errno(r, "Failed to setup SIGUSR1 signal handling: %m");
128 return EXIT_FAILURE;
129 }
130
131 for (size_t i = 0; i < npids; i++) {
132 PidRef pidref = PIDREF_NULL;
133 pid_t pid;
134
135 r = safe_fork("(worker)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_CLOSE_ALL_FDS, &pid);
136 if (r < 0) {
137 log_error_errno(r, "Failed to fork(): %m");
138 return EXIT_FAILURE;
139 }
140
141 if (r == 0) {
142 /* Worker */
143 sleep(3600);
144 _exit(EXIT_SUCCESS);
145 }
146
147 r = pidref_set_pid(&pidref, pid);
148 if (r < 0) {
149 log_error_errno(r, "Failed to initialize PID ref: %m");
150 return EXIT_FAILURE;
151 }
152
153 assert_se(pidref.pid == pid);
154 assert_se(pidref.fd != -EBADF);
155
156 pids[i] = TAKE_PIDREF(pidref);
157 }
158
159 r = sd_notify(false, NOTIFY_READY);
160 if (r < 0)
161 return log_error_errno(r, "Failed to send readiness notification: %m");
162
163 r = sd_event_loop(event);
164 if (r < 0)
165 return log_error_errno(r, "Failed to run event loop: %m");
166
167 return 0;
168 }