1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
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.
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.
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/>.
27 #include "alloc-util.h"
28 #include "bus-error.h"
29 #include "bus-unit-util.h"
31 #include "calendarspec.h"
34 #include "format-util.h"
35 #include "parse-util.h"
36 #include "path-util.h"
37 #include "process-util.h"
39 #include "signal-util.h"
40 #include "spawn-polkit-agent.h"
42 #include "terminal-util.h"
44 #include "unit-name.h"
45 #include "user-util.h"
47 static bool arg_ask_password
= true;
48 static bool arg_scope
= false;
49 static bool arg_remain_after_exit
= false;
50 static bool arg_no_block
= false;
51 static bool arg_wait
= false;
52 static const char *arg_unit
= NULL
;
53 static const char *arg_description
= NULL
;
54 static const char *arg_slice
= NULL
;
55 static bool arg_send_sighup
= false;
56 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
57 static const char *arg_host
= NULL
;
58 static bool arg_user
= false;
59 static const char *arg_service_type
= NULL
;
60 static const char *arg_exec_user
= NULL
;
61 static const char *arg_exec_group
= NULL
;
62 static int arg_nice
= 0;
63 static bool arg_nice_set
= false;
64 static char **arg_environment
= NULL
;
65 static char **arg_property
= NULL
;
67 ARG_STDIO_NONE
, /* The default, as it is for normal services, stdin connected to /dev/null, and stdout+stderr to the journal */
68 ARG_STDIO_PTY
, /* Interactive behaviour, requested by --pty: we allocate a pty and connect it to the TTY we are invoked from */
69 ARG_STDIO_DIRECT
, /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
70 ARG_STDIO_AUTO
, /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
71 } arg_stdio
= ARG_STDIO_NONE
;
72 static char **arg_path_property
= NULL
;
73 static char **arg_socket_property
= NULL
;
74 static char **arg_timer_property
= NULL
;
75 static bool with_timer
= false;
76 static bool arg_quiet
= false;
77 static bool arg_aggressive_gc
= false;
79 static void help(void) {
80 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
81 "Run the specified command in a transient scope or service.\n\n"
82 " -h --help Show this help\n"
83 " --version Show package version\n"
84 " --no-ask-password Do not prompt for password\n"
85 " --user Run as user unit\n"
86 " -H --host=[USER@]HOST Operate on remote host\n"
87 " -M --machine=CONTAINER Operate on local container\n"
88 " --scope Run this as scope rather than service\n"
89 " --unit=UNIT Run under the specified unit name\n"
90 " -p --property=NAME=VALUE Set service or scope unit property\n"
91 " --description=TEXT Description for unit\n"
92 " --slice=SLICE Run in the specified slice\n"
93 " --no-block Do not wait until operation finished\n"
94 " -r --remain-after-exit Leave service around until explicitly stopped\n"
95 " --wait Wait until service stopped again\n"
96 " --send-sighup Send SIGHUP when terminating\n"
97 " --service-type=TYPE Service type\n"
98 " --uid=USER Run as system user\n"
99 " --gid=GROUP Run as system group\n"
100 " --nice=NICE Nice level\n"
101 " -E --setenv=NAME=VALUE Set environment\n"
102 " -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
104 " -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
105 " -q --quiet Suppress information messages during runtime\n"
106 " -G --collect Unload unit after it ran, even when failed\n\n"
108 " --path-property=NAME=VALUE Set path unit property\n\n"
110 " --socket-property=NAME=VALUE Set socket unit property\n\n"
112 " --on-active=SECONDS Run after SECONDS delay\n"
113 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
114 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
115 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
116 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
117 " --on-calendar=SPEC Realtime timer\n"
118 " --timer-property=NAME=VALUE Set timer unit property\n"
119 , program_invocation_short_name
);
122 static int add_timer_property(const char *name
, const char *val
) {
123 _cleanup_free_
char *p
= NULL
;
128 p
= strjoin(name
, "=", val
);
132 if (strv_consume(&arg_timer_property
, p
) < 0)
140 static int parse_argv(int argc
, char *argv
[]) {
159 ARG_ON_UNIT_INACTIVE
,
169 static const struct option options
[] = {
170 { "help", no_argument
, NULL
, 'h' },
171 { "version", no_argument
, NULL
, ARG_VERSION
},
172 { "user", no_argument
, NULL
, ARG_USER
},
173 { "system", no_argument
, NULL
, ARG_SYSTEM
},
174 { "scope", no_argument
, NULL
, ARG_SCOPE
},
175 { "unit", required_argument
, NULL
, ARG_UNIT
},
176 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
177 { "slice", required_argument
, NULL
, ARG_SLICE
},
178 { "remain-after-exit", no_argument
, NULL
, 'r' },
179 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
180 { "host", required_argument
, NULL
, 'H' },
181 { "machine", required_argument
, NULL
, 'M' },
182 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
183 { "wait", no_argument
, NULL
, ARG_WAIT
},
184 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
185 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
186 { "nice", required_argument
, NULL
, ARG_NICE
},
187 { "setenv", required_argument
, NULL
, 'E' },
188 { "property", required_argument
, NULL
, 'p' },
189 { "tty", no_argument
, NULL
, 't' }, /* deprecated alias */
190 { "pty", no_argument
, NULL
, 't' },
191 { "pipe", no_argument
, NULL
, 'P' },
192 { "quiet", no_argument
, NULL
, 'q' },
193 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
194 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
195 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
196 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
197 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
198 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
199 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
200 { "path-property", required_argument
, NULL
, ARG_PATH_PROPERTY
},
201 { "socket-property", required_argument
, NULL
, ARG_SOCKET_PROPERTY
},
202 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
203 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
204 { "collect", no_argument
, NULL
, 'G' },
208 bool with_trigger
= false;
214 while ((c
= getopt_long(argc
, argv
, "+hrH:M:E:p:tPqG", options
, NULL
)) >= 0)
225 case ARG_NO_ASK_PASSWORD
:
226 arg_ask_password
= false;
245 case ARG_DESCRIPTION
:
246 arg_description
= optarg
;
253 case ARG_SEND_SIGHUP
:
254 arg_send_sighup
= true;
258 arg_remain_after_exit
= true;
262 arg_transport
= BUS_TRANSPORT_REMOTE
;
267 arg_transport
= BUS_TRANSPORT_MACHINE
;
271 case ARG_SERVICE_TYPE
:
272 arg_service_type
= optarg
;
276 arg_exec_user
= optarg
;
280 arg_exec_group
= optarg
;
284 r
= parse_nice(optarg
, &arg_nice
);
286 return log_error_errno(r
, "Failed to parse nice value: %s", optarg
);
292 if (strv_extend(&arg_environment
, optarg
) < 0)
298 if (strv_extend(&arg_property
, optarg
) < 0)
303 case 't': /* --pty */
304 if (IN_SET(arg_stdio
, ARG_STDIO_DIRECT
, ARG_STDIO_AUTO
)) /* if --pipe is already used, upgrade to auto mode */
305 arg_stdio
= ARG_STDIO_AUTO
;
307 arg_stdio
= ARG_STDIO_PTY
;
310 case 'P': /* --pipe */
311 if (IN_SET(arg_stdio
, ARG_STDIO_PTY
, ARG_STDIO_AUTO
)) /* If --pty is already used, upgrade to auto mode */
312 arg_stdio
= ARG_STDIO_AUTO
;
314 arg_stdio
= ARG_STDIO_DIRECT
;
322 r
= add_timer_property("OnActiveSec", optarg
);
330 r
= add_timer_property("OnBootSec", optarg
);
338 r
= add_timer_property("OnStartupSec", optarg
);
345 case ARG_ON_UNIT_ACTIVE
:
346 r
= add_timer_property("OnUnitActiveSec", optarg
);
353 case ARG_ON_UNIT_INACTIVE
:
354 r
= add_timer_property("OnUnitInactiveSec", optarg
);
361 case ARG_ON_CALENDAR
:
362 r
= add_timer_property("OnCalendar", optarg
);
369 case ARG_TIMER_PROPERTY
:
371 if (strv_extend(&arg_timer_property
, optarg
) < 0)
374 with_timer
= with_timer
||
375 !!startswith(optarg
, "OnActiveSec=") ||
376 !!startswith(optarg
, "OnBootSec=") ||
377 !!startswith(optarg
, "OnStartupSec=") ||
378 !!startswith(optarg
, "OnUnitActiveSec=") ||
379 !!startswith(optarg
, "OnUnitInactiveSec=") ||
380 !!startswith(optarg
, "OnCalendar=");
383 case ARG_PATH_PROPERTY
:
385 if (strv_extend(&arg_path_property
, optarg
) < 0)
390 case ARG_SOCKET_PROPERTY
:
392 if (strv_extend(&arg_socket_property
, optarg
) < 0)
406 arg_aggressive_gc
= true;
413 assert_not_reached("Unhandled option");
416 with_trigger
= !!arg_path_property
|| !!arg_socket_property
|| with_timer
;
418 /* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
419 if ((int) !!arg_path_property
+ (int) !!arg_socket_property
+ (int) with_timer
> 1) {
420 log_error("Only single trigger (path, socket, timer) unit can be created.");
424 if (arg_stdio
== ARG_STDIO_AUTO
) {
425 /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
426 * to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
427 * pipeline, but we are neatly interactive with tty-level isolation otherwise. */
428 arg_stdio
= isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
) && isatty(STDERR_FILENO
) ?
433 if ((optind
>= argc
) && (!arg_unit
|| !with_trigger
)) {
434 log_error("Command line to execute required.");
438 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
439 log_error("Execution in user context is not supported on non-local systems.");
443 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
444 log_error("Scope execution is not supported on non-local systems.");
448 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
449 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
453 if (arg_stdio
!= ARG_STDIO_NONE
&& (with_trigger
|| arg_scope
)) {
454 log_error("--pty/--pipe is not compatible in timer or --scope mode.");
458 if (arg_stdio
!= ARG_STDIO_NONE
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
459 log_error("--pty/--pipe is only supported when connecting to the local system or containers.");
463 if (arg_stdio
!= ARG_STDIO_NONE
&& arg_no_block
) {
464 log_error("--pty/--pipe is not compatible with --no-block.");
468 if (arg_scope
&& with_trigger
) {
469 log_error("Path, socket or timer options are not supported in --scope mode.");
473 if (arg_timer_property
&& !with_timer
) {
474 log_error("--timer-property= has no effect without any other timer options.");
480 log_error("--wait may not be combined with --no-block.");
485 log_error("--wait may not be combined with path, socket or timer operations.");
490 log_error("--wait may not be combined with --scope.");
498 static int transient_unit_set_properties(sd_bus_message
*m
, UnitType t
, char **properties
) {
501 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
503 return bus_log_create_error(r
);
505 if (arg_aggressive_gc
) {
506 r
= sd_bus_message_append(m
, "(sv)", "CollectMode", "s", "inactive-or-failed");
508 return bus_log_create_error(r
);
511 r
= bus_append_unit_property_assignment_many(m
, t
, properties
);
518 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
522 if (!isempty(arg_slice
)) {
523 _cleanup_free_
char *slice
= NULL
;
525 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
527 return log_error_errno(r
, "Failed to mangle name '%s': %m", arg_slice
);
529 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
531 return bus_log_create_error(r
);
537 static int transient_kill_set_properties(sd_bus_message
*m
) {
542 if (arg_send_sighup
) {
543 r
= sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
545 return bus_log_create_error(r
);
551 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
552 bool send_term
= false;
557 r
= transient_unit_set_properties(m
, UNIT_SERVICE
, arg_property
);
561 r
= transient_kill_set_properties(m
);
565 r
= transient_cgroup_set_properties(m
);
569 if (arg_wait
|| arg_stdio
!= ARG_STDIO_NONE
) {
570 r
= sd_bus_message_append(m
, "(sv)", "AddRef", "b", 1);
572 return bus_log_create_error(r
);
575 if (arg_remain_after_exit
) {
576 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
578 return bus_log_create_error(r
);
581 if (arg_service_type
) {
582 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
584 return bus_log_create_error(r
);
588 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
590 return bus_log_create_error(r
);
593 if (arg_exec_group
) {
594 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
596 return bus_log_create_error(r
);
600 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
602 return bus_log_create_error(r
);
606 r
= sd_bus_message_append(m
,
608 "StandardInput", "s", "tty",
609 "StandardOutput", "s", "tty",
610 "StandardError", "s", "tty",
611 "TTYPath", "s", pty_path
);
613 return bus_log_create_error(r
);
617 } else if (arg_stdio
== ARG_STDIO_DIRECT
) {
618 r
= sd_bus_message_append(m
,
620 "StandardInputFileDescriptor", "h", STDIN_FILENO
,
621 "StandardOutputFileDescriptor", "h", STDOUT_FILENO
,
622 "StandardErrorFileDescriptor", "h", STDERR_FILENO
);
624 return bus_log_create_error(r
);
626 send_term
= isatty(STDIN_FILENO
) || isatty(STDOUT_FILENO
) || isatty(STDERR_FILENO
);
636 n
= strjoina("TERM=", e
);
637 r
= sd_bus_message_append(m
,
639 "Environment", "as", 1, n
);
641 return bus_log_create_error(r
);
645 if (!strv_isempty(arg_environment
)) {
646 r
= sd_bus_message_open_container(m
, 'r', "sv");
648 return bus_log_create_error(r
);
650 r
= sd_bus_message_append(m
, "s", "Environment");
652 return bus_log_create_error(r
);
654 r
= sd_bus_message_open_container(m
, 'v', "as");
656 return bus_log_create_error(r
);
658 r
= sd_bus_message_append_strv(m
, arg_environment
);
660 return bus_log_create_error(r
);
662 r
= sd_bus_message_close_container(m
);
664 return bus_log_create_error(r
);
666 r
= sd_bus_message_close_container(m
);
668 return bus_log_create_error(r
);
673 r
= sd_bus_message_open_container(m
, 'r', "sv");
675 return bus_log_create_error(r
);
677 r
= sd_bus_message_append(m
, "s", "ExecStart");
679 return bus_log_create_error(r
);
681 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
683 return bus_log_create_error(r
);
685 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
687 return bus_log_create_error(r
);
689 r
= sd_bus_message_open_container(m
, 'r', "sasb");
691 return bus_log_create_error(r
);
693 r
= sd_bus_message_append(m
, "s", argv
[0]);
695 return bus_log_create_error(r
);
697 r
= sd_bus_message_append_strv(m
, argv
);
699 return bus_log_create_error(r
);
701 r
= sd_bus_message_append(m
, "b", false);
703 return bus_log_create_error(r
);
705 r
= sd_bus_message_close_container(m
);
707 return bus_log_create_error(r
);
709 r
= sd_bus_message_close_container(m
);
711 return bus_log_create_error(r
);
713 r
= sd_bus_message_close_container(m
);
715 return bus_log_create_error(r
);
717 r
= sd_bus_message_close_container(m
);
719 return bus_log_create_error(r
);
725 static int transient_scope_set_properties(sd_bus_message
*m
) {
730 r
= transient_unit_set_properties(m
, UNIT_SCOPE
, arg_property
);
734 r
= transient_kill_set_properties(m
);
738 r
= transient_cgroup_set_properties(m
);
742 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid_cached());
744 return bus_log_create_error(r
);
749 static int transient_timer_set_properties(sd_bus_message
*m
) {
754 r
= transient_unit_set_properties(m
, UNIT_TIMER
, arg_timer_property
);
758 /* Automatically clean up our transient timers */
759 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterElapse", "b", false);
761 return bus_log_create_error(r
);
766 static int make_unit_name(sd_bus
*bus
, UnitType t
, char **ret
) {
767 const char *unique
, *id
;
773 assert(t
< _UNIT_TYPE_MAX
);
775 r
= sd_bus_get_unique_name(bus
, &unique
);
779 /* We couldn't get the unique name, which is a pretty
780 * common case if we are connected to systemd
781 * directly. In that case, just pick a random uuid as
784 r
= sd_id128_randomize(&rnd
);
786 return log_error_errno(r
, "Failed to generate random run unit name: %m");
788 if (asprintf(ret
, "run-r" SD_ID128_FORMAT_STR
".%s", SD_ID128_FORMAT_VAL(rnd
), unit_type_to_string(t
)) < 0)
794 /* We managed to get the unique name, then let's use that to
795 * name our transient units. */
797 id
= startswith(unique
, ":1.");
799 log_error("Unique name %s has unexpected format.", unique
);
803 p
= strjoin("run-u", id
, ".", unit_type_to_string(t
));
811 typedef struct RunContext
{
817 /* The exit data of the unit */
819 uint64_t inactive_exit_usec
;
820 uint64_t inactive_enter_usec
;
822 uint64_t cpu_usage_nsec
;
823 uint64_t ip_ingress_bytes
;
824 uint64_t ip_egress_bytes
;
826 uint32_t exit_status
;
829 static void run_context_free(RunContext
*c
) {
832 c
->forward
= pty_forward_free(c
->forward
);
833 c
->match
= sd_bus_slot_unref(c
->match
);
834 c
->bus
= sd_bus_unref(c
->bus
);
835 c
->event
= sd_event_unref(c
->event
);
837 free(c
->active_state
);
841 static void run_context_check_done(RunContext
*c
) {
847 done
= STRPTR_IN_SET(c
->active_state
, "inactive", "failed");
851 if (c
->forward
&& done
) /* If the service is gone, it's time to drain the output */
852 done
= pty_forward_drain(c
->forward
);
855 sd_event_exit(c
->event
, EXIT_SUCCESS
);
858 static int run_context_update(RunContext
*c
, const char *path
) {
860 static const struct bus_properties_map map
[] = {
861 { "ActiveState", "s", NULL
, offsetof(RunContext
, active_state
) },
862 { "InactiveExitTimestampMonotonic", "t", NULL
, offsetof(RunContext
, inactive_exit_usec
) },
863 { "InactiveEnterTimestampMonotonic", "t", NULL
, offsetof(RunContext
, inactive_enter_usec
) },
864 { "Result", "s", NULL
, offsetof(RunContext
, result
) },
865 { "ExecMainCode", "i", NULL
, offsetof(RunContext
, exit_code
) },
866 { "ExecMainStatus", "i", NULL
, offsetof(RunContext
, exit_status
) },
867 { "CPUUsageNSec", "t", NULL
, offsetof(RunContext
, cpu_usage_nsec
) },
868 { "IPIngressBytes", "t", NULL
, offsetof(RunContext
, ip_ingress_bytes
) },
869 { "IPEgressBytes", "t", NULL
, offsetof(RunContext
, ip_egress_bytes
) },
873 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
876 r
= bus_map_all_properties(c
->bus
,
877 "org.freedesktop.systemd1",
883 sd_event_exit(c
->event
, EXIT_FAILURE
);
884 return log_error_errno(r
, "Failed to query unit state: %s", bus_error_message(&error
, r
));
887 run_context_check_done(c
);
891 static int on_properties_changed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
892 RunContext
*c
= userdata
;
897 return run_context_update(c
, sd_bus_message_get_path(m
));
900 static int pty_forward_handler(PTYForward
*f
, int rcode
, void *userdata
) {
901 RunContext
*c
= userdata
;
906 sd_event_exit(c
->event
, EXIT_FAILURE
);
907 return log_error_errno(rcode
, "Error on PTY forwarding logic: %m");
910 run_context_check_done(c
);
914 static int start_transient_service(
919 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
920 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
921 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
922 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
923 _cleanup_close_
int master
= -1;
930 if (arg_stdio
== ARG_STDIO_PTY
) {
932 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
933 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
935 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
937 r
= ptsname_malloc(master
, &pty_path
);
939 return log_error_errno(r
, "Failed to determine tty name: %m");
941 if (unlockpt(master
) < 0)
942 return log_error_errno(errno
, "Failed to unlock tty: %m");
944 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
945 _cleanup_(sd_bus_unrefp
) sd_bus
*system_bus
= NULL
;
946 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pty_reply
= NULL
;
949 r
= sd_bus_default_system(&system_bus
);
951 return log_error_errno(r
, "Failed to connect to system bus: %m");
953 r
= sd_bus_call_method(system_bus
,
954 "org.freedesktop.machine1",
955 "/org/freedesktop/machine1",
956 "org.freedesktop.machine1.Manager",
962 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
966 r
= sd_bus_message_read(pty_reply
, "hs", &master
, &s
);
968 return bus_log_parse_error(r
);
970 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
972 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
974 pty_path
= strdup(s
);
978 assert_not_reached("Can't allocate tty via ssh");
982 r
= bus_wait_for_jobs_new(bus
, &w
);
984 return log_error_errno(r
, "Could not watch jobs: %m");
988 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
990 return log_error_errno(r
, "Failed to mangle unit name: %m");
992 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
997 r
= sd_bus_message_new_method_call(
1000 "org.freedesktop.systemd1",
1001 "/org/freedesktop/systemd1",
1002 "org.freedesktop.systemd1.Manager",
1003 "StartTransientUnit");
1005 return bus_log_create_error(r
);
1007 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1009 return bus_log_create_error(r
);
1012 r
= sd_bus_message_append(m
, "ss", service
, "fail");
1014 return bus_log_create_error(r
);
1017 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1019 return bus_log_create_error(r
);
1021 r
= transient_service_set_properties(m
, argv
, pty_path
);
1025 r
= sd_bus_message_close_container(m
);
1027 return bus_log_create_error(r
);
1029 /* Auxiliary units */
1030 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1032 return bus_log_create_error(r
);
1034 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1036 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1038 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
1043 r
= sd_bus_message_read(reply
, "o", &object
);
1045 return bus_log_parse_error(r
);
1047 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1053 log_info("Running as unit: %s", service
);
1055 if (arg_wait
|| arg_stdio
!= ARG_STDIO_NONE
) {
1056 _cleanup_(run_context_free
) RunContext c
= {
1057 .cpu_usage_nsec
= NSEC_INFINITY
,
1058 .ip_ingress_bytes
= UINT64_MAX
,
1059 .ip_egress_bytes
= UINT64_MAX
,
1060 .inactive_exit_usec
= USEC_INFINITY
,
1061 .inactive_enter_usec
= USEC_INFINITY
,
1063 _cleanup_free_
char *path
= NULL
;
1066 c
.bus
= sd_bus_ref(bus
);
1068 r
= sd_event_default(&c
.event
);
1070 return log_error_errno(r
, "Failed to get event loop: %m");
1073 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
1074 (void) sd_event_add_signal(c
.event
, NULL
, SIGINT
, NULL
, NULL
);
1075 (void) sd_event_add_signal(c
.event
, NULL
, SIGTERM
, NULL
, NULL
);
1078 log_info("Press ^] three times within 1s to disconnect TTY.");
1080 r
= pty_forward_new(c
.event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &c
.forward
);
1082 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
1084 pty_forward_set_handler(c
.forward
, pty_forward_handler
, &c
);
1086 /* Make sure to process any TTY events before we process bus events */
1087 (void) pty_forward_set_priority(c
.forward
, SD_EVENT_PRIORITY_IMPORTANT
);
1090 path
= unit_dbus_path_from_name(service
);
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
);
1101 return log_error_errno(r
, "Failed to add properties changed signal.");
1103 r
= sd_bus_attach_event(bus
, c
.event
, SD_EVENT_PRIORITY_NORMAL
);
1105 return log_error_errno(r
, "Failed to attach bus to event loop.");
1107 r
= run_context_update(&c
, path
);
1111 r
= sd_event_loop(c
.event
);
1113 return log_error_errno(r
, "Failed to run event loop: %m");
1118 r
= pty_forward_get_last_char(c
.forward
, &last_char
);
1119 if (r
>= 0 && !arg_quiet
&& last_char
!= '\n')
1120 fputc('\n', stdout
);
1123 if (arg_wait
&& !arg_quiet
) {
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
1128 c
.forward
= pty_forward_free(c
.forward
);
1130 if (!isempty(c
.result
))
1131 log_info("Finished with result: %s", strna(c
.result
));
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
));
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
));
1145 if (c
.cpu_usage_nsec
!= NSEC_INFINITY
) {
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
));
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
));
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
));
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
;
1164 *retval
= EXIT_FAILURE
;
1170 static int start_transient_scope(
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
;
1176 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1177 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
1178 _cleanup_free_
char *scope
= NULL
;
1179 const char *object
= NULL
;
1185 r
= bus_wait_for_jobs_new(bus
, &w
);
1190 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
1192 return log_error_errno(r
, "Failed to mangle scope name: %m");
1194 r
= make_unit_name(bus
, UNIT_SCOPE
, &scope
);
1199 r
= sd_bus_message_new_method_call(
1202 "org.freedesktop.systemd1",
1203 "/org/freedesktop/systemd1",
1204 "org.freedesktop.systemd1.Manager",
1205 "StartTransientUnit");
1207 return bus_log_create_error(r
);
1209 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1211 return bus_log_create_error(r
);
1214 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
1216 return bus_log_create_error(r
);
1219 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1221 return bus_log_create_error(r
);
1223 r
= transient_scope_set_properties(m
);
1227 r
= sd_bus_message_close_container(m
);
1229 return bus_log_create_error(r
);
1231 /* Auxiliary units */
1232 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1234 return bus_log_create_error(r
);
1236 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1238 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1240 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
1245 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
1246 return log_error_errno(errno
, "Failed to set nice level: %m");
1249 if (arg_exec_group
) {
1252 r
= get_group_creds(&arg_exec_group
, &gid
);
1254 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
1256 if (setresgid(gid
, gid
, gid
) < 0)
1257 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1260 if (arg_exec_user
) {
1261 const char *home
, *shell
;
1265 r
= get_user_creds_clean(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
1267 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
1270 r
= strv_extendf(&user_env
, "HOME=%s", home
);
1276 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
1281 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
1285 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
1289 if (!arg_exec_group
) {
1290 if (setresgid(gid
, gid
, gid
) < 0)
1291 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1294 if (setresuid(uid
, uid
, uid
) < 0)
1295 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
1298 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
1302 r
= sd_bus_message_read(reply
, "o", &object
);
1304 return bus_log_parse_error(r
);
1306 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1311 log_info("Running scope as unit: %s", scope
);
1313 execvpe(argv
[0], argv
, env
);
1315 return log_error_errno(errno
, "Failed to execute: %m");
1318 static int start_transient_trigger(
1321 const char *suffix
) {
1323 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1324 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1325 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1326 _cleanup_free_
char *trigger
= NULL
, *service
= NULL
;
1327 const char *object
= NULL
;
1333 r
= bus_wait_for_jobs_new(bus
, &w
);
1338 switch (unit_name_to_type(arg_unit
)) {
1341 service
= strdup(arg_unit
);
1345 r
= unit_name_change_suffix(service
, suffix
, &trigger
);
1347 return log_error_errno(r
, "Failed to change unit suffix: %m");
1351 trigger
= strdup(arg_unit
);
1355 r
= unit_name_change_suffix(trigger
, ".service", &service
);
1357 return log_error_errno(r
, "Failed to change unit suffix: %m");
1361 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1363 return log_error_errno(r
, "Failed to mangle unit name: %m");
1365 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, suffix
, &trigger
);
1367 return log_error_errno(r
, "Failed to mangle unit name: %m");
1372 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
1376 r
= unit_name_change_suffix(service
, suffix
, &trigger
);
1378 return log_error_errno(r
, "Failed to change unit suffix: %m");
1381 r
= sd_bus_message_new_method_call(
1384 "org.freedesktop.systemd1",
1385 "/org/freedesktop/systemd1",
1386 "org.freedesktop.systemd1.Manager",
1387 "StartTransientUnit");
1389 return bus_log_create_error(r
);
1391 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1393 return bus_log_create_error(r
);
1396 r
= sd_bus_message_append(m
, "ss", trigger
, "fail");
1398 return bus_log_create_error(r
);
1401 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1403 return bus_log_create_error(r
);
1405 if (streq(suffix
, ".path"))
1406 r
= transient_unit_set_properties(m
, UNIT_PATH
, arg_path_property
);
1407 else if (streq(suffix
, ".socket"))
1408 r
= transient_unit_set_properties(m
, UNIT_SOCKET
, arg_socket_property
);
1409 else if (streq(suffix
, ".timer"))
1410 r
= transient_timer_set_properties(m
);
1412 assert_not_reached("Invalid suffix");
1416 r
= sd_bus_message_close_container(m
);
1418 return bus_log_create_error(r
);
1420 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1422 return bus_log_create_error(r
);
1424 if (!strv_isempty(argv
)) {
1425 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1427 return bus_log_create_error(r
);
1429 r
= sd_bus_message_append(m
, "s", service
);
1431 return bus_log_create_error(r
);
1433 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1435 return bus_log_create_error(r
);
1437 r
= transient_service_set_properties(m
, argv
, NULL
);
1441 r
= sd_bus_message_close_container(m
);
1443 return bus_log_create_error(r
);
1445 r
= sd_bus_message_close_container(m
);
1447 return bus_log_create_error(r
);
1450 r
= sd_bus_message_close_container(m
);
1452 return bus_log_create_error(r
);
1454 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1456 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1458 log_error("Failed to start transient %s unit: %s", suffix
+ 1, bus_error_message(&error
, -r
));
1462 r
= sd_bus_message_read(reply
, "o", &object
);
1464 return bus_log_parse_error(r
);
1466 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1471 log_info("Running %s as unit: %s", suffix
+ 1, trigger
);
1473 log_info("Will run service as unit: %s", service
);
1479 int main(int argc
, char* argv
[]) {
1480 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1481 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1482 int r
, retval
= EXIT_SUCCESS
;
1484 log_parse_environment();
1487 r
= parse_argv(argc
, argv
);
1491 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1492 /* Patch in an absolute path */
1494 r
= find_binary(argv
[optind
], &command
);
1496 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1500 argv
[optind
] = command
;
1503 if (!arg_description
) {
1504 description
= strv_join(argv
+ optind
, " ");
1510 if (arg_unit
&& isempty(description
)) {
1511 r
= free_and_strdup(&description
, arg_unit
);
1516 arg_description
= description
;
1519 /* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
1521 if (arg_wait
|| arg_stdio
!= ARG_STDIO_NONE
)
1522 r
= bus_connect_transport(arg_transport
, arg_host
, arg_user
, &bus
);
1524 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1526 log_error_errno(r
, "Failed to create bus connection: %m");
1531 r
= start_transient_scope(bus
, argv
+ optind
);
1532 else if (arg_path_property
)
1533 r
= start_transient_trigger(bus
, argv
+ optind
, ".path");
1534 else if (arg_socket_property
)
1535 r
= start_transient_trigger(bus
, argv
+ optind
, ".socket");
1536 else if (with_timer
)
1537 r
= start_transient_trigger(bus
, argv
+ optind
, ".timer");
1539 r
= start_transient_service(bus
, argv
+ optind
, &retval
);
1542 strv_free(arg_environment
);
1543 strv_free(arg_property
);
1544 strv_free(arg_path_property
);
1545 strv_free(arg_socket_property
);
1546 strv_free(arg_timer_property
);
1548 return r
< 0 ? EXIT_FAILURE
: retval
;