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 or timer\n"
87 "unit. If a timer option is specified and the unit specified with\n"
88 "the --unit option exists, the command can be omitted.\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 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 " --send-sighup Send SIGHUP when terminating\n"
103 " --service-type=TYPE Service type\n"
104 " --uid=USER Run as system user\n"
105 " --gid=GROUP Run as system group\n"
106 " --nice=NICE Nice level\n"
107 " -E --setenv=NAME=VALUE Set environment\n"
108 " -t --pty Run service on pseudo tty\n"
109 " -q --quiet Suppress information messages during runtime\n\n"
111 " --on-active=SECONDS Run after SECONDS delay\n"
112 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
113 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
114 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
115 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
116 " --on-calendar=SPEC Realtime timer\n"
117 " --timer-property=NAME=VALUE Set timer unit property\n",
118 program_invocation_short_name
);
121 static bool with_timer(void) {
122 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
125 static int parse_argv(int argc
, char *argv
[]) {
144 ARG_ON_UNIT_INACTIVE
,
151 static const struct option options
[] = {
152 { "help", no_argument
, NULL
, 'h' },
153 { "version", no_argument
, NULL
, ARG_VERSION
},
154 { "user", no_argument
, NULL
, ARG_USER
},
155 { "system", no_argument
, NULL
, ARG_SYSTEM
},
156 { "scope", no_argument
, NULL
, ARG_SCOPE
},
157 { "unit", required_argument
, NULL
, ARG_UNIT
},
158 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
159 { "slice", required_argument
, NULL
, ARG_SLICE
},
160 { "remain-after-exit", no_argument
, NULL
, 'r' },
161 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
162 { "host", required_argument
, NULL
, 'H' },
163 { "machine", required_argument
, NULL
, 'M' },
164 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
165 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
166 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
167 { "nice", required_argument
, NULL
, ARG_NICE
},
168 { "setenv", required_argument
, NULL
, 'E' },
169 { "property", required_argument
, NULL
, 'p' },
170 { "tty", no_argument
, NULL
, 't' }, /* deprecated */
171 { "pty", no_argument
, NULL
, 't' },
172 { "quiet", no_argument
, NULL
, 'q' },
173 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
174 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
175 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
176 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
177 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
178 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
179 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
180 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
181 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
190 while ((c
= getopt_long(argc
, argv
, "+hrH:M:p:tq", options
, NULL
)) >= 0)
198 case ARG_NO_ASK_PASSWORD
:
199 arg_ask_password
= false;
221 case ARG_DESCRIPTION
:
222 arg_description
= optarg
;
229 case ARG_SEND_SIGHUP
:
230 arg_send_sighup
= true;
234 arg_remain_after_exit
= true;
238 arg_transport
= BUS_TRANSPORT_REMOTE
;
243 arg_transport
= BUS_TRANSPORT_MACHINE
;
247 case ARG_SERVICE_TYPE
:
248 arg_service_type
= optarg
;
252 arg_exec_user
= optarg
;
256 arg_exec_group
= optarg
;
260 r
= safe_atoi(optarg
, &arg_nice
);
261 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
262 log_error("Failed to parse nice value");
270 if (strv_extend(&arg_environment
, optarg
) < 0)
276 if (strv_extend(&arg_property
, optarg
) < 0)
291 r
= parse_sec(optarg
, &arg_on_active
);
293 log_error("Failed to parse timer value: %s", optarg
);
301 r
= parse_sec(optarg
, &arg_on_boot
);
303 log_error("Failed to parse timer value: %s", optarg
);
311 r
= parse_sec(optarg
, &arg_on_startup
);
313 log_error("Failed to parse timer value: %s", optarg
);
319 case ARG_ON_UNIT_ACTIVE
:
321 r
= parse_sec(optarg
, &arg_on_unit_active
);
323 log_error("Failed to parse timer value: %s", optarg
);
329 case ARG_ON_UNIT_INACTIVE
:
331 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
333 log_error("Failed to parse timer value: %s", optarg
);
339 case ARG_ON_CALENDAR
: {
340 CalendarSpec
*spec
= NULL
;
342 r
= calendar_spec_from_string(optarg
, &spec
);
344 log_error("Invalid calendar spec: %s", optarg
);
348 calendar_spec_free(spec
);
349 arg_on_calendar
= optarg
;
353 case ARG_TIMER_PROPERTY
:
355 if (strv_extend(&arg_timer_property
, optarg
) < 0)
368 assert_not_reached("Unhandled option");
371 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
372 log_error("Command line to execute required.");
376 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
377 log_error("Execution in user context is not supported on non-local systems.");
381 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
382 log_error("Scope execution is not supported on non-local systems.");
386 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
387 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
391 if (arg_pty
&& (with_timer() || arg_scope
)) {
392 log_error("--pty is not compatible in timer or --scope mode.");
396 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
397 log_error("--pty is only supported when connecting to the local system or containers.");
401 if (arg_scope
&& with_timer()) {
402 log_error("Timer options are not supported in --scope mode.");
406 if (arg_timer_property
&& !with_timer()) {
407 log_error("--timer-property= has no effect without any other timer options.");
414 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
418 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
422 STRV_FOREACH(i
, properties
) {
423 r
= bus_append_unit_property_assignment(m
, *i
);
431 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
435 if (!isempty(arg_slice
)) {
436 _cleanup_free_
char *slice
;
438 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
442 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
450 static int transient_kill_set_properties(sd_bus_message
*m
) {
454 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
459 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
464 r
= transient_unit_set_properties(m
, arg_property
);
468 r
= transient_kill_set_properties(m
);
472 r
= transient_cgroup_set_properties(m
);
476 if (arg_remain_after_exit
) {
477 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
482 if (arg_service_type
) {
483 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
489 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
494 if (arg_exec_group
) {
495 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
501 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
509 r
= sd_bus_message_append(m
,
511 "StandardInput", "s", "tty",
512 "StandardOutput", "s", "tty",
513 "StandardError", "s", "tty",
514 "TTYPath", "s", pty_path
);
522 n
= strjoina("TERM=", e
);
523 r
= sd_bus_message_append(m
,
525 "Environment", "as", 1, n
);
531 if (!strv_isempty(arg_environment
)) {
532 r
= sd_bus_message_open_container(m
, 'r', "sv");
536 r
= sd_bus_message_append(m
, "s", "Environment");
540 r
= sd_bus_message_open_container(m
, 'v', "as");
544 r
= sd_bus_message_append_strv(m
, arg_environment
);
548 r
= sd_bus_message_close_container(m
);
552 r
= sd_bus_message_close_container(m
);
559 r
= sd_bus_message_open_container(m
, 'r', "sv");
563 r
= sd_bus_message_append(m
, "s", "ExecStart");
567 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
571 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
575 r
= sd_bus_message_open_container(m
, 'r', "sasb");
579 r
= sd_bus_message_append(m
, "s", argv
[0]);
583 r
= sd_bus_message_append_strv(m
, argv
);
587 r
= sd_bus_message_append(m
, "b", false);
591 r
= sd_bus_message_close_container(m
);
595 r
= sd_bus_message_close_container(m
);
599 r
= sd_bus_message_close_container(m
);
603 r
= sd_bus_message_close_container(m
);
611 static int transient_scope_set_properties(sd_bus_message
*m
) {
616 r
= transient_unit_set_properties(m
, arg_property
);
620 r
= transient_kill_set_properties(m
);
624 r
= transient_cgroup_set_properties(m
);
628 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
635 static int transient_timer_set_properties(sd_bus_message
*m
) {
640 r
= transient_unit_set_properties(m
, arg_timer_property
);
644 /* Automatically clean up our transient timers */
645 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterElapse", "b", false);
650 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
656 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
661 if (arg_on_startup
) {
662 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
667 if (arg_on_unit_active
) {
668 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
673 if (arg_on_unit_inactive
) {
674 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
679 if (arg_on_calendar
) {
680 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
688 static int make_unit_name(sd_bus
*bus
, UnitType t
, char **ret
) {
689 const char *unique
, *id
;
695 assert(t
< _UNIT_TYPE_MAX
);
697 r
= sd_bus_get_unique_name(bus
, &unique
);
701 /* We couldn't get the unique name, which is a pretty
702 * common case if we are connected to systemd
703 * directly. In that case, just pick a random uuid as
706 r
= sd_id128_randomize(&rnd
);
708 return log_error_errno(r
, "Failed to generate random run unit name: %m");
710 if (asprintf(ret
, "run-r" SD_ID128_FORMAT_STR
".%s", SD_ID128_FORMAT_VAL(rnd
), unit_type_to_string(t
)) < 0)
716 /* We managed to get the unique name, then let's use that to
717 * name our transient units. */
719 id
= startswith(unique
, ":1.");
721 log_error("Unique name %s has unexpected format.", unique
);
725 p
= strjoin("run-u", id
, ".", unit_type_to_string(t
), NULL
);
733 static int start_transient_service(
737 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
738 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
739 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
740 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
741 _cleanup_close_
int master
= -1;
749 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
750 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
752 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
754 r
= ptsname_malloc(master
, &pty_path
);
756 return log_error_errno(r
, "Failed to determine tty name: %m");
758 if (unlockpt(master
) < 0)
759 return log_error_errno(errno
, "Failed to unlock tty: %m");
761 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
762 _cleanup_(sd_bus_unrefp
) sd_bus
*system_bus
= NULL
;
763 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*pty_reply
= NULL
;
766 r
= sd_bus_default_system(&system_bus
);
768 return log_error_errno(r
, "Failed to connect to system bus: %m");
770 r
= sd_bus_call_method(system_bus
,
771 "org.freedesktop.machine1",
772 "/org/freedesktop/machine1",
773 "org.freedesktop.machine1.Manager",
779 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
783 r
= sd_bus_message_read(pty_reply
, "hs", &master
, &s
);
785 return bus_log_parse_error(r
);
787 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
789 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
791 pty_path
= strdup(s
);
795 assert_not_reached("Can't allocate tty via ssh");
799 r
= bus_wait_for_jobs_new(bus
, &w
);
801 return log_error_errno(r
, "Could not watch jobs: %m");
805 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
807 return log_error_errno(r
, "Failed to mangle unit name: %m");
809 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
814 r
= sd_bus_message_new_method_call(
817 "org.freedesktop.systemd1",
818 "/org/freedesktop/systemd1",
819 "org.freedesktop.systemd1.Manager",
820 "StartTransientUnit");
822 return bus_log_create_error(r
);
824 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
826 return bus_log_create_error(r
);
829 r
= sd_bus_message_append(m
, "ss", service
, "fail");
831 return bus_log_create_error(r
);
834 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
836 return bus_log_create_error(r
);
838 r
= transient_service_set_properties(m
, argv
, pty_path
);
840 return bus_log_create_error(r
);
842 r
= sd_bus_message_close_container(m
);
844 return bus_log_create_error(r
);
846 /* Auxiliary units */
847 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
849 return bus_log_create_error(r
);
851 polkit_agent_open_if_enabled();
853 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
855 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
860 r
= sd_bus_message_read(reply
, "o", &object
);
862 return bus_log_parse_error(r
);
864 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
870 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
871 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
874 r
= sd_event_default(&event
);
876 return log_error_errno(r
, "Failed to get event loop: %m");
878 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
880 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
881 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
884 log_info("Running as unit: %s\nPress ^] three times within 1s to disconnect TTY.", service
);
886 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
888 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
890 r
= sd_event_loop(event
);
892 return log_error_errno(r
, "Failed to run event loop: %m");
894 pty_forward_get_last_char(forward
, &last_char
);
896 forward
= pty_forward_free(forward
);
898 if (!arg_quiet
&& last_char
!= '\n')
901 } else if (!arg_quiet
)
902 log_info("Running as unit: %s", service
);
907 static int start_transient_scope(
911 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
912 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
913 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
914 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
915 _cleanup_free_
char *scope
= NULL
;
916 const char *object
= NULL
;
922 r
= bus_wait_for_jobs_new(bus
, &w
);
927 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
929 return log_error_errno(r
, "Failed to mangle scope name: %m");
931 r
= make_unit_name(bus
, UNIT_SCOPE
, &scope
);
936 r
= sd_bus_message_new_method_call(
939 "org.freedesktop.systemd1",
940 "/org/freedesktop/systemd1",
941 "org.freedesktop.systemd1.Manager",
942 "StartTransientUnit");
944 return bus_log_create_error(r
);
946 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
948 return bus_log_create_error(r
);
951 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
953 return bus_log_create_error(r
);
956 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
958 return bus_log_create_error(r
);
960 r
= transient_scope_set_properties(m
);
962 return bus_log_create_error(r
);
964 r
= sd_bus_message_close_container(m
);
966 return bus_log_create_error(r
);
968 /* Auxiliary units */
969 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
971 return bus_log_create_error(r
);
973 polkit_agent_open_if_enabled();
975 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
977 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
982 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
983 return log_error_errno(errno
, "Failed to set nice level: %m");
986 if (arg_exec_group
) {
989 r
= get_group_creds(&arg_exec_group
, &gid
);
991 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
993 if (setresgid(gid
, gid
, gid
) < 0)
994 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
998 const char *home
, *shell
;
1002 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
1004 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
1006 r
= strv_extendf(&user_env
, "HOME=%s", home
);
1010 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
1014 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
1018 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
1022 if (!arg_exec_group
) {
1023 if (setresgid(gid
, gid
, gid
) < 0)
1024 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1027 if (setresuid(uid
, uid
, uid
) < 0)
1028 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
1031 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
1035 r
= sd_bus_message_read(reply
, "o", &object
);
1037 return bus_log_parse_error(r
);
1039 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1044 log_info("Running scope as unit: %s", scope
);
1046 execvpe(argv
[0], argv
, env
);
1048 return log_error_errno(errno
, "Failed to execute: %m");
1051 static int start_transient_timer(
1055 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1056 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
, *reply
= NULL
;
1057 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1058 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1059 const char *object
= NULL
;
1065 r
= bus_wait_for_jobs_new(bus
, &w
);
1070 switch (unit_name_to_type(arg_unit
)) {
1073 service
= strdup(arg_unit
);
1077 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1079 return log_error_errno(r
, "Failed to change unit suffix: %m");
1083 timer
= strdup(arg_unit
);
1087 r
= unit_name_change_suffix(timer
, ".service", &service
);
1089 return log_error_errno(r
, "Failed to change unit suffix: %m");
1093 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1095 return log_error_errno(r
, "Failed to mangle unit name: %m");
1097 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1099 return log_error_errno(r
, "Failed to mangle unit name: %m");
1104 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
1108 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1110 return log_error_errno(r
, "Failed to change unit suffix: %m");
1113 r
= sd_bus_message_new_method_call(
1116 "org.freedesktop.systemd1",
1117 "/org/freedesktop/systemd1",
1118 "org.freedesktop.systemd1.Manager",
1119 "StartTransientUnit");
1121 return bus_log_create_error(r
);
1123 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1125 return bus_log_create_error(r
);
1128 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1130 return bus_log_create_error(r
);
1133 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1135 return bus_log_create_error(r
);
1137 r
= transient_timer_set_properties(m
);
1139 return bus_log_create_error(r
);
1141 r
= sd_bus_message_close_container(m
);
1143 return bus_log_create_error(r
);
1145 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1147 return bus_log_create_error(r
);
1150 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1152 return bus_log_create_error(r
);
1154 r
= sd_bus_message_append(m
, "s", service
);
1156 return bus_log_create_error(r
);
1158 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1160 return bus_log_create_error(r
);
1162 r
= transient_service_set_properties(m
, argv
, NULL
);
1164 return bus_log_create_error(r
);
1166 r
= sd_bus_message_close_container(m
);
1168 return bus_log_create_error(r
);
1170 r
= sd_bus_message_close_container(m
);
1172 return bus_log_create_error(r
);
1175 r
= sd_bus_message_close_container(m
);
1177 return bus_log_create_error(r
);
1179 polkit_agent_open_if_enabled();
1181 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1183 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1187 r
= sd_bus_message_read(reply
, "o", &object
);
1189 return bus_log_parse_error(r
);
1191 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1195 log_info("Running timer as unit: %s", timer
);
1197 log_info("Will run service as unit: %s", service
);
1202 int main(int argc
, char* argv
[]) {
1203 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1204 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1207 log_parse_environment();
1210 r
= parse_argv(argc
, argv
);
1214 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1215 /* Patch in an absolute path */
1217 r
= find_binary(argv
[optind
], &command
);
1219 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1223 argv
[optind
] = command
;
1226 if (!arg_description
) {
1227 description
= strv_join(argv
+ optind
, " ");
1233 if (arg_unit
&& isempty(description
)) {
1234 r
= free_and_strdup(&description
, arg_unit
);
1239 arg_description
= description
;
1242 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1244 log_error_errno(r
, "Failed to create bus connection: %m");
1249 r
= start_transient_scope(bus
, argv
+ optind
);
1250 else if (with_timer())
1251 r
= start_transient_timer(bus
, argv
+ optind
);
1253 r
= start_transient_service(bus
, argv
+ optind
);
1256 strv_free(arg_environment
);
1257 strv_free(arg_property
);
1258 strv_free(arg_timer_property
);
1260 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;