2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
27 #include "bus-error.h"
28 #include "bus-unit-util.h"
30 #include "calendarspec.h"
33 #include "format-util.h"
34 #include "parse-util.h"
35 #include "path-util.h"
36 #include "process-util.h"
38 #include "signal-util.h"
39 #include "spawn-polkit-agent.h"
41 #include "terminal-util.h"
42 #include "unit-name.h"
43 #include "user-util.h"
45 static bool arg_ask_password
= true;
46 static bool arg_scope
= false;
47 static bool arg_remain_after_exit
= false;
48 static bool arg_no_block
= false;
49 static bool arg_wait
= false;
50 static const char *arg_unit
= NULL
;
51 static const char *arg_description
= NULL
;
52 static const char *arg_slice
= NULL
;
53 static bool arg_send_sighup
= false;
54 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
55 static const char *arg_host
= NULL
;
56 static bool arg_user
= false;
57 static const char *arg_service_type
= NULL
;
58 static const char *arg_exec_user
= NULL
;
59 static const char *arg_exec_group
= NULL
;
60 static int arg_nice
= 0;
61 static bool arg_nice_set
= false;
62 static char **arg_environment
= NULL
;
63 static char **arg_property
= NULL
;
64 static bool arg_pty
= false;
65 static usec_t arg_on_active
= 0;
66 static usec_t arg_on_boot
= 0;
67 static usec_t arg_on_startup
= 0;
68 static usec_t arg_on_unit_active
= 0;
69 static usec_t arg_on_unit_inactive
= 0;
70 static const char *arg_on_calendar
= NULL
;
71 static char **arg_timer_property
= NULL
;
72 static bool arg_quiet
= false;
74 static void polkit_agent_open_if_enabled(void) {
76 /* Open the polkit agent as a child process if necessary */
77 if (!arg_ask_password
)
80 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
86 static void help(void) {
87 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
88 "Run the specified command in a transient scope or service.\n\n"
89 " -h --help Show this help\n"
90 " --version Show package version\n"
91 " --no-ask-password Do not prompt for password\n"
92 " --user Run as user unit\n"
93 " -H --host=[USER@]HOST Operate on remote host\n"
94 " -M --machine=CONTAINER Operate on local container\n"
95 " --scope Run this as scope rather than service\n"
96 " --unit=UNIT Run under the specified unit name\n"
97 " -p --property=NAME=VALUE Set service or scope unit property\n"
98 " --description=TEXT Description for unit\n"
99 " --slice=SLICE Run in the specified slice\n"
100 " --no-block Do not wait until operation finished\n"
101 " -r --remain-after-exit Leave service around until explicitly stopped\n"
102 " --wait Wait until service stopped again\n"
103 " --send-sighup Send SIGHUP when terminating\n"
104 " --service-type=TYPE Service type\n"
105 " --uid=USER Run as system user\n"
106 " --gid=GROUP Run as system group\n"
107 " --nice=NICE Nice level\n"
108 " -E --setenv=NAME=VALUE Set environment\n"
109 " -t --pty Run service on pseudo tty\n"
110 " -q --quiet Suppress information messages during runtime\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 bool with_timer(void) {
123 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
126 static int parse_argv(int argc
, char *argv
[]) {
145 ARG_ON_UNIT_INACTIVE
,
153 static const struct option options
[] = {
154 { "help", no_argument
, NULL
, 'h' },
155 { "version", no_argument
, NULL
, ARG_VERSION
},
156 { "user", no_argument
, NULL
, ARG_USER
},
157 { "system", no_argument
, NULL
, ARG_SYSTEM
},
158 { "scope", no_argument
, NULL
, ARG_SCOPE
},
159 { "unit", required_argument
, NULL
, ARG_UNIT
},
160 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
161 { "slice", required_argument
, NULL
, ARG_SLICE
},
162 { "remain-after-exit", no_argument
, NULL
, 'r' },
163 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
164 { "host", required_argument
, NULL
, 'H' },
165 { "machine", required_argument
, NULL
, 'M' },
166 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
167 { "wait", no_argument
, NULL
, ARG_WAIT
},
168 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
169 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
170 { "nice", required_argument
, NULL
, ARG_NICE
},
171 { "setenv", required_argument
, NULL
, 'E' },
172 { "property", required_argument
, NULL
, 'p' },
173 { "tty", no_argument
, NULL
, 't' }, /* deprecated */
174 { "pty", no_argument
, NULL
, 't' },
175 { "quiet", no_argument
, NULL
, 'q' },
176 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
177 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
178 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
179 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
180 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
181 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
182 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
183 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
184 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
193 while ((c
= getopt_long(argc
, argv
, "+hrH:M:E:p:tq", options
, NULL
)) >= 0)
204 case ARG_NO_ASK_PASSWORD
:
205 arg_ask_password
= false;
224 case ARG_DESCRIPTION
:
225 arg_description
= optarg
;
232 case ARG_SEND_SIGHUP
:
233 arg_send_sighup
= true;
237 arg_remain_after_exit
= true;
241 arg_transport
= BUS_TRANSPORT_REMOTE
;
246 arg_transport
= BUS_TRANSPORT_MACHINE
;
250 case ARG_SERVICE_TYPE
:
251 arg_service_type
= optarg
;
255 arg_exec_user
= optarg
;
259 arg_exec_group
= optarg
;
263 r
= parse_nice(optarg
, &arg_nice
);
265 return log_error_errno(r
, "Failed to parse nice value: %s", optarg
);
271 if (strv_extend(&arg_environment
, optarg
) < 0)
277 if (strv_extend(&arg_property
, optarg
) < 0)
292 r
= parse_sec(optarg
, &arg_on_active
);
294 log_error("Failed to parse timer value: %s", optarg
);
302 r
= parse_sec(optarg
, &arg_on_boot
);
304 log_error("Failed to parse timer value: %s", optarg
);
312 r
= parse_sec(optarg
, &arg_on_startup
);
314 log_error("Failed to parse timer value: %s", optarg
);
320 case ARG_ON_UNIT_ACTIVE
:
322 r
= parse_sec(optarg
, &arg_on_unit_active
);
324 log_error("Failed to parse timer value: %s", optarg
);
330 case ARG_ON_UNIT_INACTIVE
:
332 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
334 log_error("Failed to parse timer value: %s", optarg
);
340 case ARG_ON_CALENDAR
: {
341 CalendarSpec
*spec
= NULL
;
343 r
= calendar_spec_from_string(optarg
, &spec
);
345 log_error("Invalid calendar spec: %s", optarg
);
349 calendar_spec_free(spec
);
350 arg_on_calendar
= optarg
;
354 case ARG_TIMER_PROPERTY
:
356 if (strv_extend(&arg_timer_property
, optarg
) < 0)
373 assert_not_reached("Unhandled option");
376 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
377 log_error("Command line to execute required.");
381 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
382 log_error("Execution in user context is not supported on non-local systems.");
386 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
387 log_error("Scope execution is not supported on non-local systems.");
391 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
392 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
396 if (arg_pty
&& (with_timer() || arg_scope
)) {
397 log_error("--pty is not compatible in timer or --scope mode.");
401 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
402 log_error("--pty is only supported when connecting to the local system or containers.");
406 if (arg_pty
&& arg_no_block
) {
407 log_error("--pty is not compatible with --no-block.");
411 if (arg_scope
&& with_timer()) {
412 log_error("Timer options are not supported in --scope mode.");
416 if (arg_timer_property
&& !with_timer()) {
417 log_error("--timer-property= has no effect without any other timer options.");
423 log_error("--wait may not be combined with --no-block.");
428 log_error("--wait may not be combined with timer operations.");
433 log_error("--wait may not be combined with --scope.");
441 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
444 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
448 r
= bus_append_unit_property_assignment_many(m
, properties
);
455 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
459 if (!isempty(arg_slice
)) {
460 _cleanup_free_
char *slice
;
462 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
466 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
474 static int transient_kill_set_properties(sd_bus_message
*m
) {
478 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
483 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
488 r
= transient_unit_set_properties(m
, arg_property
);
492 r
= transient_kill_set_properties(m
);
496 r
= transient_cgroup_set_properties(m
);
501 r
= sd_bus_message_append(m
, "(sv)", "AddRef", "b", 1);
506 if (arg_remain_after_exit
) {
507 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
512 if (arg_service_type
) {
513 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
519 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
524 if (arg_exec_group
) {
525 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
531 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
539 r
= sd_bus_message_append(m
,
541 "StandardInput", "s", "tty",
542 "StandardOutput", "s", "tty",
543 "StandardError", "s", "tty",
544 "TTYPath", "s", pty_path
);
552 n
= strjoina("TERM=", e
);
553 r
= sd_bus_message_append(m
,
555 "Environment", "as", 1, n
);
561 if (!strv_isempty(arg_environment
)) {
562 r
= sd_bus_message_open_container(m
, 'r', "sv");
566 r
= sd_bus_message_append(m
, "s", "Environment");
570 r
= sd_bus_message_open_container(m
, 'v', "as");
574 r
= sd_bus_message_append_strv(m
, arg_environment
);
578 r
= sd_bus_message_close_container(m
);
582 r
= sd_bus_message_close_container(m
);
589 r
= sd_bus_message_open_container(m
, 'r', "sv");
593 r
= sd_bus_message_append(m
, "s", "ExecStart");
597 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
601 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
605 r
= sd_bus_message_open_container(m
, 'r', "sasb");
609 r
= sd_bus_message_append(m
, "s", argv
[0]);
613 r
= sd_bus_message_append_strv(m
, argv
);
617 r
= sd_bus_message_append(m
, "b", false);
621 r
= sd_bus_message_close_container(m
);
625 r
= sd_bus_message_close_container(m
);
629 r
= sd_bus_message_close_container(m
);
633 r
= sd_bus_message_close_container(m
);
641 static int transient_scope_set_properties(sd_bus_message
*m
) {
646 r
= transient_unit_set_properties(m
, arg_property
);
650 r
= transient_kill_set_properties(m
);
654 r
= transient_cgroup_set_properties(m
);
658 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
665 static int transient_timer_set_properties(sd_bus_message
*m
) {
670 r
= transient_unit_set_properties(m
, arg_timer_property
);
674 /* Automatically clean up our transient timers */
675 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterElapse", "b", false);
680 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
686 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
691 if (arg_on_startup
) {
692 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
697 if (arg_on_unit_active
) {
698 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
703 if (arg_on_unit_inactive
) {
704 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
709 if (arg_on_calendar
) {
710 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
718 static int make_unit_name(sd_bus
*bus
, UnitType t
, char **ret
) {
719 const char *unique
, *id
;
725 assert(t
< _UNIT_TYPE_MAX
);
727 r
= sd_bus_get_unique_name(bus
, &unique
);
731 /* We couldn't get the unique name, which is a pretty
732 * common case if we are connected to systemd
733 * directly. In that case, just pick a random uuid as
736 r
= sd_id128_randomize(&rnd
);
738 return log_error_errno(r
, "Failed to generate random run unit name: %m");
740 if (asprintf(ret
, "run-r" SD_ID128_FORMAT_STR
".%s", SD_ID128_FORMAT_VAL(rnd
), unit_type_to_string(t
)) < 0)
746 /* We managed to get the unique name, then let's use that to
747 * name our transient units. */
749 id
= startswith(unique
, ":1.");
751 log_error("Unique name %s has unexpected format.", unique
);
755 p
= strjoin("run-u", id
, ".", unit_type_to_string(t
));
763 typedef struct RunContext
{
769 /* The exit data of the unit */
771 uint64_t inactive_exit_usec
;
772 uint64_t inactive_enter_usec
;
774 uint64_t cpu_usage_nsec
;
776 uint32_t exit_status
;
779 static void run_context_free(RunContext
*c
) {
782 c
->forward
= pty_forward_free(c
->forward
);
783 c
->match
= sd_bus_slot_unref(c
->match
);
784 c
->bus
= sd_bus_unref(c
->bus
);
785 c
->event
= sd_event_unref(c
->event
);
787 free(c
->active_state
);
791 static void run_context_check_done(RunContext
*c
) {
797 done
= STRPTR_IN_SET(c
->active_state
, "inactive", "failed");
801 if (c
->forward
&& done
) /* If the service is gone, it's time to drain the output */
802 done
= pty_forward_drain(c
->forward
);
805 sd_event_exit(c
->event
, EXIT_SUCCESS
);
808 static int run_context_update(RunContext
*c
, const char *path
) {
810 static const struct bus_properties_map map
[] = {
811 { "ActiveState", "s", NULL
, offsetof(RunContext
, active_state
) },
812 { "InactiveExitTimestampMonotonic", "t", NULL
, offsetof(RunContext
, inactive_exit_usec
) },
813 { "InactiveEnterTimestampMonotonic", "t", NULL
, offsetof(RunContext
, inactive_enter_usec
) },
814 { "Result", "s", NULL
, offsetof(RunContext
, result
) },
815 { "ExecMainCode", "i", NULL
, offsetof(RunContext
, exit_code
) },
816 { "ExecMainStatus", "i", NULL
, offsetof(RunContext
, exit_status
) },
817 { "CPUUsageNSec", "t", NULL
, offsetof(RunContext
, cpu_usage_nsec
) },
823 r
= bus_map_all_properties(c
->bus
,
824 "org.freedesktop.systemd1",
829 sd_event_exit(c
->event
, EXIT_FAILURE
);
830 return log_error_errno(r
, "Failed to query unit state: %m");
833 run_context_check_done(c
);
837 static int on_properties_changed(sd_bus_message
*m
, void *userdata
, sd_bus_error
*error
) {
838 RunContext
*c
= userdata
;
843 return run_context_update(c
, sd_bus_message_get_path(m
));
846 static int pty_forward_handler(PTYForward
*f
, int rcode
, void *userdata
) {
847 RunContext
*c
= userdata
;
852 sd_event_exit(c
->event
, EXIT_FAILURE
);
853 return log_error_errno(rcode
, "Error on PTY forwarding logic: %m");
856 run_context_check_done(c
);
860 static int start_transient_service(
865 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
866 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
867 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
868 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
869 _cleanup_close_
int master
= -1;
878 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
879 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
881 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
883 r
= ptsname_malloc(master
, &pty_path
);
885 return log_error_errno(r
, "Failed to determine tty name: %m");
887 if (unlockpt(master
) < 0)
888 return log_error_errno(errno
, "Failed to unlock tty: %m");
890 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
891 _cleanup_(sd_bus_unrefp
) sd_bus
*system_bus
= NULL
;
892 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pty_reply
= NULL
;
895 r
= sd_bus_default_system(&system_bus
);
897 return log_error_errno(r
, "Failed to connect to system bus: %m");
899 r
= sd_bus_call_method(system_bus
,
900 "org.freedesktop.machine1",
901 "/org/freedesktop/machine1",
902 "org.freedesktop.machine1.Manager",
908 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
912 r
= sd_bus_message_read(pty_reply
, "hs", &master
, &s
);
914 return bus_log_parse_error(r
);
916 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
918 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
920 pty_path
= strdup(s
);
924 assert_not_reached("Can't allocate tty via ssh");
928 r
= bus_wait_for_jobs_new(bus
, &w
);
930 return log_error_errno(r
, "Could not watch jobs: %m");
934 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
936 return log_error_errno(r
, "Failed to mangle unit name: %m");
938 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
943 r
= sd_bus_message_new_method_call(
946 "org.freedesktop.systemd1",
947 "/org/freedesktop/systemd1",
948 "org.freedesktop.systemd1.Manager",
949 "StartTransientUnit");
951 return bus_log_create_error(r
);
953 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
955 return bus_log_create_error(r
);
958 r
= sd_bus_message_append(m
, "ss", service
, "fail");
960 return bus_log_create_error(r
);
963 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
965 return bus_log_create_error(r
);
967 r
= transient_service_set_properties(m
, argv
, pty_path
);
969 return bus_log_create_error(r
);
971 r
= sd_bus_message_close_container(m
);
973 return bus_log_create_error(r
);
975 /* Auxiliary units */
976 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
978 return bus_log_create_error(r
);
980 polkit_agent_open_if_enabled();
982 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
984 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
989 r
= sd_bus_message_read(reply
, "o", &object
);
991 return bus_log_parse_error(r
);
993 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
999 log_info("Running as unit: %s", service
);
1001 if (arg_wait
|| master
>= 0) {
1002 _cleanup_(run_context_free
) RunContext c
= {};
1003 _cleanup_free_
char *path
= NULL
;
1006 c
.bus
= sd_bus_ref(bus
);
1008 r
= sd_event_default(&c
.event
);
1010 return log_error_errno(r
, "Failed to get event loop: %m");
1013 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
1014 (void) sd_event_add_signal(c
.event
, NULL
, SIGINT
, NULL
, NULL
);
1015 (void) sd_event_add_signal(c
.event
, NULL
, SIGTERM
, NULL
, NULL
);
1018 log_info("Press ^] three times within 1s to disconnect TTY.");
1020 r
= pty_forward_new(c
.event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &c
.forward
);
1022 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
1024 pty_forward_set_handler(c
.forward
, pty_forward_handler
, &c
);
1028 path
= unit_dbus_path_from_name(service
);
1032 mt
= strjoina("type='signal',"
1033 "sender='org.freedesktop.systemd1',"
1034 "path='", path
, "',"
1035 "interface='org.freedesktop.DBus.Properties',"
1036 "member='PropertiesChanged'");
1037 r
= sd_bus_add_match(bus
, &c
.match
, mt
, on_properties_changed
, &c
);
1039 return log_error_errno(r
, "Failed to add properties changed signal.");
1041 r
= sd_bus_attach_event(bus
, c
.event
, 0);
1043 return log_error_errno(r
, "Failed to attach bus to event loop.");
1045 r
= run_context_update(&c
, path
);
1049 r
= sd_event_loop(c
.event
);
1051 return log_error_errno(r
, "Failed to run event loop: %m");
1056 r
= pty_forward_get_last_char(c
.forward
, &last_char
);
1057 if (r
>= 0 && !arg_quiet
&& last_char
!= '\n')
1058 fputc('\n', stdout
);
1061 if (arg_wait
&& !arg_quiet
) {
1063 /* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, in its
1064 * original settings (i.e. proper line breaks), so that we can show the summary in a pretty
1066 c
.forward
= pty_forward_free(c
.forward
);
1068 if (!isempty(c
.result
))
1069 log_info("Finished with result: %s", strna(c
.result
));
1071 if (c
.exit_code
== CLD_EXITED
)
1072 log_info("Main processes terminated with: code=%s/status=%i", sigchld_code_to_string(c
.exit_code
), c
.exit_status
);
1073 else if (c
.exit_code
> 0)
1074 log_info("Main processes terminated with: code=%s/status=%s", sigchld_code_to_string(c
.exit_code
), signal_to_string(c
.exit_status
));
1076 if (c
.inactive_enter_usec
> 0 && c
.inactive_enter_usec
!= USEC_INFINITY
&&
1077 c
.inactive_exit_usec
> 0 && c
.inactive_exit_usec
!= USEC_INFINITY
&&
1078 c
.inactive_enter_usec
> c
.inactive_exit_usec
) {
1079 char ts
[FORMAT_TIMESPAN_MAX
];
1080 log_info("Service runtime: %s", format_timespan(ts
, sizeof(ts
), c
.inactive_enter_usec
- c
.inactive_exit_usec
, USEC_PER_MSEC
));
1083 if (c
.cpu_usage_nsec
> 0 && c
.cpu_usage_nsec
!= NSEC_INFINITY
) {
1084 char ts
[FORMAT_TIMESPAN_MAX
];
1085 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
));
1089 /* Try to propagate the service's return value */
1090 if (c
.result
&& STR_IN_SET(c
.result
, "success", "exit-code") && c
.exit_code
== CLD_EXITED
)
1091 *retval
= c
.exit_status
;
1093 *retval
= EXIT_FAILURE
;
1099 static int start_transient_scope(
1103 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1104 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1105 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1106 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
1107 _cleanup_free_
char *scope
= NULL
;
1108 const char *object
= NULL
;
1114 r
= bus_wait_for_jobs_new(bus
, &w
);
1119 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
1121 return log_error_errno(r
, "Failed to mangle scope name: %m");
1123 r
= make_unit_name(bus
, UNIT_SCOPE
, &scope
);
1128 r
= sd_bus_message_new_method_call(
1131 "org.freedesktop.systemd1",
1132 "/org/freedesktop/systemd1",
1133 "org.freedesktop.systemd1.Manager",
1134 "StartTransientUnit");
1136 return bus_log_create_error(r
);
1138 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1140 return bus_log_create_error(r
);
1143 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
1145 return bus_log_create_error(r
);
1148 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1150 return bus_log_create_error(r
);
1152 r
= transient_scope_set_properties(m
);
1154 return bus_log_create_error(r
);
1156 r
= sd_bus_message_close_container(m
);
1158 return bus_log_create_error(r
);
1160 /* Auxiliary units */
1161 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
1163 return bus_log_create_error(r
);
1165 polkit_agent_open_if_enabled();
1167 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1169 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
1174 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
1175 return log_error_errno(errno
, "Failed to set nice level: %m");
1178 if (arg_exec_group
) {
1181 r
= get_group_creds(&arg_exec_group
, &gid
);
1183 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
1185 if (setresgid(gid
, gid
, gid
) < 0)
1186 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1189 if (arg_exec_user
) {
1190 const char *home
, *shell
;
1194 r
= get_user_creds_clean(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
1196 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
1199 r
= strv_extendf(&user_env
, "HOME=%s", home
);
1205 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
1210 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
1214 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
1218 if (!arg_exec_group
) {
1219 if (setresgid(gid
, gid
, gid
) < 0)
1220 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1223 if (setresuid(uid
, uid
, uid
) < 0)
1224 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
1227 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
1231 r
= sd_bus_message_read(reply
, "o", &object
);
1233 return bus_log_parse_error(r
);
1235 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1240 log_info("Running scope as unit: %s", scope
);
1242 execvpe(argv
[0], argv
, env
);
1244 return log_error_errno(errno
, "Failed to execute: %m");
1247 static int start_transient_timer(
1251 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1252 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1253 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1254 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1255 const char *object
= NULL
;
1261 r
= bus_wait_for_jobs_new(bus
, &w
);
1266 switch (unit_name_to_type(arg_unit
)) {
1269 service
= strdup(arg_unit
);
1273 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1275 return log_error_errno(r
, "Failed to change unit suffix: %m");
1279 timer
= strdup(arg_unit
);
1283 r
= unit_name_change_suffix(timer
, ".service", &service
);
1285 return log_error_errno(r
, "Failed to change unit suffix: %m");
1289 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1291 return log_error_errno(r
, "Failed to mangle unit name: %m");
1293 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1295 return log_error_errno(r
, "Failed to mangle unit name: %m");
1300 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
1304 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1306 return log_error_errno(r
, "Failed to change unit suffix: %m");
1309 r
= sd_bus_message_new_method_call(
1312 "org.freedesktop.systemd1",
1313 "/org/freedesktop/systemd1",
1314 "org.freedesktop.systemd1.Manager",
1315 "StartTransientUnit");
1317 return bus_log_create_error(r
);
1319 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1321 return bus_log_create_error(r
);
1324 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1326 return bus_log_create_error(r
);
1329 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1331 return bus_log_create_error(r
);
1333 r
= transient_timer_set_properties(m
);
1335 return bus_log_create_error(r
);
1337 r
= sd_bus_message_close_container(m
);
1339 return bus_log_create_error(r
);
1341 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1343 return bus_log_create_error(r
);
1345 if (!strv_isempty(argv
)) {
1346 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1348 return bus_log_create_error(r
);
1350 r
= sd_bus_message_append(m
, "s", service
);
1352 return bus_log_create_error(r
);
1354 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1356 return bus_log_create_error(r
);
1358 r
= transient_service_set_properties(m
, argv
, NULL
);
1360 return bus_log_create_error(r
);
1362 r
= sd_bus_message_close_container(m
);
1364 return bus_log_create_error(r
);
1366 r
= sd_bus_message_close_container(m
);
1368 return bus_log_create_error(r
);
1371 r
= sd_bus_message_close_container(m
);
1373 return bus_log_create_error(r
);
1375 polkit_agent_open_if_enabled();
1377 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1379 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1383 r
= sd_bus_message_read(reply
, "o", &object
);
1385 return bus_log_parse_error(r
);
1387 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1392 log_info("Running timer as unit: %s", timer
);
1394 log_info("Will run service as unit: %s", service
);
1400 int main(int argc
, char* argv
[]) {
1401 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1402 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1403 int r
, retval
= EXIT_SUCCESS
;
1405 log_parse_environment();
1408 r
= parse_argv(argc
, argv
);
1412 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1413 /* Patch in an absolute path */
1415 r
= find_binary(argv
[optind
], &command
);
1417 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1421 argv
[optind
] = command
;
1424 if (!arg_description
) {
1425 description
= strv_join(argv
+ optind
, " ");
1431 if (arg_unit
&& isempty(description
)) {
1432 r
= free_and_strdup(&description
, arg_unit
);
1437 arg_description
= description
;
1440 /* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the limited direct
1442 if (arg_wait
|| arg_pty
)
1443 r
= bus_connect_transport(arg_transport
, arg_host
, arg_user
, &bus
);
1445 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1447 log_error_errno(r
, "Failed to create bus connection: %m");
1452 r
= start_transient_scope(bus
, argv
+ optind
);
1453 else if (with_timer())
1454 r
= start_transient_timer(bus
, argv
+ optind
);
1456 r
= start_transient_service(bus
, argv
+ optind
, &retval
);
1459 strv_free(arg_environment
);
1460 strv_free(arg_property
);
1461 strv_free(arg_timer_property
);
1463 return r
< 0 ? EXIT_FAILURE
: retval
;