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 "formats-util.h"
34 #include "parse-util.h"
35 #include "path-util.h"
37 #include "signal-util.h"
38 #include "spawn-polkit-agent.h"
40 #include "terminal-util.h"
41 #include "unit-name.h"
42 #include "user-util.h"
44 static bool arg_ask_password
= true;
45 static bool arg_scope
= false;
46 static bool arg_remain_after_exit
= false;
47 static bool arg_no_block
= false;
48 static const char *arg_unit
= NULL
;
49 static const char *arg_description
= NULL
;
50 static const char *arg_slice
= NULL
;
51 static bool arg_send_sighup
= false;
52 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
53 static const char *arg_host
= NULL
;
54 static bool arg_user
= false;
55 static const char *arg_service_type
= NULL
;
56 static const char *arg_exec_user
= NULL
;
57 static const char *arg_exec_group
= NULL
;
58 static int arg_nice
= 0;
59 static bool arg_nice_set
= false;
60 static char **arg_environment
= NULL
;
61 static char **arg_property
= NULL
;
62 static bool arg_pty
= false;
63 static usec_t arg_on_active
= 0;
64 static usec_t arg_on_boot
= 0;
65 static usec_t arg_on_startup
= 0;
66 static usec_t arg_on_unit_active
= 0;
67 static usec_t arg_on_unit_inactive
= 0;
68 static const char *arg_on_calendar
= NULL
;
69 static char **arg_timer_property
= NULL
;
70 static bool arg_quiet
= false;
72 static void polkit_agent_open_if_enabled(void) {
74 /* Open the polkit agent as a child process if necessary */
75 if (!arg_ask_password
)
78 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
84 static void help(void) {
85 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
86 "Run the specified command in a transient scope or service.\n\n"
87 " -h --help Show this help\n"
88 " --version Show package version\n"
89 " --no-ask-password Do not prompt for password\n"
90 " --user Run as user unit\n"
91 " -H --host=[USER@]HOST Operate on remote host\n"
92 " -M --machine=CONTAINER Operate on local container\n"
93 " --scope Run this as scope rather than service\n"
94 " --unit=UNIT Run under the specified unit name\n"
95 " -p --property=NAME=VALUE Set service or scope unit property\n"
96 " --description=TEXT Description for unit\n"
97 " --slice=SLICE Run in the specified slice\n"
98 " --no-block Do not wait until operation finished\n"
99 " -r --remain-after-exit Leave service around until explicitly stopped\n"
100 " --send-sighup Send SIGHUP when terminating\n"
101 " --service-type=TYPE Service type\n"
102 " --uid=USER Run as system user\n"
103 " --gid=GROUP Run as system group\n"
104 " --nice=NICE Nice level\n"
105 " -E --setenv=NAME=VALUE Set environment\n"
106 " -t --pty Run service on pseudo tty\n"
107 " -q --quiet Suppress information messages during runtime\n\n"
109 " --on-active=SECONDS Run after SECONDS delay\n"
110 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
111 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
112 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
113 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
114 " --on-calendar=SPEC Realtime timer\n"
115 " --timer-property=NAME=VALUE Set timer unit property\n"
116 , program_invocation_short_name
);
119 static bool with_timer(void) {
120 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
123 static int parse_argv(int argc
, char *argv
[]) {
142 ARG_ON_UNIT_INACTIVE
,
149 static const struct option options
[] = {
150 { "help", no_argument
, NULL
, 'h' },
151 { "version", no_argument
, NULL
, ARG_VERSION
},
152 { "user", no_argument
, NULL
, ARG_USER
},
153 { "system", no_argument
, NULL
, ARG_SYSTEM
},
154 { "scope", no_argument
, NULL
, ARG_SCOPE
},
155 { "unit", required_argument
, NULL
, ARG_UNIT
},
156 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
157 { "slice", required_argument
, NULL
, ARG_SLICE
},
158 { "remain-after-exit", no_argument
, NULL
, 'r' },
159 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
160 { "host", required_argument
, NULL
, 'H' },
161 { "machine", required_argument
, NULL
, 'M' },
162 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
163 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
164 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
165 { "nice", required_argument
, NULL
, ARG_NICE
},
166 { "setenv", required_argument
, NULL
, 'E' },
167 { "property", required_argument
, NULL
, 'p' },
168 { "tty", no_argument
, NULL
, 't' }, /* deprecated */
169 { "pty", no_argument
, NULL
, 't' },
170 { "quiet", no_argument
, NULL
, 'q' },
171 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
172 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
173 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
174 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
175 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
176 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
177 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
178 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
179 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
188 while ((c
= getopt_long(argc
, argv
, "+hrH:M:E:p:tq", options
, NULL
)) >= 0)
199 case ARG_NO_ASK_PASSWORD
:
200 arg_ask_password
= false;
219 case ARG_DESCRIPTION
:
220 arg_description
= optarg
;
227 case ARG_SEND_SIGHUP
:
228 arg_send_sighup
= true;
232 arg_remain_after_exit
= true;
236 arg_transport
= BUS_TRANSPORT_REMOTE
;
241 arg_transport
= BUS_TRANSPORT_MACHINE
;
245 case ARG_SERVICE_TYPE
:
246 arg_service_type
= optarg
;
250 arg_exec_user
= optarg
;
254 arg_exec_group
= optarg
;
258 r
= parse_nice(optarg
, &arg_nice
);
260 return log_error_errno(r
, "Failed to parse nice value: %s", optarg
);
266 if (strv_extend(&arg_environment
, optarg
) < 0)
272 if (strv_extend(&arg_property
, optarg
) < 0)
287 r
= parse_sec(optarg
, &arg_on_active
);
289 log_error("Failed to parse timer value: %s", optarg
);
297 r
= parse_sec(optarg
, &arg_on_boot
);
299 log_error("Failed to parse timer value: %s", optarg
);
307 r
= parse_sec(optarg
, &arg_on_startup
);
309 log_error("Failed to parse timer value: %s", optarg
);
315 case ARG_ON_UNIT_ACTIVE
:
317 r
= parse_sec(optarg
, &arg_on_unit_active
);
319 log_error("Failed to parse timer value: %s", optarg
);
325 case ARG_ON_UNIT_INACTIVE
:
327 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
329 log_error("Failed to parse timer value: %s", optarg
);
335 case ARG_ON_CALENDAR
: {
336 CalendarSpec
*spec
= NULL
;
338 r
= calendar_spec_from_string(optarg
, &spec
);
340 log_error("Invalid calendar spec: %s", optarg
);
344 calendar_spec_free(spec
);
345 arg_on_calendar
= optarg
;
349 case ARG_TIMER_PROPERTY
:
351 if (strv_extend(&arg_timer_property
, optarg
) < 0)
364 assert_not_reached("Unhandled option");
367 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
368 log_error("Command line to execute required.");
372 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
373 log_error("Execution in user context is not supported on non-local systems.");
377 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
378 log_error("Scope execution is not supported on non-local systems.");
382 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
383 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
387 if (arg_pty
&& (with_timer() || arg_scope
)) {
388 log_error("--pty is not compatible in timer or --scope mode.");
392 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
393 log_error("--pty is only supported when connecting to the local system or containers.");
397 if (arg_scope
&& with_timer()) {
398 log_error("Timer options are not supported in --scope mode.");
402 if (arg_timer_property
&& !with_timer()) {
403 log_error("--timer-property= has no effect without any other timer options.");
410 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
413 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
417 r
= bus_append_unit_property_assignment_many(m
, properties
);
424 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
428 if (!isempty(arg_slice
)) {
429 _cleanup_free_
char *slice
;
431 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
435 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
443 static int transient_kill_set_properties(sd_bus_message
*m
) {
447 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
452 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
457 r
= transient_unit_set_properties(m
, arg_property
);
461 r
= transient_kill_set_properties(m
);
465 r
= transient_cgroup_set_properties(m
);
469 if (arg_remain_after_exit
) {
470 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
475 if (arg_service_type
) {
476 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
482 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
487 if (arg_exec_group
) {
488 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
494 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
502 r
= sd_bus_message_append(m
,
504 "StandardInput", "s", "tty",
505 "StandardOutput", "s", "tty",
506 "StandardError", "s", "tty",
507 "TTYPath", "s", pty_path
);
515 n
= strjoina("TERM=", e
);
516 r
= sd_bus_message_append(m
,
518 "Environment", "as", 1, n
);
524 if (!strv_isempty(arg_environment
)) {
525 r
= sd_bus_message_open_container(m
, 'r', "sv");
529 r
= sd_bus_message_append(m
, "s", "Environment");
533 r
= sd_bus_message_open_container(m
, 'v', "as");
537 r
= sd_bus_message_append_strv(m
, arg_environment
);
541 r
= sd_bus_message_close_container(m
);
545 r
= sd_bus_message_close_container(m
);
552 r
= sd_bus_message_open_container(m
, 'r', "sv");
556 r
= sd_bus_message_append(m
, "s", "ExecStart");
560 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
564 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
568 r
= sd_bus_message_open_container(m
, 'r', "sasb");
572 r
= sd_bus_message_append(m
, "s", argv
[0]);
576 r
= sd_bus_message_append_strv(m
, argv
);
580 r
= sd_bus_message_append(m
, "b", false);
584 r
= sd_bus_message_close_container(m
);
588 r
= sd_bus_message_close_container(m
);
592 r
= sd_bus_message_close_container(m
);
596 r
= sd_bus_message_close_container(m
);
604 static int transient_scope_set_properties(sd_bus_message
*m
) {
609 r
= transient_unit_set_properties(m
, arg_property
);
613 r
= transient_kill_set_properties(m
);
617 r
= transient_cgroup_set_properties(m
);
621 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
628 static int transient_timer_set_properties(sd_bus_message
*m
) {
633 r
= transient_unit_set_properties(m
, arg_timer_property
);
637 /* Automatically clean up our transient timers */
638 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterElapse", "b", false);
643 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
649 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
654 if (arg_on_startup
) {
655 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
660 if (arg_on_unit_active
) {
661 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
666 if (arg_on_unit_inactive
) {
667 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
672 if (arg_on_calendar
) {
673 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
681 static int make_unit_name(sd_bus
*bus
, UnitType t
, char **ret
) {
682 const char *unique
, *id
;
688 assert(t
< _UNIT_TYPE_MAX
);
690 r
= sd_bus_get_unique_name(bus
, &unique
);
694 /* We couldn't get the unique name, which is a pretty
695 * common case if we are connected to systemd
696 * directly. In that case, just pick a random uuid as
699 r
= sd_id128_randomize(&rnd
);
701 return log_error_errno(r
, "Failed to generate random run unit name: %m");
703 if (asprintf(ret
, "run-r" SD_ID128_FORMAT_STR
".%s", SD_ID128_FORMAT_VAL(rnd
), unit_type_to_string(t
)) < 0)
709 /* We managed to get the unique name, then let's use that to
710 * name our transient units. */
712 id
= startswith(unique
, ":1.");
714 log_error("Unique name %s has unexpected format.", unique
);
718 p
= strjoin("run-u", id
, ".", unit_type_to_string(t
), NULL
);
726 static int start_transient_service(
730 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
731 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
732 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
733 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
734 _cleanup_close_
int master
= -1;
742 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
743 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
745 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
747 r
= ptsname_malloc(master
, &pty_path
);
749 return log_error_errno(r
, "Failed to determine tty name: %m");
751 if (unlockpt(master
) < 0)
752 return log_error_errno(errno
, "Failed to unlock tty: %m");
754 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
755 _cleanup_(sd_bus_unrefp
) sd_bus
*system_bus
= NULL
;
756 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pty_reply
= NULL
;
759 r
= sd_bus_default_system(&system_bus
);
761 return log_error_errno(r
, "Failed to connect to system bus: %m");
763 r
= sd_bus_call_method(system_bus
,
764 "org.freedesktop.machine1",
765 "/org/freedesktop/machine1",
766 "org.freedesktop.machine1.Manager",
772 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
776 r
= sd_bus_message_read(pty_reply
, "hs", &master
, &s
);
778 return bus_log_parse_error(r
);
780 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
782 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
784 pty_path
= strdup(s
);
788 assert_not_reached("Can't allocate tty via ssh");
792 r
= bus_wait_for_jobs_new(bus
, &w
);
794 return log_error_errno(r
, "Could not watch jobs: %m");
798 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
800 return log_error_errno(r
, "Failed to mangle unit name: %m");
802 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
807 r
= sd_bus_message_new_method_call(
810 "org.freedesktop.systemd1",
811 "/org/freedesktop/systemd1",
812 "org.freedesktop.systemd1.Manager",
813 "StartTransientUnit");
815 return bus_log_create_error(r
);
817 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
819 return bus_log_create_error(r
);
822 r
= sd_bus_message_append(m
, "ss", service
, "fail");
824 return bus_log_create_error(r
);
827 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
829 return bus_log_create_error(r
);
831 r
= transient_service_set_properties(m
, argv
, pty_path
);
833 return bus_log_create_error(r
);
835 r
= sd_bus_message_close_container(m
);
837 return bus_log_create_error(r
);
839 /* Auxiliary units */
840 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
842 return bus_log_create_error(r
);
844 polkit_agent_open_if_enabled();
846 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
848 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
853 r
= sd_bus_message_read(reply
, "o", &object
);
855 return bus_log_parse_error(r
);
857 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
863 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
864 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
867 r
= sd_event_default(&event
);
869 return log_error_errno(r
, "Failed to get event loop: %m");
871 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
873 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
874 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
877 log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service
);
879 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
881 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
883 r
= sd_event_loop(event
);
885 return log_error_errno(r
, "Failed to run event loop: %m");
887 pty_forward_get_last_char(forward
, &last_char
);
889 forward
= pty_forward_free(forward
);
891 if (!arg_quiet
&& last_char
!= '\n')
894 } else if (!arg_quiet
)
895 log_info("Running as unit: %s", service
);
900 static int start_transient_scope(
904 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
905 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
906 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
907 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
908 _cleanup_free_
char *scope
= NULL
;
909 const char *object
= NULL
;
915 r
= bus_wait_for_jobs_new(bus
, &w
);
920 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
922 return log_error_errno(r
, "Failed to mangle scope name: %m");
924 r
= make_unit_name(bus
, UNIT_SCOPE
, &scope
);
929 r
= sd_bus_message_new_method_call(
932 "org.freedesktop.systemd1",
933 "/org/freedesktop/systemd1",
934 "org.freedesktop.systemd1.Manager",
935 "StartTransientUnit");
937 return bus_log_create_error(r
);
939 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
941 return bus_log_create_error(r
);
944 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
946 return bus_log_create_error(r
);
949 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
951 return bus_log_create_error(r
);
953 r
= transient_scope_set_properties(m
);
955 return bus_log_create_error(r
);
957 r
= sd_bus_message_close_container(m
);
959 return bus_log_create_error(r
);
961 /* Auxiliary units */
962 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
964 return bus_log_create_error(r
);
966 polkit_agent_open_if_enabled();
968 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
970 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
975 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
976 return log_error_errno(errno
, "Failed to set nice level: %m");
979 if (arg_exec_group
) {
982 r
= get_group_creds(&arg_exec_group
, &gid
);
984 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
986 if (setresgid(gid
, gid
, gid
) < 0)
987 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
991 const char *home
, *shell
;
995 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
997 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
999 r
= strv_extendf(&user_env
, "HOME=%s", home
);
1003 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
1007 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
1011 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
1015 if (!arg_exec_group
) {
1016 if (setresgid(gid
, gid
, gid
) < 0)
1017 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1020 if (setresuid(uid
, uid
, uid
) < 0)
1021 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
1024 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
1028 r
= sd_bus_message_read(reply
, "o", &object
);
1030 return bus_log_parse_error(r
);
1032 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1037 log_info("Running scope as unit: %s", scope
);
1039 execvpe(argv
[0], argv
, env
);
1041 return log_error_errno(errno
, "Failed to execute: %m");
1044 static int start_transient_timer(
1048 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1049 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1050 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1051 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1052 const char *object
= NULL
;
1058 r
= bus_wait_for_jobs_new(bus
, &w
);
1063 switch (unit_name_to_type(arg_unit
)) {
1066 service
= strdup(arg_unit
);
1070 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1072 return log_error_errno(r
, "Failed to change unit suffix: %m");
1076 timer
= strdup(arg_unit
);
1080 r
= unit_name_change_suffix(timer
, ".service", &service
);
1082 return log_error_errno(r
, "Failed to change unit suffix: %m");
1086 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1088 return log_error_errno(r
, "Failed to mangle unit name: %m");
1090 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1092 return log_error_errno(r
, "Failed to mangle unit name: %m");
1097 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
1101 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1103 return log_error_errno(r
, "Failed to change unit suffix: %m");
1106 r
= sd_bus_message_new_method_call(
1109 "org.freedesktop.systemd1",
1110 "/org/freedesktop/systemd1",
1111 "org.freedesktop.systemd1.Manager",
1112 "StartTransientUnit");
1114 return bus_log_create_error(r
);
1116 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1118 return bus_log_create_error(r
);
1121 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1123 return bus_log_create_error(r
);
1126 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1128 return bus_log_create_error(r
);
1130 r
= transient_timer_set_properties(m
);
1132 return bus_log_create_error(r
);
1134 r
= sd_bus_message_close_container(m
);
1136 return bus_log_create_error(r
);
1138 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1140 return bus_log_create_error(r
);
1142 if (!strv_isempty(argv
)) {
1143 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1145 return bus_log_create_error(r
);
1147 r
= sd_bus_message_append(m
, "s", service
);
1149 return bus_log_create_error(r
);
1151 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1153 return bus_log_create_error(r
);
1155 r
= transient_service_set_properties(m
, argv
, NULL
);
1157 return bus_log_create_error(r
);
1159 r
= sd_bus_message_close_container(m
);
1161 return bus_log_create_error(r
);
1163 r
= sd_bus_message_close_container(m
);
1165 return bus_log_create_error(r
);
1168 r
= sd_bus_message_close_container(m
);
1170 return bus_log_create_error(r
);
1172 polkit_agent_open_if_enabled();
1174 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1176 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1180 r
= sd_bus_message_read(reply
, "o", &object
);
1182 return bus_log_parse_error(r
);
1184 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1188 log_info("Running timer as unit: %s", timer
);
1190 log_info("Will run service as unit: %s", service
);
1195 int main(int argc
, char* argv
[]) {
1196 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1197 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1200 log_parse_environment();
1203 r
= parse_argv(argc
, argv
);
1207 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1208 /* Patch in an absolute path */
1210 r
= find_binary(argv
[optind
], &command
);
1212 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1216 argv
[optind
] = command
;
1219 if (!arg_description
) {
1220 description
= strv_join(argv
+ optind
, " ");
1226 if (arg_unit
&& isempty(description
)) {
1227 r
= free_and_strdup(&description
, arg_unit
);
1232 arg_description
= description
;
1235 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1237 log_error_errno(r
, "Failed to create bus connection: %m");
1242 r
= start_transient_scope(bus
, argv
+ optind
);
1243 else if (with_timer())
1244 r
= start_transient_timer(bus
, argv
+ optind
);
1246 r
= start_transient_service(bus
, argv
+ optind
);
1249 strv_free(arg_environment
);
1250 strv_free(arg_property
);
1251 strv_free(arg_timer_property
);
1253 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;