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
) {
128 p
= strjoin(name
, "=", val
);
132 if (strv_consume(&arg_timer_property
, p
) < 0)
138 static int parse_argv(int argc
, char *argv
[]) {
157 ARG_ON_UNIT_INACTIVE
,
167 static const struct option options
[] = {
168 { "help", no_argument
, NULL
, 'h' },
169 { "version", no_argument
, NULL
, ARG_VERSION
},
170 { "user", no_argument
, NULL
, ARG_USER
},
171 { "system", no_argument
, NULL
, ARG_SYSTEM
},
172 { "scope", no_argument
, NULL
, ARG_SCOPE
},
173 { "unit", required_argument
, NULL
, ARG_UNIT
},
174 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
175 { "slice", required_argument
, NULL
, ARG_SLICE
},
176 { "remain-after-exit", no_argument
, NULL
, 'r' },
177 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
178 { "host", required_argument
, NULL
, 'H' },
179 { "machine", required_argument
, NULL
, 'M' },
180 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
181 { "wait", no_argument
, NULL
, ARG_WAIT
},
182 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
183 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
184 { "nice", required_argument
, NULL
, ARG_NICE
},
185 { "setenv", required_argument
, NULL
, 'E' },
186 { "property", required_argument
, NULL
, 'p' },
187 { "tty", no_argument
, NULL
, 't' }, /* deprecated alias */
188 { "pty", no_argument
, NULL
, 't' },
189 { "pipe", no_argument
, NULL
, 'P' },
190 { "quiet", no_argument
, NULL
, 'q' },
191 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
192 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
193 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
194 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
195 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
196 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
197 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
198 { "path-property", required_argument
, NULL
, ARG_PATH_PROPERTY
},
199 { "socket-property", required_argument
, NULL
, ARG_SOCKET_PROPERTY
},
200 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
201 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
202 { "collect", no_argument
, NULL
, 'G' },
206 bool with_trigger
= false;
212 while ((c
= getopt_long(argc
, argv
, "+hrH:M:E:p:tPqG", options
, NULL
)) >= 0)
223 case ARG_NO_ASK_PASSWORD
:
224 arg_ask_password
= false;
243 case ARG_DESCRIPTION
:
244 arg_description
= optarg
;
251 case ARG_SEND_SIGHUP
:
252 arg_send_sighup
= true;
256 arg_remain_after_exit
= true;
260 arg_transport
= BUS_TRANSPORT_REMOTE
;
265 arg_transport
= BUS_TRANSPORT_MACHINE
;
269 case ARG_SERVICE_TYPE
:
270 arg_service_type
= optarg
;
274 arg_exec_user
= optarg
;
278 arg_exec_group
= optarg
;
282 r
= parse_nice(optarg
, &arg_nice
);
284 return log_error_errno(r
, "Failed to parse nice value: %s", optarg
);
290 if (strv_extend(&arg_environment
, optarg
) < 0)
296 if (strv_extend(&arg_property
, optarg
) < 0)
301 case 't': /* --pty */
302 if (IN_SET(arg_stdio
, ARG_STDIO_DIRECT
, ARG_STDIO_AUTO
)) /* if --pipe is already used, upgrade to auto mode */
303 arg_stdio
= ARG_STDIO_AUTO
;
305 arg_stdio
= ARG_STDIO_PTY
;
308 case 'P': /* --pipe */
309 if (IN_SET(arg_stdio
, ARG_STDIO_PTY
, ARG_STDIO_AUTO
)) /* If --pty is already used, upgrade to auto mode */
310 arg_stdio
= ARG_STDIO_AUTO
;
312 arg_stdio
= ARG_STDIO_DIRECT
;
320 r
= add_timer_property("OnActiveSec", optarg
);
328 r
= add_timer_property("OnBootSec", optarg
);
336 r
= add_timer_property("OnStartupSec", optarg
);
343 case ARG_ON_UNIT_ACTIVE
:
344 r
= add_timer_property("OnUnitActiveSec", optarg
);
351 case ARG_ON_UNIT_INACTIVE
:
352 r
= add_timer_property("OnUnitInactiveSec", optarg
);
359 case ARG_ON_CALENDAR
:
360 r
= add_timer_property("OnCalendar", optarg
);
367 case ARG_TIMER_PROPERTY
:
369 if (strv_extend(&arg_timer_property
, optarg
) < 0)
372 with_timer
= with_timer
||
373 !!startswith(optarg
, "OnActiveSec=") ||
374 !!startswith(optarg
, "OnBootSec=") ||
375 !!startswith(optarg
, "OnStartupSec=") ||
376 !!startswith(optarg
, "OnUnitActiveSec=") ||
377 !!startswith(optarg
, "OnUnitInactiveSec=") ||
378 !!startswith(optarg
, "OnCalendar=");
381 case ARG_PATH_PROPERTY
:
383 if (strv_extend(&arg_path_property
, optarg
) < 0)
388 case ARG_SOCKET_PROPERTY
:
390 if (strv_extend(&arg_socket_property
, optarg
) < 0)
404 arg_aggressive_gc
= true;
411 assert_not_reached("Unhandled option");
414 with_trigger
= !!arg_path_property
|| !!arg_socket_property
|| with_timer
;
416 /* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
417 if ((int) !!arg_path_property
+ (int) !!arg_socket_property
+ (int) with_timer
> 1) {
418 log_error("Only single trigger (path, socket, timer) unit can be created.");
422 if (arg_stdio
== ARG_STDIO_AUTO
) {
423 /* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
424 * to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
425 * pipeline, but we are neatly interactive with tty-level isolation otherwise. */
426 arg_stdio
= isatty(STDIN_FILENO
) && isatty(STDOUT_FILENO
) && isatty(STDERR_FILENO
) ?
431 if ((optind
>= argc
) && (!arg_unit
|| !with_trigger
)) {
432 log_error("Command line to execute required.");
436 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
437 log_error("Execution in user context is not supported on non-local systems.");
441 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
442 log_error("Scope execution is not supported on non-local systems.");
446 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
447 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
451 if (arg_stdio
!= ARG_STDIO_NONE
&& (with_trigger
|| arg_scope
)) {
452 log_error("--pty/--pipe is not compatible in timer or --scope mode.");
456 if (arg_stdio
!= ARG_STDIO_NONE
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
457 log_error("--pty/--pipe is only supported when connecting to the local system or containers.");
461 if (arg_stdio
!= ARG_STDIO_NONE
&& arg_no_block
) {
462 log_error("--pty/--pipe is not compatible with --no-block.");
466 if (arg_scope
&& with_trigger
) {
467 log_error("Path, socket or timer options are not supported in --scope mode.");
471 if (arg_timer_property
&& !with_timer
) {
472 log_error("--timer-property= has no effect without any other timer options.");
478 log_error("--wait may not be combined with --no-block.");
483 log_error("--wait may not be combined with path, socket or timer operations.");
488 log_error("--wait may not be combined with --scope.");
496 static int transient_unit_set_properties(sd_bus_message
*m
, UnitType t
, char **properties
) {
499 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
501 return bus_log_create_error(r
);
503 if (arg_aggressive_gc
) {
504 r
= sd_bus_message_append(m
, "(sv)", "CollectMode", "s", "inactive-or-failed");
506 return bus_log_create_error(r
);
509 r
= bus_append_unit_property_assignment_many(m
, t
, properties
);
516 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
520 if (!isempty(arg_slice
)) {
521 _cleanup_free_
char *slice
= NULL
;
523 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
525 return log_error_errno(r
, "Failed to mangle name '%s': %m", arg_slice
);
527 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
529 return bus_log_create_error(r
);
535 static int transient_kill_set_properties(sd_bus_message
*m
) {
540 if (arg_send_sighup
) {
541 r
= sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
543 return bus_log_create_error(r
);
549 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
550 bool send_term
= false;
555 r
= transient_unit_set_properties(m
, UNIT_SERVICE
, arg_property
);
559 r
= transient_kill_set_properties(m
);
563 r
= transient_cgroup_set_properties(m
);
567 if (arg_wait
|| arg_stdio
!= ARG_STDIO_NONE
) {
568 r
= sd_bus_message_append(m
, "(sv)", "AddRef", "b", 1);
570 return bus_log_create_error(r
);
573 if (arg_remain_after_exit
) {
574 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
576 return bus_log_create_error(r
);
579 if (arg_service_type
) {
580 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
582 return bus_log_create_error(r
);
586 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
588 return bus_log_create_error(r
);
591 if (arg_exec_group
) {
592 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
594 return bus_log_create_error(r
);
598 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
600 return bus_log_create_error(r
);
604 r
= sd_bus_message_append(m
,
606 "StandardInput", "s", "tty",
607 "StandardOutput", "s", "tty",
608 "StandardError", "s", "tty",
609 "TTYPath", "s", pty_path
);
611 return bus_log_create_error(r
);
615 } else if (arg_stdio
== ARG_STDIO_DIRECT
) {
616 r
= sd_bus_message_append(m
,
618 "StandardInputFileDescriptor", "h", STDIN_FILENO
,
619 "StandardOutputFileDescriptor", "h", STDOUT_FILENO
,
620 "StandardErrorFileDescriptor", "h", STDERR_FILENO
);
622 return bus_log_create_error(r
);
624 send_term
= isatty(STDIN_FILENO
) || isatty(STDOUT_FILENO
) || isatty(STDERR_FILENO
);
634 n
= strjoina("TERM=", e
);
635 r
= sd_bus_message_append(m
,
637 "Environment", "as", 1, n
);
639 return bus_log_create_error(r
);
643 if (!strv_isempty(arg_environment
)) {
644 r
= sd_bus_message_open_container(m
, 'r', "sv");
646 return bus_log_create_error(r
);
648 r
= sd_bus_message_append(m
, "s", "Environment");
650 return bus_log_create_error(r
);
652 r
= sd_bus_message_open_container(m
, 'v', "as");
654 return bus_log_create_error(r
);
656 r
= sd_bus_message_append_strv(m
, arg_environment
);
658 return bus_log_create_error(r
);
660 r
= sd_bus_message_close_container(m
);
662 return bus_log_create_error(r
);
664 r
= sd_bus_message_close_container(m
);
666 return bus_log_create_error(r
);
671 r
= sd_bus_message_open_container(m
, 'r', "sv");
673 return bus_log_create_error(r
);
675 r
= sd_bus_message_append(m
, "s", "ExecStart");
677 return bus_log_create_error(r
);
679 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
681 return bus_log_create_error(r
);
683 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
685 return bus_log_create_error(r
);
687 r
= sd_bus_message_open_container(m
, 'r', "sasb");
689 return bus_log_create_error(r
);
691 r
= sd_bus_message_append(m
, "s", argv
[0]);
693 return bus_log_create_error(r
);
695 r
= sd_bus_message_append_strv(m
, argv
);
697 return bus_log_create_error(r
);
699 r
= sd_bus_message_append(m
, "b", false);
701 return bus_log_create_error(r
);
703 r
= sd_bus_message_close_container(m
);
705 return bus_log_create_error(r
);
707 r
= sd_bus_message_close_container(m
);
709 return bus_log_create_error(r
);
711 r
= sd_bus_message_close_container(m
);
713 return bus_log_create_error(r
);
715 r
= sd_bus_message_close_container(m
);
717 return bus_log_create_error(r
);
723 static int transient_scope_set_properties(sd_bus_message
*m
) {
728 r
= transient_unit_set_properties(m
, UNIT_SCOPE
, arg_property
);
732 r
= transient_kill_set_properties(m
);
736 r
= transient_cgroup_set_properties(m
);
740 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid_cached());
742 return bus_log_create_error(r
);
747 static int transient_timer_set_properties(sd_bus_message
*m
) {
752 r
= transient_unit_set_properties(m
, UNIT_TIMER
, arg_timer_property
);
756 /* Automatically clean up our transient timers */
757 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterElapse", "b", false);
759 return bus_log_create_error(r
);
764 static int make_unit_name(sd_bus
*bus
, UnitType t
, char **ret
) {
765 const char *unique
, *id
;
771 assert(t
< _UNIT_TYPE_MAX
);
773 r
= sd_bus_get_unique_name(bus
, &unique
);
777 /* We couldn't get the unique name, which is a pretty
778 * common case if we are connected to systemd
779 * directly. In that case, just pick a random uuid as
782 r
= sd_id128_randomize(&rnd
);
784 return log_error_errno(r
, "Failed to generate random run unit name: %m");
786 if (asprintf(ret
, "run-r" SD_ID128_FORMAT_STR
".%s", SD_ID128_FORMAT_VAL(rnd
), unit_type_to_string(t
)) < 0)
792 /* We managed to get the unique name, then let's use that to
793 * name our transient units. */
795 id
= startswith(unique
, ":1.");
797 log_error("Unique name %s has unexpected format.", unique
);
801 p
= strjoin("run-u", id
, ".", unit_type_to_string(t
));
809 typedef struct RunContext
{
815 /* The exit data of the unit */
817 uint64_t inactive_exit_usec
;
818 uint64_t inactive_enter_usec
;
820 uint64_t cpu_usage_nsec
;
821 uint64_t ip_ingress_bytes
;
822 uint64_t ip_egress_bytes
;
824 uint32_t exit_status
;
827 static void run_context_free(RunContext
*c
) {
830 c
->forward
= pty_forward_free(c
->forward
);
831 c
->match
= sd_bus_slot_unref(c
->match
);
832 c
->bus
= sd_bus_unref(c
->bus
);
833 c
->event
= sd_event_unref(c
->event
);
835 free(c
->active_state
);
839 static void run_context_check_done(RunContext
*c
) {
845 done
= STRPTR_IN_SET(c
->active_state
, "inactive", "failed");
849 if (c
->forward
&& done
) /* If the service is gone, it's time to drain the output */
850 done
= pty_forward_drain(c
->forward
);
853 sd_event_exit(c
->event
, EXIT_SUCCESS
);
856 static int run_context_update(RunContext
*c
, const char *path
) {
858 static const struct bus_properties_map map
[] = {
859 { "ActiveState", "s", NULL
, offsetof(RunContext
, active_state
) },
860 { "InactiveExitTimestampMonotonic", "t", NULL
, offsetof(RunContext
, inactive_exit_usec
) },
861 { "InactiveEnterTimestampMonotonic", "t", NULL
, offsetof(RunContext
, inactive_enter_usec
) },
862 { "Result", "s", NULL
, offsetof(RunContext
, result
) },
863 { "ExecMainCode", "i", NULL
, offsetof(RunContext
, exit_code
) },
864 { "ExecMainStatus", "i", NULL
, offsetof(RunContext
, exit_status
) },
865 { "CPUUsageNSec", "t", NULL
, offsetof(RunContext
, cpu_usage_nsec
) },
866 { "IPIngressBytes", "t", NULL
, offsetof(RunContext
, ip_ingress_bytes
) },
867 { "IPEgressBytes", "t", NULL
, offsetof(RunContext
, ip_egress_bytes
) },
871 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
874 r
= bus_map_all_properties(c
->bus
,
875 "org.freedesktop.systemd1",
881 sd_event_exit(c
->event
, EXIT_FAILURE
);
882 return log_error_errno(r
, "Failed to query unit state: %s", bus_error_message(&error
, r
));
885 run_context_check_done(c
);
889 static int on_properties_changed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
890 RunContext
*c
= userdata
;
895 return run_context_update(c
, sd_bus_message_get_path(m
));
898 static int pty_forward_handler(PTYForward
*f
, int rcode
, void *userdata
) {
899 RunContext
*c
= userdata
;
904 sd_event_exit(c
->event
, EXIT_FAILURE
);
905 return log_error_errno(rcode
, "Error on PTY forwarding logic: %m");
908 run_context_check_done(c
);
912 static int start_transient_service(
917 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
918 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
919 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
920 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
921 _cleanup_close_
int master
= -1;
928 if (arg_stdio
== ARG_STDIO_PTY
) {
930 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
931 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
933 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
935 r
= ptsname_malloc(master
, &pty_path
);
937 return log_error_errno(r
, "Failed to determine tty name: %m");
939 if (unlockpt(master
) < 0)
940 return log_error_errno(errno
, "Failed to unlock tty: %m");
942 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
943 _cleanup_(sd_bus_unrefp
) sd_bus
*system_bus
= NULL
;
944 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pty_reply
= NULL
;
947 r
= sd_bus_default_system(&system_bus
);
949 return log_error_errno(r
, "Failed to connect to system bus: %m");
951 r
= sd_bus_call_method(system_bus
,
952 "org.freedesktop.machine1",
953 "/org/freedesktop/machine1",
954 "org.freedesktop.machine1.Manager",
960 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
964 r
= sd_bus_message_read(pty_reply
, "hs", &master
, &s
);
966 return bus_log_parse_error(r
);
968 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
970 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
972 pty_path
= strdup(s
);
976 assert_not_reached("Can't allocate tty via ssh");
980 r
= bus_wait_for_jobs_new(bus
, &w
);
982 return log_error_errno(r
, "Could not watch jobs: %m");
986 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
988 return log_error_errno(r
, "Failed to mangle unit name: %m");
990 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
995 r
= sd_bus_message_new_method_call(
998 "org.freedesktop.systemd1",
999 "/org/freedesktop/systemd1",
1000 "org.freedesktop.systemd1.Manager",
1001 "StartTransientUnit");
1003 return bus_log_create_error(r
);
1005 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1007 return bus_log_create_error(r
);
1010 r
= sd_bus_message_append(m
, "ss", service
, "fail");
1012 return bus_log_create_error(r
);
1015 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1017 return bus_log_create_error(r
);
1019 r
= transient_service_set_properties(m
, argv
, pty_path
);
1023 r
= sd_bus_message_close_container(m
);
1025 return bus_log_create_error(r
);
1027 /* Auxiliary units */
1028 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1030 return bus_log_create_error(r
);
1032 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1034 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1036 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
1041 r
= sd_bus_message_read(reply
, "o", &object
);
1043 return bus_log_parse_error(r
);
1045 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1051 log_info("Running as unit: %s", service
);
1053 if (arg_wait
|| arg_stdio
!= ARG_STDIO_NONE
) {
1054 _cleanup_(run_context_free
) RunContext c
= {
1055 .cpu_usage_nsec
= NSEC_INFINITY
,
1056 .ip_ingress_bytes
= UINT64_MAX
,
1057 .ip_egress_bytes
= UINT64_MAX
,
1058 .inactive_exit_usec
= USEC_INFINITY
,
1059 .inactive_enter_usec
= USEC_INFINITY
,
1061 _cleanup_free_
char *path
= NULL
;
1063 c
.bus
= sd_bus_ref(bus
);
1065 r
= sd_event_default(&c
.event
);
1067 return log_error_errno(r
, "Failed to get event loop: %m");
1070 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
1071 (void) sd_event_add_signal(c
.event
, NULL
, SIGINT
, NULL
, NULL
);
1072 (void) sd_event_add_signal(c
.event
, NULL
, SIGTERM
, NULL
, NULL
);
1075 log_info("Press ^] three times within 1s to disconnect TTY.");
1077 r
= pty_forward_new(c
.event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &c
.forward
);
1079 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
1081 pty_forward_set_handler(c
.forward
, pty_forward_handler
, &c
);
1083 /* Make sure to process any TTY events before we process bus events */
1084 (void) pty_forward_set_priority(c
.forward
, SD_EVENT_PRIORITY_IMPORTANT
);
1087 path
= unit_dbus_path_from_name(service
);
1091 r
= sd_bus_match_signal_async(
1094 "org.freedesktop.systemd1",
1096 "org.freedesktop.DBus.Properties",
1097 "PropertiesChanged",
1098 on_properties_changed
, NULL
, &c
);
1100 return log_error_errno(r
, "Failed to request properties changed signal match: %m");
1102 r
= sd_bus_attach_event(bus
, c
.event
, SD_EVENT_PRIORITY_NORMAL
);
1104 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
1106 r
= run_context_update(&c
, path
);
1110 r
= sd_event_loop(c
.event
);
1112 return log_error_errno(r
, "Failed to run event loop: %m");
1117 r
= pty_forward_get_last_char(c
.forward
, &last_char
);
1118 if (r
>= 0 && !arg_quiet
&& last_char
!= '\n')
1119 fputc('\n', stdout
);
1122 if (arg_wait
&& !arg_quiet
) {
1124 /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, in its
1125 * original settings (i.e. proper line breaks), so that we can show the summary in a pretty
1127 c
.forward
= pty_forward_free(c
.forward
);
1129 if (!isempty(c
.result
))
1130 log_info("Finished with result: %s", strna(c
.result
));
1132 if (c
.exit_code
== CLD_EXITED
)
1133 log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c
.exit_code
), c
.exit_status
);
1134 else if (c
.exit_code
> 0)
1135 log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c
.exit_code
), signal_to_string(c
.exit_status
));
1137 if (c
.inactive_enter_usec
> 0 && c
.inactive_enter_usec
!= USEC_INFINITY
&&
1138 c
.inactive_exit_usec
> 0 && c
.inactive_exit_usec
!= USEC_INFINITY
&&
1139 c
.inactive_enter_usec
> c
.inactive_exit_usec
) {
1140 char ts
[FORMAT_TIMESPAN_MAX
];
1141 log_info("Service runtime: %s", format_timespan(ts
, sizeof(ts
), c
.inactive_enter_usec
- c
.inactive_exit_usec
, USEC_PER_MSEC
));
1144 if (c
.cpu_usage_nsec
!= NSEC_INFINITY
) {
1145 char ts
[FORMAT_TIMESPAN_MAX
];
1146 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
));
1149 if (c
.ip_ingress_bytes
!= UINT64_MAX
) {
1150 char bytes
[FORMAT_BYTES_MAX
];
1151 log_info("IP traffic received: %s", format_bytes(bytes
, sizeof(bytes
), c
.ip_ingress_bytes
));
1153 if (c
.ip_egress_bytes
!= UINT64_MAX
) {
1154 char bytes
[FORMAT_BYTES_MAX
];
1155 log_info("IP traffic sent: %s", format_bytes(bytes
, sizeof(bytes
), c
.ip_egress_bytes
));
1159 /* Try to propagate the service's return value */
1160 if (c
.result
&& STR_IN_SET(c
.result
, "success", "exit-code") && c
.exit_code
== CLD_EXITED
)
1161 *retval
= c
.exit_status
;
1163 *retval
= EXIT_FAILURE
;
1169 static int start_transient_scope(
1173 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1174 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1175 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1176 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
1177 _cleanup_free_
char *scope
= NULL
;
1178 const char *object
= NULL
;
1184 r
= bus_wait_for_jobs_new(bus
, &w
);
1189 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
1191 return log_error_errno(r
, "Failed to mangle scope name: %m");
1193 r
= make_unit_name(bus
, UNIT_SCOPE
, &scope
);
1198 r
= sd_bus_message_new_method_call(
1201 "org.freedesktop.systemd1",
1202 "/org/freedesktop/systemd1",
1203 "org.freedesktop.systemd1.Manager",
1204 "StartTransientUnit");
1206 return bus_log_create_error(r
);
1208 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1210 return bus_log_create_error(r
);
1213 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
1215 return bus_log_create_error(r
);
1218 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1220 return bus_log_create_error(r
);
1222 r
= transient_scope_set_properties(m
);
1226 r
= sd_bus_message_close_container(m
);
1228 return bus_log_create_error(r
);
1230 /* Auxiliary units */
1231 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1233 return bus_log_create_error(r
);
1235 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1237 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1239 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
1244 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
1245 return log_error_errno(errno
, "Failed to set nice level: %m");
1248 if (arg_exec_group
) {
1251 r
= get_group_creds(&arg_exec_group
, &gid
);
1253 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
1255 if (setresgid(gid
, gid
, gid
) < 0)
1256 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1259 if (arg_exec_user
) {
1260 const char *home
, *shell
;
1264 r
= get_user_creds_clean(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
1266 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
1269 r
= strv_extendf(&user_env
, "HOME=%s", home
);
1275 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
1280 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
1284 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
1288 if (!arg_exec_group
) {
1289 if (setresgid(gid
, gid
, gid
) < 0)
1290 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1293 if (setresuid(uid
, uid
, uid
) < 0)
1294 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
1297 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
1301 r
= sd_bus_message_read(reply
, "o", &object
);
1303 return bus_log_parse_error(r
);
1305 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1310 log_info("Running scope as unit: %s", scope
);
1312 execvpe(argv
[0], argv
, env
);
1314 return log_error_errno(errno
, "Failed to execute: %m");
1317 static int start_transient_trigger(
1320 const char *suffix
) {
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
;
1324 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1325 _cleanup_free_
char *trigger
= NULL
, *service
= NULL
;
1326 const char *object
= NULL
;
1332 r
= bus_wait_for_jobs_new(bus
, &w
);
1337 switch (unit_name_to_type(arg_unit
)) {
1340 service
= strdup(arg_unit
);
1344 r
= unit_name_change_suffix(service
, suffix
, &trigger
);
1346 return log_error_errno(r
, "Failed to change unit suffix: %m");
1350 trigger
= strdup(arg_unit
);
1354 r
= unit_name_change_suffix(trigger
, ".service", &service
);
1356 return log_error_errno(r
, "Failed to change unit suffix: %m");
1360 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1362 return log_error_errno(r
, "Failed to mangle unit name: %m");
1364 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, suffix
, &trigger
);
1366 return log_error_errno(r
, "Failed to mangle unit name: %m");
1371 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
1375 r
= unit_name_change_suffix(service
, suffix
, &trigger
);
1377 return log_error_errno(r
, "Failed to change unit suffix: %m");
1380 r
= sd_bus_message_new_method_call(
1383 "org.freedesktop.systemd1",
1384 "/org/freedesktop/systemd1",
1385 "org.freedesktop.systemd1.Manager",
1386 "StartTransientUnit");
1388 return bus_log_create_error(r
);
1390 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1392 return bus_log_create_error(r
);
1395 r
= sd_bus_message_append(m
, "ss", trigger
, "fail");
1397 return bus_log_create_error(r
);
1400 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1402 return bus_log_create_error(r
);
1404 if (streq(suffix
, ".path"))
1405 r
= transient_unit_set_properties(m
, UNIT_PATH
, arg_path_property
);
1406 else if (streq(suffix
, ".socket"))
1407 r
= transient_unit_set_properties(m
, UNIT_SOCKET
, arg_socket_property
);
1408 else if (streq(suffix
, ".timer"))
1409 r
= transient_timer_set_properties(m
);
1411 assert_not_reached("Invalid suffix");
1415 r
= sd_bus_message_close_container(m
);
1417 return bus_log_create_error(r
);
1419 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1421 return bus_log_create_error(r
);
1423 if (!strv_isempty(argv
)) {
1424 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1426 return bus_log_create_error(r
);
1428 r
= sd_bus_message_append(m
, "s", service
);
1430 return bus_log_create_error(r
);
1432 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1434 return bus_log_create_error(r
);
1436 r
= transient_service_set_properties(m
, argv
, NULL
);
1440 r
= sd_bus_message_close_container(m
);
1442 return bus_log_create_error(r
);
1444 r
= sd_bus_message_close_container(m
);
1446 return bus_log_create_error(r
);
1449 r
= sd_bus_message_close_container(m
);
1451 return bus_log_create_error(r
);
1453 polkit_agent_open_if_enabled(arg_transport
, arg_ask_password
);
1455 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1457 log_error("Failed to start transient %s unit: %s", suffix
+ 1, bus_error_message(&error
, -r
));
1461 r
= sd_bus_message_read(reply
, "o", &object
);
1463 return bus_log_parse_error(r
);
1465 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1470 log_info("Running %s as unit: %s", suffix
+ 1, trigger
);
1472 log_info("Will run service as unit: %s", service
);
1478 int main(int argc
, char* argv
[]) {
1479 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1480 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1481 int r
, retval
= EXIT_SUCCESS
;
1483 log_parse_environment();
1486 r
= parse_argv(argc
, argv
);
1490 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1491 /* Patch in an absolute path */
1493 r
= find_binary(argv
[optind
], &command
);
1495 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1499 argv
[optind
] = command
;
1502 if (!arg_description
) {
1503 description
= strv_join(argv
+ optind
, " ");
1509 if (arg_unit
&& isempty(description
)) {
1510 r
= free_and_strdup(&description
, arg_unit
);
1515 arg_description
= description
;
1518 /* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
1520 if (arg_wait
|| arg_stdio
!= ARG_STDIO_NONE
)
1521 r
= bus_connect_transport(arg_transport
, arg_host
, arg_user
, &bus
);
1523 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1525 log_error_errno(r
, "Failed to create bus connection: %m");
1530 r
= start_transient_scope(bus
, argv
+ optind
);
1531 else if (arg_path_property
)
1532 r
= start_transient_trigger(bus
, argv
+ optind
, ".path");
1533 else if (arg_socket_property
)
1534 r
= start_transient_trigger(bus
, argv
+ optind
, ".socket");
1535 else if (with_timer
)
1536 r
= start_transient_trigger(bus
, argv
+ optind
, ".timer");
1538 r
= start_transient_service(bus
, argv
+ optind
, &retval
);
1541 strv_free(arg_environment
);
1542 strv_free(arg_property
);
1543 strv_free(arg_path_property
);
1544 strv_free(arg_socket_property
);
1545 strv_free(arg_timer_property
);
1547 return r
< 0 ? EXIT_FAILURE
: retval
;