1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "alloc-util.h"
29 #include "bus-error.h"
31 #include "calendarspec.h"
33 #include "event-util.h"
35 #include "formats-util.h"
36 #include "parse-util.h"
37 #include "path-util.h"
39 #include "signal-util.h"
40 #include "spawn-polkit-agent.h"
42 #include "terminal-util.h"
43 #include "unit-name.h"
44 #include "user-util.h"
46 static bool arg_ask_password
= true;
47 static bool arg_scope
= false;
48 static bool arg_remain_after_exit
= false;
49 static bool arg_no_block
= 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 or timer\n"
89 "unit. If timer option is specified and unit is exist which is\n"
90 "specified with --unit option then command can be omitted.\n\n"
91 " -h --help Show this help\n"
92 " --version Show package version\n"
93 " --no-ask-password Do not prompt for password\n"
94 " --user Run as user unit\n"
95 " -H --host=[USER@]HOST Operate on remote host\n"
96 " -M --machine=CONTAINER Operate on local container\n"
97 " --scope Run this as scope rather than service\n"
98 " --unit=UNIT Run under the specified unit name\n"
99 " -p --property=NAME=VALUE Set unit property\n"
100 " --description=TEXT Description for unit\n"
101 " --slice=SLICE Run in the specified slice\n"
102 " --no-block Do not wait until operation finished\n"
103 " -r --remain-after-exit Leave service around until explicitly stopped\n"
104 " --send-sighup Send SIGHUP when terminating\n"
105 " --service-type=TYPE Service type\n"
106 " --uid=USER Run as system user\n"
107 " --gid=GROUP Run as system group\n"
108 " --nice=NICE Nice level\n"
109 " --setenv=NAME=VALUE Set environment\n"
110 " -t --pty Run service on pseudo tty\n"
111 " -q --quiet Suppress information messages during runtime\n\n"
113 " --on-active=SECONDS Run after SECONDS delay\n"
114 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
115 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
116 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
117 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
118 " --on-calendar=SPEC Realtime timer\n"
119 " --timer-property=NAME=VALUE Set timer unit property\n",
120 program_invocation_short_name
);
123 static bool with_timer(void) {
124 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
127 static int parse_argv(int argc
, char *argv
[]) {
149 ARG_ON_UNIT_INACTIVE
,
155 static const struct option options
[] = {
156 { "help", no_argument
, NULL
, 'h' },
157 { "version", no_argument
, NULL
, ARG_VERSION
},
158 { "user", no_argument
, NULL
, ARG_USER
},
159 { "system", no_argument
, NULL
, ARG_SYSTEM
},
160 { "scope", no_argument
, NULL
, ARG_SCOPE
},
161 { "unit", required_argument
, NULL
, ARG_UNIT
},
162 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
163 { "slice", required_argument
, NULL
, ARG_SLICE
},
164 { "remain-after-exit", no_argument
, NULL
, 'r' },
165 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
166 { "host", required_argument
, NULL
, 'H' },
167 { "machine", required_argument
, NULL
, 'M' },
168 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
169 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
170 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
171 { "nice", required_argument
, NULL
, ARG_NICE
},
172 { "setenv", required_argument
, NULL
, ARG_SETENV
},
173 { "property", required_argument
, NULL
, 'p' },
174 { "tty", 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:p:tq", options
, NULL
)) >= 0)
201 case ARG_NO_ASK_PASSWORD
:
202 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
= safe_atoi(optarg
, &arg_nice
);
264 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
265 log_error("Failed to parse nice value");
273 if (strv_extend(&arg_environment
, optarg
) < 0)
279 if (strv_extend(&arg_property
, optarg
) < 0)
294 r
= parse_sec(optarg
, &arg_on_active
);
296 log_error("Failed to parse timer value: %s", optarg
);
304 r
= parse_sec(optarg
, &arg_on_boot
);
306 log_error("Failed to parse timer value: %s", optarg
);
314 r
= parse_sec(optarg
, &arg_on_startup
);
316 log_error("Failed to parse timer value: %s", optarg
);
322 case ARG_ON_UNIT_ACTIVE
:
324 r
= parse_sec(optarg
, &arg_on_unit_active
);
326 log_error("Failed to parse timer value: %s", optarg
);
332 case ARG_ON_UNIT_INACTIVE
:
334 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
336 log_error("Failed to parse timer value: %s", optarg
);
342 case ARG_ON_CALENDAR
: {
343 CalendarSpec
*spec
= NULL
;
345 r
= calendar_spec_from_string(optarg
, &spec
);
347 log_error("Invalid calendar spec: %s", optarg
);
351 calendar_spec_free(spec
);
352 arg_on_calendar
= optarg
;
356 case ARG_TIMER_PROPERTY
:
358 if (strv_extend(&arg_timer_property
, optarg
) < 0)
371 assert_not_reached("Unhandled option");
374 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
375 log_error("Command line to execute required.");
379 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
380 log_error("Execution in user context is not supported on non-local systems.");
384 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
385 log_error("Scope execution is not supported on non-local systems.");
389 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
390 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
394 if (arg_pty
&& (with_timer() || arg_scope
)) {
395 log_error("--pty is not compatible in timer or --scope mode.");
399 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
400 log_error("--pty is only supported when connecting to the local system or containers.");
404 if (arg_scope
&& with_timer()) {
405 log_error("Timer options are not supported in --scope mode.");
409 if (arg_timer_property
&& !with_timer()) {
410 log_error("--timer-property= has no effect without any other timer options.");
417 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
421 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
425 STRV_FOREACH(i
, properties
) {
426 r
= sd_bus_message_open_container(m
, 'r', "sv");
430 r
= bus_append_unit_property_assignment(m
, *i
);
434 r
= sd_bus_message_close_container(m
);
442 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
446 if (!isempty(arg_slice
)) {
447 _cleanup_free_
char *slice
;
449 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
453 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
461 static int transient_kill_set_properties(sd_bus_message
*m
) {
465 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
470 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
475 r
= transient_unit_set_properties(m
, arg_property
);
479 r
= transient_kill_set_properties(m
);
483 r
= transient_cgroup_set_properties(m
);
487 if (arg_remain_after_exit
) {
488 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
493 if (arg_service_type
) {
494 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
500 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
505 if (arg_exec_group
) {
506 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
512 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
520 r
= sd_bus_message_append(m
,
522 "StandardInput", "s", "tty",
523 "StandardOutput", "s", "tty",
524 "StandardError", "s", "tty",
525 "TTYPath", "s", pty_path
);
533 n
= strjoina("TERM=", e
);
534 r
= sd_bus_message_append(m
,
536 "Environment", "as", 1, n
);
542 if (!strv_isempty(arg_environment
)) {
543 r
= sd_bus_message_open_container(m
, 'r', "sv");
547 r
= sd_bus_message_append(m
, "s", "Environment");
551 r
= sd_bus_message_open_container(m
, 'v', "as");
555 r
= sd_bus_message_append_strv(m
, arg_environment
);
559 r
= sd_bus_message_close_container(m
);
563 r
= sd_bus_message_close_container(m
);
570 r
= sd_bus_message_open_container(m
, 'r', "sv");
574 r
= sd_bus_message_append(m
, "s", "ExecStart");
578 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
582 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
586 r
= sd_bus_message_open_container(m
, 'r', "sasb");
590 r
= sd_bus_message_append(m
, "s", argv
[0]);
594 r
= sd_bus_message_append_strv(m
, argv
);
598 r
= sd_bus_message_append(m
, "b", false);
602 r
= sd_bus_message_close_container(m
);
606 r
= sd_bus_message_close_container(m
);
610 r
= sd_bus_message_close_container(m
);
614 r
= sd_bus_message_close_container(m
);
622 static int transient_scope_set_properties(sd_bus_message
*m
) {
627 r
= transient_unit_set_properties(m
, arg_property
);
631 r
= transient_kill_set_properties(m
);
635 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
642 static int transient_timer_set_properties(sd_bus_message
*m
) {
647 r
= transient_unit_set_properties(m
, arg_timer_property
);
651 /* Automatically clean up our transient timers */
652 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterElapse", "b", false);
657 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
663 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
668 if (arg_on_startup
) {
669 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
674 if (arg_on_unit_active
) {
675 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
680 if (arg_on_unit_inactive
) {
681 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
686 if (arg_on_calendar
) {
687 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
695 static int make_unit_name(sd_bus
*bus
, UnitType t
, char **ret
) {
696 const char *unique
, *id
;
702 assert(t
< _UNIT_TYPE_MAX
);
704 r
= sd_bus_get_unique_name(bus
, &unique
);
708 /* We couldn't get the unique name, which is a pretty
709 * common case if we are connected to systemd
710 * directly. In that case, just pick a random uuid as
713 r
= sd_id128_randomize(&rnd
);
715 return log_error_errno(r
, "Failed to generate random run unit name: %m");
717 if (asprintf(ret
, "run-r" SD_ID128_FORMAT_STR
".%s", SD_ID128_FORMAT_VAL(rnd
), unit_type_to_string(t
)) < 0)
723 /* We managed to get the unique name, then let's use that to
724 * name our transient units. */
726 id
= startswith(unique
, ":1.");
728 log_error("Unique name %s has unexpected format.", unique
);
732 p
= strjoin("run-u", id
, ".", unit_type_to_string(t
), NULL
);
740 static int start_transient_service(
744 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
745 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
746 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
747 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
748 _cleanup_close_
int master
= -1;
756 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
757 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
759 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
761 r
= ptsname_malloc(master
, &pty_path
);
763 return log_error_errno(r
, "Failed to determine tty name: %m");
765 if (unlockpt(master
) < 0)
766 return log_error_errno(errno
, "Failed to unlock tty: %m");
768 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
769 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
772 r
= sd_bus_default_system(&system_bus
);
774 return log_error_errno(r
, "Failed to connect to system bus: %m");
776 r
= sd_bus_call_method(system_bus
,
777 "org.freedesktop.machine1",
778 "/org/freedesktop/machine1",
779 "org.freedesktop.machine1.Manager",
785 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
789 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
791 return bus_log_parse_error(r
);
793 reply
= sd_bus_message_unref(reply
);
795 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
797 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
799 pty_path
= strdup(s
);
803 assert_not_reached("Can't allocate tty via ssh");
807 r
= bus_wait_for_jobs_new(bus
, &w
);
809 return log_error_errno(r
, "Could not watch jobs: %m");
813 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
815 return log_error_errno(r
, "Failed to mangle unit name: %m");
817 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
822 r
= sd_bus_message_new_method_call(
825 "org.freedesktop.systemd1",
826 "/org/freedesktop/systemd1",
827 "org.freedesktop.systemd1.Manager",
828 "StartTransientUnit");
830 return bus_log_create_error(r
);
832 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
834 return bus_log_create_error(r
);
837 r
= sd_bus_message_append(m
, "ss", service
, "fail");
839 return bus_log_create_error(r
);
842 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
844 return bus_log_create_error(r
);
846 r
= transient_service_set_properties(m
, argv
, pty_path
);
848 return bus_log_create_error(r
);
850 r
= sd_bus_message_close_container(m
);
852 return bus_log_create_error(r
);
854 /* Auxiliary units */
855 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
857 return bus_log_create_error(r
);
859 polkit_agent_open_if_enabled();
861 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
863 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
868 r
= sd_bus_message_read(reply
, "o", &object
);
870 return bus_log_parse_error(r
);
872 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
878 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
879 _cleanup_event_unref_ sd_event
*event
= NULL
;
882 r
= sd_event_default(&event
);
884 return log_error_errno(r
, "Failed to get event loop: %m");
886 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
888 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
889 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
892 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
894 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
896 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
898 r
= sd_event_loop(event
);
900 return log_error_errno(r
, "Failed to run event loop: %m");
902 pty_forward_get_last_char(forward
, &last_char
);
904 forward
= pty_forward_free(forward
);
906 if (!arg_quiet
&& last_char
!= '\n')
909 } else if (!arg_quiet
)
910 log_info("Running as unit %s.", service
);
915 static int start_transient_scope(
919 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
920 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
921 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
922 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
923 _cleanup_free_
char *scope
= NULL
;
924 const char *object
= NULL
;
930 r
= bus_wait_for_jobs_new(bus
, &w
);
935 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
937 return log_error_errno(r
, "Failed to mangle scope name: %m");
939 r
= make_unit_name(bus
, UNIT_SCOPE
, &scope
);
944 r
= sd_bus_message_new_method_call(
947 "org.freedesktop.systemd1",
948 "/org/freedesktop/systemd1",
949 "org.freedesktop.systemd1.Manager",
950 "StartTransientUnit");
952 return bus_log_create_error(r
);
954 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
956 return bus_log_create_error(r
);
959 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
961 return bus_log_create_error(r
);
964 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
966 return bus_log_create_error(r
);
968 r
= transient_scope_set_properties(m
);
970 return bus_log_create_error(r
);
972 r
= sd_bus_message_close_container(m
);
974 return bus_log_create_error(r
);
976 /* Auxiliary units */
977 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
979 return bus_log_create_error(r
);
981 polkit_agent_open_if_enabled();
983 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
985 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
990 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
991 return log_error_errno(errno
, "Failed to set nice level: %m");
994 if (arg_exec_group
) {
997 r
= get_group_creds(&arg_exec_group
, &gid
);
999 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
1001 if (setresgid(gid
, gid
, gid
) < 0)
1002 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1005 if (arg_exec_user
) {
1006 const char *home
, *shell
;
1010 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
1012 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
1014 r
= strv_extendf(&user_env
, "HOME=%s", home
);
1018 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
1022 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
1026 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
1030 if (!arg_exec_group
) {
1031 if (setresgid(gid
, gid
, gid
) < 0)
1032 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
1035 if (setresuid(uid
, uid
, uid
) < 0)
1036 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
1039 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
1043 r
= sd_bus_message_read(reply
, "o", &object
);
1045 return bus_log_parse_error(r
);
1047 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1052 log_info("Running scope as unit %s.", scope
);
1054 execvpe(argv
[0], argv
, env
);
1056 return log_error_errno(errno
, "Failed to execute: %m");
1059 static int start_transient_timer(
1063 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1064 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1065 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1066 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1067 const char *object
= NULL
;
1073 r
= bus_wait_for_jobs_new(bus
, &w
);
1078 switch (unit_name_to_type(arg_unit
)) {
1081 service
= strdup(arg_unit
);
1085 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1087 return log_error_errno(r
, "Failed to change unit suffix: %m");
1091 timer
= strdup(arg_unit
);
1095 r
= unit_name_change_suffix(timer
, ".service", &service
);
1097 return log_error_errno(r
, "Failed to change unit suffix: %m");
1101 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1103 return log_error_errno(r
, "Failed to mangle unit name: %m");
1105 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1107 return log_error_errno(r
, "Failed to mangle unit name: %m");
1112 r
= make_unit_name(bus
, UNIT_SERVICE
, &service
);
1116 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1118 return log_error_errno(r
, "Failed to change unit suffix: %m");
1121 r
= sd_bus_message_new_method_call(
1124 "org.freedesktop.systemd1",
1125 "/org/freedesktop/systemd1",
1126 "org.freedesktop.systemd1.Manager",
1127 "StartTransientUnit");
1129 return bus_log_create_error(r
);
1131 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1133 return bus_log_create_error(r
);
1136 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1138 return bus_log_create_error(r
);
1141 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1143 return bus_log_create_error(r
);
1145 r
= transient_timer_set_properties(m
);
1147 return bus_log_create_error(r
);
1149 r
= sd_bus_message_close_container(m
);
1151 return bus_log_create_error(r
);
1153 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1155 return bus_log_create_error(r
);
1158 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1160 return bus_log_create_error(r
);
1162 r
= sd_bus_message_append(m
, "s", service
);
1164 return bus_log_create_error(r
);
1166 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1168 return bus_log_create_error(r
);
1170 r
= transient_service_set_properties(m
, argv
, NULL
);
1172 return bus_log_create_error(r
);
1174 r
= sd_bus_message_close_container(m
);
1176 return bus_log_create_error(r
);
1178 r
= sd_bus_message_close_container(m
);
1180 return bus_log_create_error(r
);
1183 r
= sd_bus_message_close_container(m
);
1185 return bus_log_create_error(r
);
1187 polkit_agent_open_if_enabled();
1189 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1191 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1195 r
= sd_bus_message_read(reply
, "o", &object
);
1197 return bus_log_parse_error(r
);
1199 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1203 log_info("Running timer as unit %s.", timer
);
1205 log_info("Will run service as unit %s.", service
);
1210 int main(int argc
, char* argv
[]) {
1211 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1212 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1215 log_parse_environment();
1218 r
= parse_argv(argc
, argv
);
1222 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1223 /* Patch in an absolute path */
1225 r
= find_binary(argv
[optind
], &command
);
1227 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1231 argv
[optind
] = command
;
1234 if (!arg_description
) {
1235 description
= strv_join(argv
+ optind
, " ");
1241 if (arg_unit
&& isempty(description
)) {
1242 r
= free_and_strdup(&description
, arg_unit
);
1247 arg_description
= description
;
1250 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1252 log_error_errno(r
, "Failed to create bus connection: %m");
1257 r
= start_transient_scope(bus
, argv
+ optind
);
1258 else if (with_timer())
1259 r
= start_transient_timer(bus
, argv
+ optind
);
1261 r
= start_transient_service(bus
, argv
+ optind
);
1264 strv_free(arg_environment
);
1265 strv_free(arg_property
);
1266 strv_free(arg_timer_property
);
1268 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;