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 "bus-error.h"
30 #include "calendarspec.h"
32 #include "event-util.h"
34 #include "formats-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 timer option is specified and unit is exist which is\n"
88 "specified with --unit option then 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 " --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
[]) {
147 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 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
168 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
169 { "nice", required_argument
, NULL
, ARG_NICE
},
170 { "setenv", required_argument
, NULL
, ARG_SETENV
},
171 { "property", required_argument
, NULL
, 'p' },
172 { "tty", no_argument
, NULL
, 't' },
173 { "quiet", no_argument
, NULL
, 'q' },
174 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
175 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
176 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
177 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
178 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
179 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
180 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
181 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
182 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
191 while ((c
= getopt_long(argc
, argv
, "+hrH:M:p:tq", options
, NULL
)) >= 0)
199 case ARG_NO_ASK_PASSWORD
:
200 arg_ask_password
= false;
222 case ARG_DESCRIPTION
:
223 arg_description
= optarg
;
230 case ARG_SEND_SIGHUP
:
231 arg_send_sighup
= true;
235 arg_remain_after_exit
= true;
239 arg_transport
= BUS_TRANSPORT_REMOTE
;
244 arg_transport
= BUS_TRANSPORT_MACHINE
;
248 case ARG_SERVICE_TYPE
:
249 arg_service_type
= optarg
;
253 arg_exec_user
= optarg
;
257 arg_exec_group
= optarg
;
261 r
= safe_atoi(optarg
, &arg_nice
);
262 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
263 log_error("Failed to parse nice value");
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)
369 assert_not_reached("Unhandled option");
372 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
373 log_error("Command line to execute required.");
377 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
378 log_error("Execution in user context is not supported on non-local systems.");
382 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
383 log_error("Scope execution is not supported on non-local systems.");
387 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
388 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
392 if (arg_pty
&& (with_timer() || arg_scope
)) {
393 log_error("--pty is not compatible in timer or --scope mode.");
397 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
398 log_error("--pty is only supported when connecting to the local system or containers.");
402 if (arg_scope
&& with_timer()) {
403 log_error("Timer options are not supported in --scope mode.");
407 if (arg_timer_property
&& !with_timer()) {
408 log_error("--timer-property= has no effect without any other timer options.");
415 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
419 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
423 STRV_FOREACH(i
, properties
) {
424 r
= sd_bus_message_open_container(m
, 'r', "sv");
428 r
= bus_append_unit_property_assignment(m
, *i
);
432 r
= sd_bus_message_close_container(m
);
440 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
444 if (!isempty(arg_slice
)) {
445 _cleanup_free_
char *slice
;
447 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
451 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
459 static int transient_kill_set_properties(sd_bus_message
*m
) {
463 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
468 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
473 r
= transient_unit_set_properties(m
, arg_property
);
477 r
= transient_kill_set_properties(m
);
481 r
= transient_cgroup_set_properties(m
);
485 if (arg_remain_after_exit
) {
486 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
491 if (arg_service_type
) {
492 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
498 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
503 if (arg_exec_group
) {
504 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
510 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
518 r
= sd_bus_message_append(m
,
520 "StandardInput", "s", "tty",
521 "StandardOutput", "s", "tty",
522 "StandardError", "s", "tty",
523 "TTYPath", "s", pty_path
);
531 n
= strjoina("TERM=", e
);
532 r
= sd_bus_message_append(m
,
534 "Environment", "as", 1, n
);
540 if (!strv_isempty(arg_environment
)) {
541 r
= sd_bus_message_open_container(m
, 'r', "sv");
545 r
= sd_bus_message_append(m
, "s", "Environment");
549 r
= sd_bus_message_open_container(m
, 'v', "as");
553 r
= sd_bus_message_append_strv(m
, arg_environment
);
557 r
= sd_bus_message_close_container(m
);
561 r
= sd_bus_message_close_container(m
);
568 r
= sd_bus_message_open_container(m
, 'r', "sv");
572 r
= sd_bus_message_append(m
, "s", "ExecStart");
576 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
580 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
584 r
= sd_bus_message_open_container(m
, 'r', "sasb");
588 r
= sd_bus_message_append(m
, "s", argv
[0]);
592 r
= sd_bus_message_append_strv(m
, argv
);
596 r
= sd_bus_message_append(m
, "b", false);
600 r
= sd_bus_message_close_container(m
);
604 r
= sd_bus_message_close_container(m
);
608 r
= sd_bus_message_close_container(m
);
612 r
= sd_bus_message_close_container(m
);
620 static int transient_scope_set_properties(sd_bus_message
*m
) {
625 r
= transient_unit_set_properties(m
, arg_property
);
629 r
= transient_kill_set_properties(m
);
633 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
640 static int transient_timer_set_properties(sd_bus_message
*m
) {
645 r
= transient_unit_set_properties(m
, arg_timer_property
);
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 start_transient_service(
692 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
693 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
694 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
695 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
696 _cleanup_close_
int master
= -1;
704 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
705 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
707 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
709 r
= ptsname_malloc(master
, &pty_path
);
711 return log_error_errno(r
, "Failed to determine tty name: %m");
713 if (unlockpt(master
) < 0)
714 return log_error_errno(errno
, "Failed to unlock tty: %m");
716 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
717 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
720 r
= sd_bus_default_system(&system_bus
);
722 return log_error_errno(r
, "Failed to connect to system bus: %m");
724 r
= sd_bus_call_method(system_bus
,
725 "org.freedesktop.machine1",
726 "/org/freedesktop/machine1",
727 "org.freedesktop.machine1.Manager",
733 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
737 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
739 return bus_log_parse_error(r
);
741 reply
= sd_bus_message_unref(reply
);
743 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
745 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
747 pty_path
= strdup(s
);
751 assert_not_reached("Can't allocate tty via ssh");
755 r
= bus_wait_for_jobs_new(bus
, &w
);
757 return log_error_errno(r
, "Could not watch jobs: %m");
761 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
763 return log_error_errno(r
, "Failed to mangle unit name: %m");
764 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
767 r
= sd_bus_message_new_method_call(
770 "org.freedesktop.systemd1",
771 "/org/freedesktop/systemd1",
772 "org.freedesktop.systemd1.Manager",
773 "StartTransientUnit");
775 return bus_log_create_error(r
);
777 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
779 return bus_log_create_error(r
);
782 r
= sd_bus_message_append(m
, "ss", service
, "fail");
784 return bus_log_create_error(r
);
787 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
789 return bus_log_create_error(r
);
791 r
= transient_service_set_properties(m
, argv
, pty_path
);
793 return bus_log_create_error(r
);
795 r
= sd_bus_message_close_container(m
);
797 return bus_log_create_error(r
);
799 /* Auxiliary units */
800 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
802 return bus_log_create_error(r
);
804 polkit_agent_open_if_enabled();
806 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
808 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
813 r
= sd_bus_message_read(reply
, "o", &object
);
815 return bus_log_parse_error(r
);
817 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
823 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
824 _cleanup_event_unref_ sd_event
*event
= NULL
;
827 r
= sd_event_default(&event
);
829 return log_error_errno(r
, "Failed to get event loop: %m");
831 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
833 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
834 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
837 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
839 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
841 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
843 r
= sd_event_loop(event
);
845 return log_error_errno(r
, "Failed to run event loop: %m");
847 pty_forward_get_last_char(forward
, &last_char
);
849 forward
= pty_forward_free(forward
);
851 if (!arg_quiet
&& last_char
!= '\n')
854 } else if (!arg_quiet
)
855 log_info("Running as unit %s.", service
);
860 static int start_transient_scope(
864 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
865 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
866 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
867 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
868 _cleanup_free_
char *scope
= NULL
;
869 const char *object
= NULL
;
875 r
= bus_wait_for_jobs_new(bus
, &w
);
880 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
882 return log_error_errno(r
, "Failed to mangle scope name: %m");
883 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
886 r
= sd_bus_message_new_method_call(
889 "org.freedesktop.systemd1",
890 "/org/freedesktop/systemd1",
891 "org.freedesktop.systemd1.Manager",
892 "StartTransientUnit");
894 return bus_log_create_error(r
);
896 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
898 return bus_log_create_error(r
);
901 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
903 return bus_log_create_error(r
);
906 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
908 return bus_log_create_error(r
);
910 r
= transient_scope_set_properties(m
);
912 return bus_log_create_error(r
);
914 r
= sd_bus_message_close_container(m
);
916 return bus_log_create_error(r
);
918 /* Auxiliary units */
919 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
921 return bus_log_create_error(r
);
923 polkit_agent_open_if_enabled();
925 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
927 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
932 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
933 return log_error_errno(errno
, "Failed to set nice level: %m");
936 if (arg_exec_group
) {
939 r
= get_group_creds(&arg_exec_group
, &gid
);
941 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
943 if (setresgid(gid
, gid
, gid
) < 0)
944 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
948 const char *home
, *shell
;
952 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
954 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
956 r
= strv_extendf(&user_env
, "HOME=%s", home
);
960 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
964 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
968 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
972 if (!arg_exec_group
) {
973 if (setresgid(gid
, gid
, gid
) < 0)
974 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
977 if (setresuid(uid
, uid
, uid
) < 0)
978 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
981 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
985 r
= sd_bus_message_read(reply
, "o", &object
);
987 return bus_log_parse_error(r
);
989 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
994 log_info("Running scope as unit %s.", scope
);
996 execvpe(argv
[0], argv
, env
);
998 return log_error_errno(errno
, "Failed to execute: %m");
1001 static int start_transient_timer(
1005 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1006 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1007 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1008 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1009 const char *object
= NULL
;
1015 r
= bus_wait_for_jobs_new(bus
, &w
);
1020 switch (unit_name_to_type(arg_unit
)) {
1023 service
= strdup(arg_unit
);
1027 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1029 return log_error_errno(r
, "Failed to change unit suffix: %m");
1033 timer
= strdup(arg_unit
);
1037 r
= unit_name_change_suffix(timer
, ".service", &service
);
1039 return log_error_errno(r
, "Failed to change unit suffix: %m");
1043 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1045 return log_error_errno(r
, "Failed to mangle unit name: %m");
1047 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1049 return log_error_errno(r
, "Failed to mangle unit name: %m");
1053 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1054 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1057 r
= sd_bus_message_new_method_call(
1060 "org.freedesktop.systemd1",
1061 "/org/freedesktop/systemd1",
1062 "org.freedesktop.systemd1.Manager",
1063 "StartTransientUnit");
1065 return bus_log_create_error(r
);
1067 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1069 return bus_log_create_error(r
);
1072 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1074 return bus_log_create_error(r
);
1077 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1079 return bus_log_create_error(r
);
1081 r
= transient_timer_set_properties(m
);
1083 return bus_log_create_error(r
);
1085 r
= sd_bus_message_close_container(m
);
1087 return bus_log_create_error(r
);
1089 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1091 return bus_log_create_error(r
);
1094 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1096 return bus_log_create_error(r
);
1098 r
= sd_bus_message_append(m
, "s", service
);
1100 return bus_log_create_error(r
);
1102 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1104 return bus_log_create_error(r
);
1106 r
= transient_service_set_properties(m
, argv
, NULL
);
1108 return bus_log_create_error(r
);
1110 r
= sd_bus_message_close_container(m
);
1112 return bus_log_create_error(r
);
1114 r
= sd_bus_message_close_container(m
);
1116 return bus_log_create_error(r
);
1119 r
= sd_bus_message_close_container(m
);
1121 return bus_log_create_error(r
);
1123 polkit_agent_open_if_enabled();
1125 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1127 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1131 r
= sd_bus_message_read(reply
, "o", &object
);
1133 return bus_log_parse_error(r
);
1135 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1139 log_info("Running timer as unit %s.", timer
);
1141 log_info("Will run service as unit %s.", service
);
1146 int main(int argc
, char* argv
[]) {
1147 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1148 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1151 log_parse_environment();
1154 r
= parse_argv(argc
, argv
);
1158 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1159 /* Patch in an absolute path */
1161 r
= find_binary(argv
[optind
], &command
);
1163 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1167 argv
[optind
] = command
;
1170 if (!arg_description
) {
1171 description
= strv_join(argv
+ optind
, " ");
1177 if (arg_unit
&& isempty(description
)) {
1178 r
= free_and_strdup(&description
, arg_unit
);
1183 arg_description
= description
;
1186 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1188 log_error_errno(r
, "Failed to create bus connection: %m");
1193 r
= start_transient_scope(bus
, argv
+ optind
);
1194 else if (with_timer())
1195 r
= start_transient_timer(bus
, argv
+ optind
);
1197 r
= start_transient_service(bus
, argv
+ optind
);
1200 strv_free(arg_environment
);
1201 strv_free(arg_property
);
1202 strv_free(arg_timer_property
);
1204 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;