]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/executor.c
fd-uitl: rename PIPE_EBADF → EBADF_PAIR, and add EBADF_TRIPLET
[thirdparty/systemd.git] / src / core / executor.c
CommitLineData
bb5232b6
LB
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include <getopt.h>
4#include <unistd.h>
5
6#include "sd-messages.h"
7
8#include "alloc-util.h"
9#include "build.h"
75689fb2 10#include "exec-invoke.h"
bb5232b6
LB
11#include "execute-serialize.h"
12#include "execute.h"
13#include "exit-status.h"
14#include "fdset.h"
15#include "fd-util.h"
16#include "fileio.h"
17#include "getopt-defs.h"
18#include "parse-util.h"
19#include "pretty-print.h"
20#include "static-destruct.h"
21
22static FILE* arg_serialization = NULL;
23
24STATIC_DESTRUCTOR_REGISTER(arg_serialization, fclosep);
25
26static int help(void) {
27 _cleanup_free_ char *link = NULL;
28 int r;
29
30 r = terminal_urlify_man("systemd", "1", &link);
31 if (r < 0)
32 return log_oom();
33
34 printf("%s [OPTIONS...]\n\n"
35 "%sSandbox and execute processes.%s\n\n"
36 " -h --help Show this help and exit\n"
37 " --version Print version string and exit\n"
38 " --log-target=TARGET Set log target (console, journal,\n"
39 " journal-or-kmsg,\n"
40 " kmsg, null)\n"
41 " --log-level=LEVEL Set log level (debug, info, notice,\n"
42 " warning, err, crit,\n"
43 " alert, emerg)\n"
44 " --log-color=BOOL Highlight important messages\n"
45 " --log-location=BOOL Include code location in messages\n"
46 " --log-time=BOOL Prefix messages with current time\n"
47 " --deserialize=FD Deserialize process config from FD\n"
48 "\nSee the %s for details.\n",
49 program_invocation_short_name,
50 ansi_highlight(),
51 ansi_normal(),
52 link);
53
54 return 0;
55}
56
57static int parse_argv(int argc, char *argv[]) {
58 enum {
59 COMMON_GETOPT_ARGS,
60 ARG_VERSION,
61 ARG_DESERIALIZE,
62 };
63
64 static const struct option options[] = {
65 { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
66 { "log-target", required_argument, NULL, ARG_LOG_TARGET },
67 { "log-color", required_argument, NULL, ARG_LOG_COLOR },
68 { "log-location", required_argument, NULL, ARG_LOG_LOCATION },
69 { "log-time", required_argument, NULL, ARG_LOG_TIME },
70 { "help", no_argument, NULL, 'h' },
71 { "version", no_argument, NULL, ARG_VERSION },
72 { "deserialize", required_argument, NULL, ARG_DESERIALIZE },
73 {}
74 };
75
76 int c, r;
77
78 assert(argc >= 0);
79 assert(argv);
80
81 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
82 switch (c) {
83 case 'h':
84 return help();
85
86 case ARG_VERSION:
87 return version();
88
89 case ARG_LOG_LEVEL:
90 r = log_set_max_level_from_string(optarg);
91 if (r < 0)
92 return log_error_errno(r, "Failed to parse log level \"%s\": %m", optarg);
93
94 break;
95
96 case ARG_LOG_TARGET:
97 r = log_set_target_from_string(optarg);
98 if (r < 0)
99 return log_error_errno(r, "Failed to parse log target \"%s\": %m", optarg);
100
101 break;
102
103 case ARG_LOG_COLOR:
104 r = log_show_color_from_string(optarg);
105 if (r < 0)
106 return log_error_errno(
107 r,
108 "Failed to parse log color setting \"%s\": %m",
109 optarg);
110
111 break;
112
113 case ARG_LOG_LOCATION:
114 r = log_show_location_from_string(optarg);
115 if (r < 0)
116 return log_error_errno(
117 r,
118 "Failed to parse log location setting \"%s\": %m",
119 optarg);
120
121 break;
122
123 case ARG_LOG_TIME:
124 r = log_show_time_from_string(optarg);
125 if (r < 0)
126 return log_error_errno(
127 r,
128 "Failed to parse log time setting \"%s\": %m",
129 optarg);
130
131 break;
132
133 case ARG_DESERIALIZE: {
134 FILE *f;
135 int fd;
136
137 fd = parse_fd(optarg);
138 if (fd < 0)
139 return log_error_errno(
140 fd,
141 "Failed to parse serialization fd \"%s\": %m",
142 optarg);
143
144 r = fd_cloexec(fd, /* cloexec= */ true);
145 if (r < 0)
146 return log_error_errno(
147 r,
148 "Failed to set serialization fd \"%s\" to close-on-exec: %m",
149 optarg);
150
151 f = fdopen(fd, "r");
152 if (!f)
153 return log_error_errno(errno, "Failed to open serialization fd %d: %m", fd);
154
155 safe_fclose(arg_serialization);
156 arg_serialization = f;
157
158 break;
159 }
160
161 case '?':
162 return -EINVAL;
163
164 default:
165 assert_not_reached();
166 }
167
168 if (!arg_serialization)
169 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
170 "No serialization fd specified.");
171
172 return 1 /* work to do */;
173}
174
175int main(int argc, char *argv[]) {
176 _cleanup_fdset_free_ FDSet *fdset = NULL;
177 int exit_status = EXIT_SUCCESS, r;
178 _cleanup_(cgroup_context_done) CGroupContext cgroup_context = {};
179 _cleanup_(exec_context_done) ExecContext context = {};
180 _cleanup_(exec_command_done) ExecCommand command = {};
181 _cleanup_(exec_params_serialized_done) ExecParameters params = EXEC_PARAMETERS_INIT(/* flags= */ 0);
182 _cleanup_(exec_shared_runtime_done) ExecSharedRuntime shared = {
71136404
LP
183 .netns_storage_socket = EBADF_PAIR,
184 .ipcns_storage_socket = EBADF_PAIR,
bb5232b6
LB
185 };
186 _cleanup_(dynamic_creds_done) DynamicCreds dynamic_creds = {};
187 _cleanup_(exec_runtime_clear) ExecRuntime runtime = {
71136404 188 .ephemeral_storage_socket = EBADF_PAIR,
bb5232b6
LB
189 .shared = &shared,
190 .dynamic_creds = &dynamic_creds,
191 };
192
193 exec_context_init(&context);
194 cgroup_context_init(&cgroup_context);
195
196 /* We might be starting the journal itself, we'll be told by the caller what to do */
197 log_set_always_reopen_console(true);
198 log_set_prohibit_ipc(true);
199 log_setup();
200
201 r = fdset_new_fill(/* filter_cloexec= */ 0, &fdset);
202 if (r < 0)
203 return log_error_errno(r, "Failed to create fd set: %m");
204
205 r = parse_argv(argc, argv);
206 if (r <= 0)
207 return r;
208
209 /* Now try again if we were told it's fine to use a different target */
210 if (log_get_target() != LOG_TARGET_KMSG) {
211 log_set_prohibit_ipc(false);
212 log_open();
213 }
214
215 r = fdset_remove(fdset, fileno(arg_serialization));
216 if (r < 0)
217 return log_error_errno(r, "Failed to remove serialization fd from fd set: %m");
218
219 r = exec_deserialize_invocation(arg_serialization,
220 fdset,
221 &context,
222 &command,
223 &params,
224 &runtime,
225 &cgroup_context);
226 if (r < 0)
227 return log_error_errno(r, "Failed to deserialize: %m");
228
229 arg_serialization = safe_fclose(arg_serialization);
230 fdset = fdset_free(fdset);
231
232 r = exec_invoke(&command,
233 &context,
234 &params,
235 &runtime,
236 &cgroup_context,
237 &exit_status);
238 if (r < 0) {
239 const char *status = ASSERT_PTR(
240 exit_status_to_string(exit_status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD));
241
242 log_exec_struct_errno(&context, &params, LOG_ERR, r,
243 "MESSAGE_ID=" SD_MESSAGE_SPAWN_FAILED_STR,
244 LOG_EXEC_INVOCATION_ID(&params),
245 LOG_EXEC_MESSAGE(&params, "Failed at step %s spawning %s: %m",
246 status, command.path),
247 "EXECUTABLE=%s", command.path);
248 } else
249 assert(exit_status == EXIT_SUCCESS); /* When 'skip' is chosen in the confirm spawn prompt */
250
251 return exit_status;
252}