]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/run/run.c
ptyfwd: before deciding that a pty is fully drained, ask the kernel again
[thirdparty/systemd.git] / src / run / run.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c2756a68
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
6c12b52e 21#include <getopt.h>
3f6fd1ba 22#include <stdio.h>
c2756a68
LP
23
24#include "sd-bus.h"
9b15b784 25#include "sd-event.h"
3f6fd1ba 26
b5efdb8a 27#include "alloc-util.h"
3f6fd1ba 28#include "bus-error.h"
20b16441 29#include "bus-unit-util.h"
40ca29a1 30#include "bus-util.h"
3f6fd1ba 31#include "calendarspec.h"
4de33e7f 32#include "env-util.h"
3ffd4af2 33#include "fd-util.h"
f97b34a6 34#include "format-util.h"
cf0fbc49 35#include "parse-util.h"
4bcc8c3c 36#include "path-util.h"
2a453c2e 37#include "process-util.h"
9b15b784 38#include "ptyfwd.h"
24882e06 39#include "signal-util.h"
8c7db2fb 40#include "spawn-polkit-agent.h"
3f6fd1ba 41#include "strv.h"
66cb2fde 42#include "terminal-util.h"
3f6fd1ba 43#include "unit-name.h"
b1d4f8e1 44#include "user-util.h"
c2756a68 45
8c7db2fb 46static bool arg_ask_password = true;
6c12b52e 47static bool arg_scope = false;
6577c7ce 48static bool arg_remain_after_exit = false;
3d161f99 49static bool arg_no_block = false;
2a453c2e 50static bool arg_wait = false;
6c12b52e 51static const char *arg_unit = NULL;
9f2e86af 52static const char *arg_description = NULL;
c221420b 53static const char *arg_slice = NULL;
a6c0353b 54static bool arg_send_sighup = false;
d21ed1ea 55static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
1ac67edb 56static const char *arg_host = NULL;
d21ed1ea 57static bool arg_user = false;
c7040b5d
LP
58static const char *arg_service_type = NULL;
59static const char *arg_exec_user = NULL;
60static const char *arg_exec_group = NULL;
61static int arg_nice = 0;
62static bool arg_nice_set = false;
63static char **arg_environment = NULL;
df31a6c0 64static char **arg_property = NULL;
5dca7739
LP
65static enum {
66 ARG_STDIO_NONE, /* The default, as it is for normal services, stdin connected to /dev/null, and stdout+stderr to the journal */
67 ARG_STDIO_PTY, /* Interactive behaviour, requested by --pty: we allocate a pty and connect it to the TTY we are invoked from */
68 ARG_STDIO_DIRECT, /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
69 ARG_STDIO_AUTO, /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
70} arg_stdio = ARG_STDIO_NONE;
4c213d6c
WC
71static usec_t arg_on_active = 0;
72static usec_t arg_on_boot = 0;
73static usec_t arg_on_startup = 0;
74static usec_t arg_on_unit_active = 0;
75static usec_t arg_on_unit_inactive = 0;
024a8ec1 76static const char *arg_on_calendar = NULL;
4c213d6c 77static char **arg_timer_property = NULL;
095dc596 78static bool arg_quiet = false;
fe9d0be9 79static bool arg_aggressive_gc = false;
c2756a68 80
601185b4 81static void help(void) {
4c213d6c 82 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
ad2c1701 83 "Run the specified command in a transient scope or service.\n\n"
4c213d6c
WC
84 " -h --help Show this help\n"
85 " --version Show package version\n"
8c7db2fb 86 " --no-ask-password Do not prompt for password\n"
4c213d6c
WC
87 " --user Run as user unit\n"
88 " -H --host=[USER@]HOST Operate on remote host\n"
89 " -M --machine=CONTAINER Operate on local container\n"
90 " --scope Run this as scope rather than service\n"
91 " --unit=UNIT Run under the specified unit name\n"
ad2c1701 92 " -p --property=NAME=VALUE Set service or scope unit property\n"
4c213d6c
WC
93 " --description=TEXT Description for unit\n"
94 " --slice=SLICE Run in the specified slice\n"
3d161f99 95 " --no-block Do not wait until operation finished\n"
4c213d6c 96 " -r --remain-after-exit Leave service around until explicitly stopped\n"
2a453c2e 97 " --wait Wait until service stopped again\n"
4c213d6c
WC
98 " --send-sighup Send SIGHUP when terminating\n"
99 " --service-type=TYPE Service type\n"
100 " --uid=USER Run as system user\n"
101 " --gid=GROUP Run as system group\n"
102 " --nice=NICE Nice level\n"
b5911366 103 " -E --setenv=NAME=VALUE Set environment\n"
5dca7739
LP
104 " -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
105 " STDERR\n"
106 " -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
fe9d0be9
LP
107 " -q --quiet Suppress information messages during runtime\n"
108 " -G --collect Unload unit after it ran, even when failed\n\n"
ad2c1701 109 "Timer options:\n"
b57b0625
ZJS
110 " --on-active=SECONDS Run after SECONDS delay\n"
111 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
112 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
113 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
114 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
4c213d6c 115 " --on-calendar=SPEC Realtime timer\n"
ad2c1701
LP
116 " --timer-property=NAME=VALUE Set timer unit property\n"
117 , program_invocation_short_name);
6c12b52e
LP
118}
119
4c213d6c
WC
120static bool with_timer(void) {
121 return arg_on_active || arg_on_boot || arg_on_startup || arg_on_unit_active || arg_on_unit_inactive || arg_on_calendar;
122}
123
6c12b52e
LP
124static int parse_argv(int argc, char *argv[]) {
125
126 enum {
127 ARG_VERSION = 0x100,
128 ARG_USER,
66b1e746 129 ARG_SYSTEM,
6c12b52e 130 ARG_SCOPE,
9f2e86af 131 ARG_UNIT,
c221420b 132 ARG_DESCRIPTION,
a6c0353b
LP
133 ARG_SLICE,
134 ARG_SEND_SIGHUP,
5cfde70c 135 ARG_SERVICE_TYPE,
c7040b5d
LP
136 ARG_EXEC_USER,
137 ARG_EXEC_GROUP,
c7040b5d 138 ARG_NICE,
4c213d6c
WC
139 ARG_ON_ACTIVE,
140 ARG_ON_BOOT,
141 ARG_ON_STARTUP,
142 ARG_ON_UNIT_ACTIVE,
143 ARG_ON_UNIT_INACTIVE,
144 ARG_ON_CALENDAR,
3d161f99
LP
145 ARG_TIMER_PROPERTY,
146 ARG_NO_BLOCK,
5cfde70c 147 ARG_NO_ASK_PASSWORD,
2a453c2e 148 ARG_WAIT,
6c12b52e
LP
149 };
150
151 static const struct option options[] = {
4c213d6c
WC
152 { "help", no_argument, NULL, 'h' },
153 { "version", no_argument, NULL, ARG_VERSION },
154 { "user", no_argument, NULL, ARG_USER },
155 { "system", no_argument, NULL, ARG_SYSTEM },
156 { "scope", no_argument, NULL, ARG_SCOPE },
157 { "unit", required_argument, NULL, ARG_UNIT },
158 { "description", required_argument, NULL, ARG_DESCRIPTION },
159 { "slice", required_argument, NULL, ARG_SLICE },
160 { "remain-after-exit", no_argument, NULL, 'r' },
161 { "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
162 { "host", required_argument, NULL, 'H' },
163 { "machine", required_argument, NULL, 'M' },
164 { "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
2a453c2e 165 { "wait", no_argument, NULL, ARG_WAIT },
4c213d6c
WC
166 { "uid", required_argument, NULL, ARG_EXEC_USER },
167 { "gid", required_argument, NULL, ARG_EXEC_GROUP },
168 { "nice", required_argument, NULL, ARG_NICE },
b5911366 169 { "setenv", required_argument, NULL, 'E' },
4c213d6c 170 { "property", required_argument, NULL, 'p' },
5dca7739 171 { "tty", no_argument, NULL, 't' }, /* deprecated alias */
5cfde70c 172 { "pty", no_argument, NULL, 't' },
5dca7739 173 { "pipe", no_argument, NULL, 'P' },
095dc596 174 { "quiet", no_argument, NULL, 'q' },
4c213d6c
WC
175 { "on-active", required_argument, NULL, ARG_ON_ACTIVE },
176 { "on-boot", required_argument, NULL, ARG_ON_BOOT },
177 { "on-startup", required_argument, NULL, ARG_ON_STARTUP },
178 { "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
179 { "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
180 { "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
181 { "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
3d161f99 182 { "no-block", no_argument, NULL, ARG_NO_BLOCK },
ad2c1701 183 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
fe9d0be9 184 { "collect", no_argument, NULL, 'G' },
eb9da376 185 {},
6c12b52e
LP
186 };
187
c7040b5d 188 int r, c;
6c12b52e
LP
189
190 assert(argc >= 0);
191 assert(argv);
192
fe9d0be9 193 while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tPqG", options, NULL)) >= 0)
6c12b52e
LP
194
195 switch (c) {
196
197 case 'h':
601185b4
ZJS
198 help();
199 return 0;
6c12b52e 200
ad2c1701
LP
201 case ARG_VERSION:
202 return version();
203
8c7db2fb
EV
204 case ARG_NO_ASK_PASSWORD:
205 arg_ask_password = false;
206 break;
207
6c12b52e
LP
208 case ARG_USER:
209 arg_user = true;
210 break;
211
66b1e746
LP
212 case ARG_SYSTEM:
213 arg_user = false;
214 break;
215
6c12b52e
LP
216 case ARG_SCOPE:
217 arg_scope = true;
218 break;
219
220 case ARG_UNIT:
221 arg_unit = optarg;
222 break;
223
9f2e86af
LP
224 case ARG_DESCRIPTION:
225 arg_description = optarg;
226 break;
227
c221420b
LP
228 case ARG_SLICE:
229 arg_slice = optarg;
230 break;
231
a6c0353b
LP
232 case ARG_SEND_SIGHUP:
233 arg_send_sighup = true;
234 break;
235
6577c7ce
LP
236 case 'r':
237 arg_remain_after_exit = true;
238 break;
239
d21ed1ea
LP
240 case 'H':
241 arg_transport = BUS_TRANSPORT_REMOTE;
242 arg_host = optarg;
243 break;
244
245 case 'M':
de33fc62 246 arg_transport = BUS_TRANSPORT_MACHINE;
d21ed1ea
LP
247 arg_host = optarg;
248 break;
249
c7040b5d
LP
250 case ARG_SERVICE_TYPE:
251 arg_service_type = optarg;
252 break;
253
254 case ARG_EXEC_USER:
255 arg_exec_user = optarg;
256 break;
257
258 case ARG_EXEC_GROUP:
259 arg_exec_group = optarg;
260 break;
261
262 case ARG_NICE:
41bf0590
LP
263 r = parse_nice(optarg, &arg_nice);
264 if (r < 0)
265 return log_error_errno(r, "Failed to parse nice value: %s", optarg);
c7040b5d
LP
266
267 arg_nice_set = true;
268 break;
269
b5911366 270 case 'E':
c7040b5d
LP
271 if (strv_extend(&arg_environment, optarg) < 0)
272 return log_oom();
273
274 break;
275
df31a6c0 276 case 'p':
df31a6c0
LP
277 if (strv_extend(&arg_property, optarg) < 0)
278 return log_oom();
279
280 break;
281
5dca7739
LP
282 case 't': /* --pty */
283 if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
284 arg_stdio = ARG_STDIO_AUTO;
285 else
286 arg_stdio = ARG_STDIO_PTY;
287 break;
288
289 case 'P': /* --pipe */
290 if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
291 arg_stdio = ARG_STDIO_AUTO;
292 else
293 arg_stdio = ARG_STDIO_DIRECT;
9b15b784
LP
294 break;
295
095dc596
LP
296 case 'q':
297 arg_quiet = true;
298 break;
299
4c213d6c
WC
300 case ARG_ON_ACTIVE:
301
302 r = parse_sec(optarg, &arg_on_active);
303 if (r < 0) {
304 log_error("Failed to parse timer value: %s", optarg);
305 return r;
306 }
307
308 break;
309
310 case ARG_ON_BOOT:
311
312 r = parse_sec(optarg, &arg_on_boot);
313 if (r < 0) {
314 log_error("Failed to parse timer value: %s", optarg);
315 return r;
316 }
317
318 break;
319
320 case ARG_ON_STARTUP:
321
322 r = parse_sec(optarg, &arg_on_startup);
323 if (r < 0) {
324 log_error("Failed to parse timer value: %s", optarg);
325 return r;
326 }
327
328 break;
329
330 case ARG_ON_UNIT_ACTIVE:
331
332 r = parse_sec(optarg, &arg_on_unit_active);
333 if (r < 0) {
334 log_error("Failed to parse timer value: %s", optarg);
335 return r;
336 }
337
338 break;
339
340 case ARG_ON_UNIT_INACTIVE:
341
342 r = parse_sec(optarg, &arg_on_unit_inactive);
343 if (r < 0) {
344 log_error("Failed to parse timer value: %s", optarg);
345 return r;
346 }
347
348 break;
349
024a8ec1
LP
350 case ARG_ON_CALENDAR: {
351 CalendarSpec *spec = NULL;
4c213d6c
WC
352
353 r = calendar_spec_from_string(optarg, &spec);
354 if (r < 0) {
355 log_error("Invalid calendar spec: %s", optarg);
356 return r;
357 }
024a8ec1
LP
358
359 calendar_spec_free(spec);
4c213d6c
WC
360 arg_on_calendar = optarg;
361 break;
024a8ec1 362 }
4c213d6c
WC
363
364 case ARG_TIMER_PROPERTY:
365
366 if (strv_extend(&arg_timer_property, optarg) < 0)
367 return log_oom();
368
369 break;
370
3d161f99
LP
371 case ARG_NO_BLOCK:
372 arg_no_block = true;
373 break;
374
2a453c2e
LP
375 case ARG_WAIT:
376 arg_wait = true;
377 break;
378
fe9d0be9
LP
379 case 'G':
380 arg_aggressive_gc = true;
381 break;
382
6c12b52e
LP
383 case '?':
384 return -EINVAL;
385
386 default:
eb9da376 387 assert_not_reached("Unhandled option");
6c12b52e 388 }
6c12b52e 389
5dca7739
LP
390
391 if (arg_stdio == ARG_STDIO_AUTO) {
392 /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
393 * to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
394 * pipeline, but we are neatly interactive with tty-level isolation otherwise. */
395 arg_stdio = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) ?
396 ARG_STDIO_PTY :
397 ARG_STDIO_DIRECT;
398 }
399
4c213d6c 400 if ((optind >= argc) && (!arg_unit || !with_timer())) {
6c12b52e
LP
401 log_error("Command line to execute required.");
402 return -EINVAL;
403 }
404
d21ed1ea
LP
405 if (arg_user && arg_transport != BUS_TRANSPORT_LOCAL) {
406 log_error("Execution in user context is not supported on non-local systems.");
407 return -EINVAL;
408 }
409
410 if (arg_scope && arg_transport != BUS_TRANSPORT_LOCAL) {
411 log_error("Scope execution is not supported on non-local systems.");
412 return -EINVAL;
413 }
414
4de33e7f
LP
415 if (arg_scope && (arg_remain_after_exit || arg_service_type)) {
416 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
c7040b5d
LP
417 return -EINVAL;
418 }
419
5dca7739
LP
420 if (arg_stdio != ARG_STDIO_NONE && (with_timer() || arg_scope)) {
421 log_error("--pty/--pipe is not compatible in timer or --scope mode.");
9b15b784
LP
422 return -EINVAL;
423 }
424
5dca7739
LP
425 if (arg_stdio != ARG_STDIO_NONE && arg_transport == BUS_TRANSPORT_REMOTE) {
426 log_error("--pty/--pipe is only supported when connecting to the local system or containers.");
024a8ec1
LP
427 return -EINVAL;
428 }
429
5dca7739
LP
430 if (arg_stdio != ARG_STDIO_NONE && arg_no_block) {
431 log_error("--pty/--pipe is not compatible with --no-block.");
578c03bc
LP
432 return -EINVAL;
433 }
434
4c213d6c
WC
435 if (arg_scope && with_timer()) {
436 log_error("Timer options are not supported in --scope mode.");
437 return -EINVAL;
438 }
439
440 if (arg_timer_property && !with_timer()) {
441 log_error("--timer-property= has no effect without any other timer options.");
442 return -EINVAL;
443 }
444
2a453c2e
LP
445 if (arg_wait) {
446 if (arg_no_block) {
447 log_error("--wait may not be combined with --no-block.");
448 return -EINVAL;
449 }
450
451 if (with_timer()) {
452 log_error("--wait may not be combined with timer operations.");
453 return -EINVAL;
454 }
455
456 if (arg_scope) {
457 log_error("--wait may not be combined with --scope.");
458 return -EINVAL;
459 }
460 }
461
6c12b52e
LP
462 return 1;
463}
464
9b15b784 465static int transient_unit_set_properties(sd_bus_message *m, char **properties) {
c2756a68
LP
466 int r;
467
9b15b784
LP
468 r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
469 if (r < 0)
f53bddf3 470 return bus_log_create_error(r);
9b15b784 471
fe9d0be9
LP
472 if (arg_aggressive_gc) {
473 r = sd_bus_message_append(m, "(sv)", "CollectMode", "s", "inactive-or-failed");
474 if (r < 0)
f53bddf3 475 return bus_log_create_error(r);
fe9d0be9
LP
476 }
477
8673cf13
LP
478 r = bus_append_unit_property_assignment_many(m, properties);
479 if (r < 0)
480 return r;
df31a6c0 481
9b15b784
LP
482 return 0;
483}
484
485static int transient_cgroup_set_properties(sd_bus_message *m) {
486 int r;
487 assert(m);
c2756a68 488
c221420b 489 if (!isempty(arg_slice)) {
f53bddf3 490 _cleanup_free_ char *slice = NULL;
c221420b 491
7410616c
LP
492 r = unit_name_mangle_with_suffix(arg_slice, UNIT_NAME_NOGLOB, ".slice", &slice);
493 if (r < 0)
f53bddf3 494 return log_error_errno(r, "Failed to mangle name '%s': %m", arg_slice);
c221420b
LP
495
496 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
497 if (r < 0)
f53bddf3 498 return bus_log_create_error(r);
c221420b
LP
499 }
500
9b15b784
LP
501 return 0;
502}
503
504static int transient_kill_set_properties(sd_bus_message *m) {
f53bddf3
LP
505 int r;
506
9b15b784
LP
507 assert(m);
508
f53bddf3
LP
509 if (arg_send_sighup) {
510 r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
511 if (r < 0)
512 return bus_log_create_error(r);
513 }
514
515 return 0;
6c12b52e
LP
516}
517
9b15b784 518static int transient_service_set_properties(sd_bus_message *m, char **argv, const char *pty_path) {
5dca7739 519 bool send_term = false;
6c12b52e
LP
520 int r;
521
8159d91a
LP
522 assert(m);
523
9b15b784
LP
524 r = transient_unit_set_properties(m, arg_property);
525 if (r < 0)
526 return r;
527
528 r = transient_kill_set_properties(m);
529 if (r < 0)
530 return r;
531
532 r = transient_cgroup_set_properties(m);
86b8d289
LP
533 if (r < 0)
534 return r;
535
5dca7739 536 if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
2a453c2e
LP
537 r = sd_bus_message_append(m, "(sv)", "AddRef", "b", 1);
538 if (r < 0)
f53bddf3 539 return bus_log_create_error(r);
2a453c2e
LP
540 }
541
df31a6c0
LP
542 if (arg_remain_after_exit) {
543 r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
544 if (r < 0)
f53bddf3 545 return bus_log_create_error(r);
df31a6c0 546 }
6577c7ce 547
c7040b5d
LP
548 if (arg_service_type) {
549 r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
550 if (r < 0)
f53bddf3 551 return bus_log_create_error(r);
c7040b5d
LP
552 }
553
554 if (arg_exec_user) {
555 r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user);
556 if (r < 0)
f53bddf3 557 return bus_log_create_error(r);
c7040b5d
LP
558 }
559
560 if (arg_exec_group) {
561 r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group);
562 if (r < 0)
f53bddf3 563 return bus_log_create_error(r);
c7040b5d
LP
564 }
565
566 if (arg_nice_set) {
567 r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
568 if (r < 0)
f53bddf3 569 return bus_log_create_error(r);
c7040b5d
LP
570 }
571
9b15b784 572 if (pty_path) {
9b15b784
LP
573 r = sd_bus_message_append(m,
574 "(sv)(sv)(sv)(sv)",
575 "StandardInput", "s", "tty",
576 "StandardOutput", "s", "tty",
577 "StandardError", "s", "tty",
578 "TTYPath", "s", pty_path);
579 if (r < 0)
f53bddf3 580 return bus_log_create_error(r);
9b15b784 581
5dca7739
LP
582 send_term = true;
583
584 } else if (arg_stdio == ARG_STDIO_DIRECT) {
585 r = sd_bus_message_append(m,
586 "(sv)(sv)(sv)",
587 "StandardInputFileDescriptor", "h", STDIN_FILENO,
588 "StandardOutputFileDescriptor", "h", STDOUT_FILENO,
589 "StandardErrorFileDescriptor", "h", STDERR_FILENO);
590 if (r < 0)
f53bddf3 591 return bus_log_create_error(r);
5dca7739
LP
592
593 send_term = isatty(STDIN_FILENO) || isatty(STDOUT_FILENO) || isatty(STDERR_FILENO);
594 }
595
596 if (send_term) {
597 const char *e;
598
9b15b784
LP
599 e = getenv("TERM");
600 if (e) {
601 char *n;
602
63c372cb 603 n = strjoina("TERM=", e);
9b15b784
LP
604 r = sd_bus_message_append(m,
605 "(sv)",
606 "Environment", "as", 1, n);
607 if (r < 0)
f53bddf3 608 return bus_log_create_error(r);
9b15b784
LP
609 }
610 }
611
c7040b5d
LP
612 if (!strv_isempty(arg_environment)) {
613 r = sd_bus_message_open_container(m, 'r', "sv");
614 if (r < 0)
f53bddf3 615 return bus_log_create_error(r);
c7040b5d
LP
616
617 r = sd_bus_message_append(m, "s", "Environment");
618 if (r < 0)
f53bddf3 619 return bus_log_create_error(r);
c7040b5d
LP
620
621 r = sd_bus_message_open_container(m, 'v', "as");
622 if (r < 0)
f53bddf3 623 return bus_log_create_error(r);
c7040b5d
LP
624
625 r = sd_bus_message_append_strv(m, arg_environment);
626 if (r < 0)
f53bddf3 627 return bus_log_create_error(r);
c7040b5d
LP
628
629 r = sd_bus_message_close_container(m);
630 if (r < 0)
f53bddf3 631 return bus_log_create_error(r);
c7040b5d
LP
632
633 r = sd_bus_message_close_container(m);
634 if (r < 0)
f53bddf3 635 return bus_log_create_error(r);
4c213d6c
WC
636 }
637
638 /* Exec container */
639 {
640 r = sd_bus_message_open_container(m, 'r', "sv");
641 if (r < 0)
f53bddf3 642 return bus_log_create_error(r);
4c213d6c
WC
643
644 r = sd_bus_message_append(m, "s", "ExecStart");
645 if (r < 0)
f53bddf3 646 return bus_log_create_error(r);
4c213d6c
WC
647
648 r = sd_bus_message_open_container(m, 'v', "a(sasb)");
649 if (r < 0)
f53bddf3 650 return bus_log_create_error(r);
4c213d6c
WC
651
652 r = sd_bus_message_open_container(m, 'a', "(sasb)");
653 if (r < 0)
f53bddf3 654 return bus_log_create_error(r);
4c213d6c
WC
655
656 r = sd_bus_message_open_container(m, 'r', "sasb");
657 if (r < 0)
f53bddf3 658 return bus_log_create_error(r);
4c213d6c
WC
659
660 r = sd_bus_message_append(m, "s", argv[0]);
661 if (r < 0)
f53bddf3 662 return bus_log_create_error(r);
4c213d6c
WC
663
664 r = sd_bus_message_append_strv(m, argv);
665 if (r < 0)
f53bddf3 666 return bus_log_create_error(r);
4c213d6c
WC
667
668 r = sd_bus_message_append(m, "b", false);
669 if (r < 0)
f53bddf3 670 return bus_log_create_error(r);
4c213d6c
WC
671
672 r = sd_bus_message_close_container(m);
673 if (r < 0)
f53bddf3 674 return bus_log_create_error(r);
4c213d6c
WC
675
676 r = sd_bus_message_close_container(m);
677 if (r < 0)
f53bddf3 678 return bus_log_create_error(r);
4c213d6c
WC
679
680 r = sd_bus_message_close_container(m);
681 if (r < 0)
f53bddf3 682 return bus_log_create_error(r);
4c213d6c
WC
683
684 r = sd_bus_message_close_container(m);
685 if (r < 0)
f53bddf3 686 return bus_log_create_error(r);
4c213d6c
WC
687 }
688
689 return 0;
690}
691
9b15b784
LP
692static int transient_scope_set_properties(sd_bus_message *m) {
693 int r;
694
695 assert(m);
696
697 r = transient_unit_set_properties(m, arg_property);
698 if (r < 0)
699 return r;
700
701 r = transient_kill_set_properties(m);
702 if (r < 0)
703 return r;
704
37e605f9
LP
705 r = transient_cgroup_set_properties(m);
706 if (r < 0)
707 return r;
708
df0ff127 709 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, (uint32_t) getpid_cached());
9b15b784 710 if (r < 0)
f53bddf3 711 return bus_log_create_error(r);
9b15b784
LP
712
713 return 0;
714}
715
4c213d6c
WC
716static int transient_timer_set_properties(sd_bus_message *m) {
717 int r;
718
719 assert(m);
720
9b15b784 721 r = transient_unit_set_properties(m, arg_timer_property);
4c213d6c
WC
722 if (r < 0)
723 return r;
724
6348d701
LP
725 /* Automatically clean up our transient timers */
726 r = sd_bus_message_append(m, "(sv)", "RemainAfterElapse", "b", false);
727 if (r < 0)
f53bddf3 728 return bus_log_create_error(r);
6348d701 729
4c213d6c
WC
730 if (arg_on_active) {
731 r = sd_bus_message_append(m, "(sv)", "OnActiveSec", "t", arg_on_active);
732 if (r < 0)
f53bddf3 733 return bus_log_create_error(r);
c7040b5d
LP
734 }
735
4c213d6c
WC
736 if (arg_on_boot) {
737 r = sd_bus_message_append(m, "(sv)", "OnBootSec", "t", arg_on_boot);
738 if (r < 0)
f53bddf3 739 return bus_log_create_error(r);
4c213d6c
WC
740 }
741
742 if (arg_on_startup) {
743 r = sd_bus_message_append(m, "(sv)", "OnStartupSec", "t", arg_on_startup);
744 if (r < 0)
f53bddf3 745 return bus_log_create_error(r);
4c213d6c
WC
746 }
747
748 if (arg_on_unit_active) {
749 r = sd_bus_message_append(m, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active);
750 if (r < 0)
f53bddf3 751 return bus_log_create_error(r);
4c213d6c
WC
752 }
753
754 if (arg_on_unit_inactive) {
755 r = sd_bus_message_append(m, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive);
756 if (r < 0)
f53bddf3 757 return bus_log_create_error(r);
4c213d6c
WC
758 }
759
760 if (arg_on_calendar) {
761 r = sd_bus_message_append(m, "(sv)", "OnCalendar", "s", arg_on_calendar);
762 if (r < 0)
f53bddf3 763 return bus_log_create_error(r);
4c213d6c
WC
764 }
765
766 return 0;
767}
768
9c8d1e1a
LP
769static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
770 const char *unique, *id;
771 char *p;
772 int r;
773
774 assert(bus);
775 assert(t >= 0);
776 assert(t < _UNIT_TYPE_MAX);
777
778 r = sd_bus_get_unique_name(bus, &unique);
779 if (r < 0) {
780 sd_id128_t rnd;
781
782 /* We couldn't get the unique name, which is a pretty
783 * common case if we are connected to systemd
784 * directly. In that case, just pick a random uuid as
785 * name */
786
787 r = sd_id128_randomize(&rnd);
788 if (r < 0)
789 return log_error_errno(r, "Failed to generate random run unit name: %m");
790
791 if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0)
792 return log_oom();
793
794 return 0;
795 }
796
797 /* We managed to get the unique name, then let's use that to
798 * name our transient units. */
799
800 id = startswith(unique, ":1.");
801 if (!id) {
802 log_error("Unique name %s has unexpected format.", unique);
803 return -EINVAL;
804 }
805
605405c6 806 p = strjoin("run-u", id, ".", unit_type_to_string(t));
9c8d1e1a
LP
807 if (!p)
808 return log_oom();
809
810 *ret = p;
811 return 0;
812}
813
2a453c2e
LP
814typedef struct RunContext {
815 sd_bus *bus;
816 sd_event *event;
817 PTYForward *forward;
818 sd_bus_slot *match;
819
820 /* The exit data of the unit */
821 char *active_state;
822 uint64_t inactive_exit_usec;
823 uint64_t inactive_enter_usec;
824 char *result;
825 uint64_t cpu_usage_nsec;
655aab20
LP
826 uint64_t ip_ingress_bytes;
827 uint64_t ip_egress_bytes;
2a453c2e
LP
828 uint32_t exit_code;
829 uint32_t exit_status;
830} RunContext;
831
832static void run_context_free(RunContext *c) {
833 assert(c);
834
835 c->forward = pty_forward_free(c->forward);
836 c->match = sd_bus_slot_unref(c->match);
837 c->bus = sd_bus_unref(c->bus);
838 c->event = sd_event_unref(c->event);
839
840 free(c->active_state);
841 free(c->result);
842}
843
844static void run_context_check_done(RunContext *c) {
95f1d6bf 845 bool done;
2a453c2e
LP
846
847 assert(c);
848
849 if (c->match)
95f1d6bf
LP
850 done = STRPTR_IN_SET(c->active_state, "inactive", "failed");
851 else
852 done = true;
2a453c2e 853
95f1d6bf
LP
854 if (c->forward && done) /* If the service is gone, it's time to drain the output */
855 done = pty_forward_drain(c->forward);
2a453c2e
LP
856
857 if (done)
858 sd_event_exit(c->event, EXIT_SUCCESS);
859}
860
5b1bad8d 861static int run_context_update(RunContext *c, const char *path) {
2a453c2e
LP
862
863 static const struct bus_properties_map map[] = {
864 { "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
865 { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_exit_usec) },
866 { "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_enter_usec) },
867 { "Result", "s", NULL, offsetof(RunContext, result) },
868 { "ExecMainCode", "i", NULL, offsetof(RunContext, exit_code) },
869 { "ExecMainStatus", "i", NULL, offsetof(RunContext, exit_status) },
870 { "CPUUsageNSec", "t", NULL, offsetof(RunContext, cpu_usage_nsec) },
655aab20
LP
871 { "IPIngressBytes", "t", NULL, offsetof(RunContext, ip_ingress_bytes) },
872 { "IPEgressBytes", "t", NULL, offsetof(RunContext, ip_egress_bytes) },
2a453c2e
LP
873 {}
874 };
875
f9e0eefc 876 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2a453c2e
LP
877 int r;
878
879 r = bus_map_all_properties(c->bus,
880 "org.freedesktop.systemd1",
5b1bad8d 881 path,
2a453c2e 882 map,
f9e0eefc 883 &error,
2a453c2e
LP
884 c);
885 if (r < 0) {
886 sd_event_exit(c->event, EXIT_FAILURE);
f9e0eefc 887 return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
2a453c2e
LP
888 }
889
890 run_context_check_done(c);
891 return 0;
892}
893
5b1bad8d
LP
894static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
895 RunContext *c = userdata;
896
897 assert(m);
898 assert(c);
899
900 return run_context_update(c, sd_bus_message_get_path(m));
901}
902
2a453c2e
LP
903static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
904 RunContext *c = userdata;
905
906 assert(f);
907
908 if (rcode < 0) {
909 sd_event_exit(c->event, EXIT_FAILURE);
910 return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
911 }
912
913 run_context_check_done(c);
914 return 0;
915}
916
4c213d6c
WC
917static int start_transient_service(
918 sd_bus *bus,
2a453c2e
LP
919 char **argv,
920 int *retval) {
4c213d6c 921
4afd3348
LP
922 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
923 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
3d161f99 924 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
ee451d76 925 _cleanup_free_ char *service = NULL, *pty_path = NULL;
9b15b784 926 _cleanup_close_ int master = -1;
4c213d6c
WC
927 int r;
928
929 assert(bus);
930 assert(argv);
2a453c2e 931 assert(retval);
4c213d6c 932
5dca7739 933 if (arg_stdio == ARG_STDIO_PTY) {
9b15b784 934
ee451d76
LP
935 if (arg_transport == BUS_TRANSPORT_LOCAL) {
936 master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
937 if (master < 0)
938 return log_error_errno(errno, "Failed to acquire pseudo tty: %m");
939
940 r = ptsname_malloc(master, &pty_path);
941 if (r < 0)
942 return log_error_errno(r, "Failed to determine tty name: %m");
943
395745ba
LP
944 if (unlockpt(master) < 0)
945 return log_error_errno(errno, "Failed to unlock tty: %m");
946
de33fc62 947 } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
4afd3348 948 _cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL;
20fc5811 949 _cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL;
ee451d76
LP
950 const char *s;
951
024a8ec1 952 r = sd_bus_default_system(&system_bus);
ee451d76 953 if (r < 0)
024a8ec1 954 return log_error_errno(r, "Failed to connect to system bus: %m");
ee451d76
LP
955
956 r = sd_bus_call_method(system_bus,
957 "org.freedesktop.machine1",
958 "/org/freedesktop/machine1",
959 "org.freedesktop.machine1.Manager",
960 "OpenMachinePTY",
961 &error,
20fc5811 962 &pty_reply,
ee451d76
LP
963 "s", arg_host);
964 if (r < 0) {
965 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
966 return r;
967 }
968
20fc5811 969 r = sd_bus_message_read(pty_reply, "hs", &master, &s);
ee451d76
LP
970 if (r < 0)
971 return bus_log_parse_error(r);
972
973 master = fcntl(master, F_DUPFD_CLOEXEC, 3);
974 if (master < 0)
975 return log_error_errno(errno, "Failed to duplicate master fd: %m");
976
977 pty_path = strdup(s);
978 if (!pty_path)
979 return log_oom();
980 } else
981 assert_not_reached("Can't allocate tty via ssh");
9b15b784
LP
982 }
983
3d161f99
LP
984 if (!arg_no_block) {
985 r = bus_wait_for_jobs_new(bus, &w);
986 if (r < 0)
987 return log_error_errno(r, "Could not watch jobs: %m");
988 }
989
4c213d6c 990 if (arg_unit) {
7410616c
LP
991 r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
992 if (r < 0)
993 return log_error_errno(r, "Failed to mangle unit name: %m");
9c8d1e1a
LP
994 } else {
995 r = make_unit_name(bus, UNIT_SERVICE, &service);
996 if (r < 0)
997 return r;
998 }
4c213d6c
WC
999
1000 r = sd_bus_message_new_method_call(
1001 bus,
1002 &m,
1003 "org.freedesktop.systemd1",
1004 "/org/freedesktop/systemd1",
1005 "org.freedesktop.systemd1.Manager",
1006 "StartTransientUnit");
9f2e86af 1007 if (r < 0)
7040b626 1008 return bus_log_create_error(r);
9f2e86af 1009
8c7db2fb
EV
1010 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1011 if (r < 0)
1012 return bus_log_create_error(r);
1013
9b15b784 1014 /* Name and mode */
4c213d6c 1015 r = sd_bus_message_append(m, "ss", service, "fail");
c2756a68 1016 if (r < 0)
7040b626 1017 return bus_log_create_error(r);
c2756a68 1018
9b15b784 1019 /* Properties */
4c213d6c 1020 r = sd_bus_message_open_container(m, 'a', "(sv)");
c2756a68 1021 if (r < 0)
7040b626 1022 return bus_log_create_error(r);
c2756a68 1023
9b15b784 1024 r = transient_service_set_properties(m, argv, pty_path);
c2756a68 1025 if (r < 0)
f53bddf3 1026 return r;
c2756a68 1027
4c213d6c 1028 r = sd_bus_message_close_container(m);
c2756a68 1029 if (r < 0)
7040b626 1030 return bus_log_create_error(r);
c2756a68 1031
9b15b784 1032 /* Auxiliary units */
4c213d6c 1033 r = sd_bus_message_append(m, "a(sa(sv))", 0);
c2756a68 1034 if (r < 0)
7040b626 1035 return bus_log_create_error(r);
c2756a68 1036
8a4b13c5 1037 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
8c7db2fb 1038
3d161f99 1039 r = sd_bus_call(bus, m, 0, &error, &reply);
024a8ec1
LP
1040 if (r < 0)
1041 return log_error_errno(r, "Failed to start transient service unit: %s", bus_error_message(&error, r));
c2756a68 1042
3d161f99
LP
1043 if (w) {
1044 const char *object;
1045
1046 r = sd_bus_message_read(reply, "o", &object);
1047 if (r < 0)
1048 return bus_log_parse_error(r);
1049
1050 r = bus_wait_for_jobs_one(w, object, arg_quiet);
1051 if (r < 0)
1052 return r;
1053 }
1054
2a453c2e
LP
1055 if (!arg_quiet)
1056 log_info("Running as unit: %s", service);
1057
5dca7739 1058 if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
655aab20
LP
1059 _cleanup_(run_context_free) RunContext c = {
1060 .cpu_usage_nsec = NSEC_INFINITY,
1061 .ip_ingress_bytes = UINT64_MAX,
1062 .ip_egress_bytes = UINT64_MAX,
1063 .inactive_exit_usec = USEC_INFINITY,
1064 .inactive_enter_usec = USEC_INFINITY,
1065 };
95f1d6bf
LP
1066 _cleanup_free_ char *path = NULL;
1067 const char *mt;
4c213d6c 1068
2a453c2e
LP
1069 c.bus = sd_bus_ref(bus);
1070
1071 r = sd_event_default(&c.event);
4c213d6c 1072 if (r < 0)
9b15b784 1073 return log_error_errno(r, "Failed to get event loop: %m");
4c213d6c 1074
2a453c2e
LP
1075 if (master >= 0) {
1076 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
1077 (void) sd_event_add_signal(c.event, NULL, SIGINT, NULL, NULL);
1078 (void) sd_event_add_signal(c.event, NULL, SIGTERM, NULL, NULL);
1079
1080 if (!arg_quiet)
1081 log_info("Press ^] three times within 1s to disconnect TTY.");
4c213d6c 1082
2a453c2e
LP
1083 r = pty_forward_new(c.event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c.forward);
1084 if (r < 0)
1085 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1086
1087 pty_forward_set_handler(c.forward, pty_forward_handler, &c);
1088 }
4c213d6c 1089
95f1d6bf
LP
1090 path = unit_dbus_path_from_name(service);
1091 if (!path)
1092 return log_oom();
2a453c2e 1093
95f1d6bf
LP
1094 mt = strjoina("type='signal',"
1095 "sender='org.freedesktop.systemd1',"
1096 "path='", path, "',"
1097 "interface='org.freedesktop.DBus.Properties',"
1098 "member='PropertiesChanged'");
1099 r = sd_bus_add_match(bus, &c.match, mt, on_properties_changed, &c);
1100 if (r < 0)
1101 return log_error_errno(r, "Failed to add properties changed signal.");
4c213d6c 1102
95f1d6bf
LP
1103 r = sd_bus_attach_event(bus, c.event, 0);
1104 if (r < 0)
1105 return log_error_errno(r, "Failed to attach bus to event loop.");
5b1bad8d 1106
95f1d6bf
LP
1107 r = run_context_update(&c, path);
1108 if (r < 0)
1109 return r;
2a453c2e
LP
1110
1111 r = sd_event_loop(c.event);
4c213d6c 1112 if (r < 0)
9b15b784 1113 return log_error_errno(r, "Failed to run event loop: %m");
4c213d6c 1114
2a453c2e
LP
1115 if (c.forward) {
1116 char last_char = 0;
4c213d6c 1117
2a453c2e
LP
1118 r = pty_forward_get_last_char(c.forward, &last_char);
1119 if (r >= 0 && !arg_quiet && last_char != '\n')
1120 fputc('\n', stdout);
1121 }
4c213d6c 1122
95f1d6bf 1123 if (arg_wait && !arg_quiet) {
9182fb52
LP
1124
1125 /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, in its
1126 * original settings (i.e. proper line breaks), so that we can show the summary in a pretty
1127 * way. */
1128 c.forward = pty_forward_free(c.forward);
1129
2a453c2e
LP
1130 if (!isempty(c.result))
1131 log_info("Finished with result: %s", strna(c.result));
9f2e86af 1132
2a453c2e
LP
1133 if (c.exit_code == CLD_EXITED)
1134 log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c.exit_code), c.exit_status);
1135 else if (c.exit_code > 0)
1136 log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c.exit_code), signal_to_string(c.exit_status));
1137
1138 if (c.inactive_enter_usec > 0 && c.inactive_enter_usec != USEC_INFINITY &&
1139 c.inactive_exit_usec > 0 && c.inactive_exit_usec != USEC_INFINITY &&
1140 c.inactive_enter_usec > c.inactive_exit_usec) {
1141 char ts[FORMAT_TIMESPAN_MAX];
1142 log_info("Service runtime: %s", format_timespan(ts, sizeof(ts), c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC));
1143 }
1144
655aab20 1145 if (c.cpu_usage_nsec != NSEC_INFINITY) {
2a453c2e
LP
1146 char ts[FORMAT_TIMESPAN_MAX];
1147 log_info("CPU time consumed: %s", format_timespan(ts, sizeof(ts), (c.cpu_usage_nsec + NSEC_PER_USEC - 1) / NSEC_PER_USEC, USEC_PER_MSEC));
1148 }
655aab20
LP
1149
1150 if (c.ip_ingress_bytes != UINT64_MAX) {
1151 char bytes[FORMAT_BYTES_MAX];
1152 log_info("IP traffic received: %s", format_bytes(bytes, sizeof(bytes), c.ip_ingress_bytes));
1153 }
1154 if (c.ip_egress_bytes != UINT64_MAX) {
1155 char bytes[FORMAT_BYTES_MAX];
1156 log_info("IP traffic sent: %s", format_bytes(bytes, sizeof(bytes), c.ip_egress_bytes));
1157 }
2a453c2e
LP
1158 }
1159
1160 /* Try to propagate the service's return value */
1161 if (c.result && STR_IN_SET(c.result, "success", "exit-code") && c.exit_code == CLD_EXITED)
1162 *retval = c.exit_status;
1163 else
1164 *retval = EXIT_FAILURE;
1165 }
7040b626
LP
1166
1167 return 0;
6c12b52e
LP
1168}
1169
1170static int start_transient_scope(
1171 sd_bus *bus,
ee451d76 1172 char **argv) {
6c12b52e 1173
4afd3348
LP
1174 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1175 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
de158ed2 1176 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
9b15b784 1177 _cleanup_strv_free_ char **env = NULL, **user_env = NULL;
4c213d6c 1178 _cleanup_free_ char *scope = NULL;
de158ed2 1179 const char *object = NULL;
6c12b52e
LP
1180 int r;
1181
8159d91a 1182 assert(bus);
4c213d6c 1183 assert(argv);
8159d91a 1184
de158ed2
LP
1185 r = bus_wait_for_jobs_new(bus, &w);
1186 if (r < 0)
1187 return log_oom();
1188
7de80bfe 1189 if (arg_unit) {
7410616c
LP
1190 r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".scope", &scope);
1191 if (r < 0)
1192 return log_error_errno(r, "Failed to mangle scope name: %m");
9c8d1e1a
LP
1193 } else {
1194 r = make_unit_name(bus, UNIT_SCOPE, &scope);
1195 if (r < 0)
1196 return r;
1197 }
6c12b52e 1198
4c213d6c 1199 r = sd_bus_message_new_method_call(
9b15b784
LP
1200 bus,
1201 &m,
1202 "org.freedesktop.systemd1",
1203 "/org/freedesktop/systemd1",
1204 "org.freedesktop.systemd1.Manager",
1205 "StartTransientUnit");
c2756a68 1206 if (r < 0)
7040b626 1207 return bus_log_create_error(r);
c2756a68 1208
8c7db2fb
EV
1209 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1210 if (r < 0)
1211 return bus_log_create_error(r);
1212
9b15b784 1213 /* Name and Mode */
4c213d6c
WC
1214 r = sd_bus_message_append(m, "ss", scope, "fail");
1215 if (r < 0)
1216 return bus_log_create_error(r);
1217
9b15b784 1218 /* Properties */
4c213d6c
WC
1219 r = sd_bus_message_open_container(m, 'a', "(sv)");
1220 if (r < 0)
1221 return bus_log_create_error(r);
1222
1223 r = transient_scope_set_properties(m);
1224 if (r < 0)
f53bddf3 1225 return r;
4c213d6c
WC
1226
1227 r = sd_bus_message_close_container(m);
1228 if (r < 0)
1229 return bus_log_create_error(r);
1230
ee451d76 1231 /* Auxiliary units */
4c213d6c 1232 r = sd_bus_message_append(m, "a(sa(sv))", 0);
6c12b52e 1233 if (r < 0)
7040b626 1234 return bus_log_create_error(r);
6c12b52e 1235
8a4b13c5 1236 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
8c7db2fb 1237
de158ed2 1238 r = sd_bus_call(bus, m, 0, &error, &reply);
ee451d76
LP
1239 if (r < 0) {
1240 log_error("Failed to start transient scope unit: %s", bus_error_message(&error, -r));
1241 return r;
1242 }
c2756a68 1243
4de33e7f 1244 if (arg_nice_set) {
4a62c710
MS
1245 if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0)
1246 return log_error_errno(errno, "Failed to set nice level: %m");
4de33e7f
LP
1247 }
1248
1249 if (arg_exec_group) {
1250 gid_t gid;
1251
1252 r = get_group_creds(&arg_exec_group, &gid);
f647962d
MS
1253 if (r < 0)
1254 return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
4de33e7f 1255
4a62c710
MS
1256 if (setresgid(gid, gid, gid) < 0)
1257 return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
4de33e7f
LP
1258 }
1259
1260 if (arg_exec_user) {
1261 const char *home, *shell;
1262 uid_t uid;
1263 gid_t gid;
1264
be39ccf3 1265 r = get_user_creds_clean(&arg_exec_user, &uid, &gid, &home, &shell);
f647962d
MS
1266 if (r < 0)
1267 return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
4de33e7f 1268
be39ccf3
LP
1269 if (home) {
1270 r = strv_extendf(&user_env, "HOME=%s", home);
1271 if (r < 0)
1272 return log_oom();
1273 }
4de33e7f 1274
be39ccf3
LP
1275 if (shell) {
1276 r = strv_extendf(&user_env, "SHELL=%s", shell);
1277 if (r < 0)
1278 return log_oom();
1279 }
4de33e7f
LP
1280
1281 r = strv_extendf(&user_env, "USER=%s", arg_exec_user);
1282 if (r < 0)
1283 return log_oom();
1284
1285 r = strv_extendf(&user_env, "LOGNAME=%s", arg_exec_user);
1286 if (r < 0)
1287 return log_oom();
1288
1289 if (!arg_exec_group) {
4a62c710
MS
1290 if (setresgid(gid, gid, gid) < 0)
1291 return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
4de33e7f
LP
1292 }
1293
4a62c710
MS
1294 if (setresuid(uid, uid, uid) < 0)
1295 return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid);
4de33e7f
LP
1296 }
1297
1298 env = strv_env_merge(3, environ, user_env, arg_environment);
1299 if (!env)
1300 return log_oom();
1301
de158ed2
LP
1302 r = sd_bus_message_read(reply, "o", &object);
1303 if (r < 0)
1304 return bus_log_parse_error(r);
1305
1306 r = bus_wait_for_jobs_one(w, object, arg_quiet);
1307 if (r < 0)
1308 return r;
1309
095dc596 1310 if (!arg_quiet)
f3ea87af 1311 log_info("Running scope as unit: %s", scope);
7040b626 1312
4de33e7f 1313 execvpe(argv[0], argv, env);
9b15b784
LP
1314
1315 return log_error_errno(errno, "Failed to execute: %m");
1316}
1317
1318static int start_transient_timer(
1319 sd_bus *bus,
ee451d76 1320 char **argv) {
9b15b784 1321
4afd3348
LP
1322 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1323 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
de158ed2 1324 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
9b15b784 1325 _cleanup_free_ char *timer = NULL, *service = NULL;
de158ed2 1326 const char *object = NULL;
9b15b784
LP
1327 int r;
1328
1329 assert(bus);
1330 assert(argv);
1331
de158ed2
LP
1332 r = bus_wait_for_jobs_new(bus, &w);
1333 if (r < 0)
1334 return log_oom();
1335
9b15b784 1336 if (arg_unit) {
7410616c 1337 switch (unit_name_to_type(arg_unit)) {
9b15b784
LP
1338
1339 case UNIT_SERVICE:
1340 service = strdup(arg_unit);
1341 if (!service)
1342 return log_oom();
1343
7410616c
LP
1344 r = unit_name_change_suffix(service, ".timer", &timer);
1345 if (r < 0)
1346 return log_error_errno(r, "Failed to change unit suffix: %m");
9b15b784
LP
1347 break;
1348
1349 case UNIT_TIMER:
1350 timer = strdup(arg_unit);
1351 if (!timer)
1352 return log_oom();
1353
7410616c
LP
1354 r = unit_name_change_suffix(timer, ".service", &service);
1355 if (r < 0)
1356 return log_error_errno(r, "Failed to change unit suffix: %m");
9b15b784
LP
1357 break;
1358
1359 default:
7410616c
LP
1360 r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".service", &service);
1361 if (r < 0)
1362 return log_error_errno(r, "Failed to mangle unit name: %m");
9b15b784 1363
7410616c
LP
1364 r = unit_name_mangle_with_suffix(arg_unit, UNIT_NAME_NOGLOB, ".timer", &timer);
1365 if (r < 0)
1366 return log_error_errno(r, "Failed to mangle unit name: %m");
9b15b784
LP
1367
1368 break;
1369 }
9c8d1e1a
LP
1370 } else {
1371 r = make_unit_name(bus, UNIT_SERVICE, &service);
1372 if (r < 0)
1373 return r;
1374
1375 r = unit_name_change_suffix(service, ".timer", &timer);
1376 if (r < 0)
1377 return log_error_errno(r, "Failed to change unit suffix: %m");
1378 }
9b15b784
LP
1379
1380 r = sd_bus_message_new_method_call(
1381 bus,
1382 &m,
1383 "org.freedesktop.systemd1",
1384 "/org/freedesktop/systemd1",
1385 "org.freedesktop.systemd1.Manager",
1386 "StartTransientUnit");
1387 if (r < 0)
1388 return bus_log_create_error(r);
1389
8c7db2fb
EV
1390 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1391 if (r < 0)
1392 return bus_log_create_error(r);
1393
9b15b784
LP
1394 /* Name and Mode */
1395 r = sd_bus_message_append(m, "ss", timer, "fail");
1396 if (r < 0)
1397 return bus_log_create_error(r);
1398
1399 /* Properties */
1400 r = sd_bus_message_open_container(m, 'a', "(sv)");
1401 if (r < 0)
1402 return bus_log_create_error(r);
1403
1404 r = transient_timer_set_properties(m);
1405 if (r < 0)
f53bddf3 1406 return r;
9b15b784
LP
1407
1408 r = sd_bus_message_close_container(m);
1409 if (r < 0)
1410 return bus_log_create_error(r);
1411
1412 r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
1413 if (r < 0)
1414 return bus_log_create_error(r);
1415
ad2c1701 1416 if (!strv_isempty(argv)) {
9b15b784
LP
1417 r = sd_bus_message_open_container(m, 'r', "sa(sv)");
1418 if (r < 0)
1419 return bus_log_create_error(r);
1420
1421 r = sd_bus_message_append(m, "s", service);
1422 if (r < 0)
1423 return bus_log_create_error(r);
1424
1425 r = sd_bus_message_open_container(m, 'a', "(sv)");
1426 if (r < 0)
1427 return bus_log_create_error(r);
1428
1429 r = transient_service_set_properties(m, argv, NULL);
1430 if (r < 0)
f53bddf3 1431 return r;
9b15b784
LP
1432
1433 r = sd_bus_message_close_container(m);
1434 if (r < 0)
1435 return bus_log_create_error(r);
1436
1437 r = sd_bus_message_close_container(m);
1438 if (r < 0)
1439 return bus_log_create_error(r);
1440 }
1441
1442 r = sd_bus_message_close_container(m);
1443 if (r < 0)
1444 return bus_log_create_error(r);
1445
8a4b13c5 1446 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
8c7db2fb 1447
de158ed2 1448 r = sd_bus_call(bus, m, 0, &error, &reply);
ee451d76
LP
1449 if (r < 0) {
1450 log_error("Failed to start transient timer unit: %s", bus_error_message(&error, -r));
1451 return r;
1452 }
9b15b784 1453
de158ed2
LP
1454 r = sd_bus_message_read(reply, "o", &object);
1455 if (r < 0)
1456 return bus_log_parse_error(r);
1457
1458 r = bus_wait_for_jobs_one(w, object, arg_quiet);
1459 if (r < 0)
1460 return r;
1461
3dea75de
NO
1462 if (!arg_quiet) {
1463 log_info("Running timer as unit: %s", timer);
1464 if (argv[0])
1465 log_info("Will run service as unit: %s", service);
1466 }
9b15b784
LP
1467
1468 return 0;
c2756a68
LP
1469}
1470
1471int main(int argc, char* argv[]) {
4afd3348 1472 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
c9d954b2 1473 _cleanup_free_ char *description = NULL, *command = NULL;
2a453c2e 1474 int r, retval = EXIT_SUCCESS;
c2756a68
LP
1475
1476 log_parse_environment();
1477 log_open();
1478
6c12b52e
LP
1479 r = parse_argv(argc, argv);
1480 if (r <= 0)
66b1e746 1481 goto finish;
c2756a68 1482
85eca92e
LP
1483 if (argc > optind && arg_transport == BUS_TRANSPORT_LOCAL) {
1484 /* Patch in an absolute path */
1485
1486 r = find_binary(argv[optind], &command);
4c213d6c 1487 if (r < 0) {
85eca92e
LP
1488 log_error_errno(r, "Failed to find executable %s: %m", argv[optind]);
1489 goto finish;
1490 }
85eca92e 1491
4c213d6c 1492 argv[optind] = command;
c9d954b2 1493 }
c9d954b2 1494
9f2e86af
LP
1495 if (!arg_description) {
1496 description = strv_join(argv + optind, " ");
1497 if (!description) {
1498 r = log_oom();
66b1e746 1499 goto finish;
9f2e86af
LP
1500 }
1501
4c213d6c 1502 if (arg_unit && isempty(description)) {
2fc09a9c
DM
1503 r = free_and_strdup(&description, arg_unit);
1504 if (r < 0)
4c213d6c 1505 goto finish;
4c213d6c
WC
1506 }
1507
9f2e86af
LP
1508 arg_description = description;
1509 }
1510
2a453c2e
LP
1511 /* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
1512 * connection */
5dca7739 1513 if (arg_wait || arg_stdio != ARG_STDIO_NONE)
2a453c2e
LP
1514 r = bus_connect_transport(arg_transport, arg_host, arg_user, &bus);
1515 else
1516 r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus);
c2756a68 1517 if (r < 0) {
da927ba9 1518 log_error_errno(r, "Failed to create bus connection: %m");
66b1e746 1519 goto finish;
c2756a68
LP
1520 }
1521
6c12b52e 1522 if (arg_scope)
ee451d76 1523 r = start_transient_scope(bus, argv + optind);
4c213d6c 1524 else if (with_timer())
ee451d76 1525 r = start_transient_timer(bus, argv + optind);
6c12b52e 1526 else
2a453c2e 1527 r = start_transient_service(bus, argv + optind, &retval);
c2756a68 1528
66b1e746 1529finish:
df31a6c0
LP
1530 strv_free(arg_environment);
1531 strv_free(arg_property);
4c213d6c 1532 strv_free(arg_timer_property);
df31a6c0 1533
2a453c2e 1534 return r < 0 ? EXIT_FAILURE : retval;
c2756a68 1535}