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