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"
43 #include "parse-util.h"
45 static bool arg_ask_password
= true;
46 static bool arg_scope
= false;
47 static bool arg_remain_after_exit
= false;
48 static bool arg_no_block
= false;
49 static const char *arg_unit
= NULL
;
50 static const char *arg_description
= NULL
;
51 static const char *arg_slice
= NULL
;
52 static bool arg_send_sighup
= false;
53 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
54 static const char *arg_host
= NULL
;
55 static bool arg_user
= false;
56 static const char *arg_service_type
= NULL
;
57 static const char *arg_exec_user
= NULL
;
58 static const char *arg_exec_group
= NULL
;
59 static int arg_nice
= 0;
60 static bool arg_nice_set
= false;
61 static char **arg_environment
= NULL
;
62 static char **arg_property
= NULL
;
63 static bool arg_pty
= false;
64 static usec_t arg_on_active
= 0;
65 static usec_t arg_on_boot
= 0;
66 static usec_t arg_on_startup
= 0;
67 static usec_t arg_on_unit_active
= 0;
68 static usec_t arg_on_unit_inactive
= 0;
69 static const char *arg_on_calendar
= NULL
;
70 static char **arg_timer_property
= NULL
;
71 static bool arg_quiet
= false;
73 static void polkit_agent_open_if_enabled(void) {
75 /* Open the polkit agent as a child process if necessary */
76 if (!arg_ask_password
)
79 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
85 static void help(void) {
86 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
87 "Run the specified command in a transient scope or service or timer\n"
88 "unit. If timer option is specified and unit is exist which is\n"
89 "specified with --unit option then command can be omitted.\n\n"
90 " -h --help Show this help\n"
91 " --version Show package version\n"
92 " --no-ask-password Do not prompt for password\n"
93 " --user Run as user unit\n"
94 " -H --host=[USER@]HOST Operate on remote host\n"
95 " -M --machine=CONTAINER Operate on local container\n"
96 " --scope Run this as scope rather than service\n"
97 " --unit=UNIT Run under the specified unit name\n"
98 " -p --property=NAME=VALUE Set unit property\n"
99 " --description=TEXT Description for unit\n"
100 " --slice=SLICE Run in the specified slice\n"
101 " --no-block Do not wait until operation finished\n"
102 " -r --remain-after-exit Leave service around until explicitly stopped\n"
103 " --send-sighup Send SIGHUP when terminating\n"
104 " --service-type=TYPE Service type\n"
105 " --uid=USER Run as system user\n"
106 " --gid=GROUP Run as system group\n"
107 " --nice=NICE Nice level\n"
108 " --setenv=NAME=VALUE Set environment\n"
109 " -t --pty Run service on pseudo tty\n"
110 " -q --quiet Suppress information messages during runtime\n\n"
112 " --on-active=SECONDS Run after SECONDS delay\n"
113 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
114 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
115 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
116 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
117 " --on-calendar=SPEC Realtime timer\n"
118 " --timer-property=NAME=VALUE Set timer unit property\n",
119 program_invocation_short_name
);
122 static bool with_timer(void) {
123 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
126 static int parse_argv(int argc
, char *argv
[]) {
148 ARG_ON_UNIT_INACTIVE
,
154 static const struct option options
[] = {
155 { "help", no_argument
, NULL
, 'h' },
156 { "version", no_argument
, NULL
, ARG_VERSION
},
157 { "user", no_argument
, NULL
, ARG_USER
},
158 { "system", no_argument
, NULL
, ARG_SYSTEM
},
159 { "scope", no_argument
, NULL
, ARG_SCOPE
},
160 { "unit", required_argument
, NULL
, ARG_UNIT
},
161 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
162 { "slice", required_argument
, NULL
, ARG_SLICE
},
163 { "remain-after-exit", no_argument
, NULL
, 'r' },
164 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
165 { "host", required_argument
, NULL
, 'H' },
166 { "machine", required_argument
, NULL
, 'M' },
167 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
168 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
169 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
170 { "nice", required_argument
, NULL
, ARG_NICE
},
171 { "setenv", required_argument
, NULL
, ARG_SETENV
},
172 { "property", required_argument
, NULL
, 'p' },
173 { "tty", no_argument
, NULL
, 't' },
174 { "quiet", no_argument
, NULL
, 'q' },
175 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
176 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
177 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
178 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
179 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
180 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
181 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
182 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
183 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
192 while ((c
= getopt_long(argc
, argv
, "+hrH:M:p:tq", options
, NULL
)) >= 0)
200 case ARG_NO_ASK_PASSWORD
:
201 arg_ask_password
= false;
223 case ARG_DESCRIPTION
:
224 arg_description
= optarg
;
231 case ARG_SEND_SIGHUP
:
232 arg_send_sighup
= true;
236 arg_remain_after_exit
= true;
240 arg_transport
= BUS_TRANSPORT_REMOTE
;
245 arg_transport
= BUS_TRANSPORT_MACHINE
;
249 case ARG_SERVICE_TYPE
:
250 arg_service_type
= optarg
;
254 arg_exec_user
= optarg
;
258 arg_exec_group
= optarg
;
262 r
= safe_atoi(optarg
, &arg_nice
);
263 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
264 log_error("Failed to parse nice value");
272 if (strv_extend(&arg_environment
, optarg
) < 0)
278 if (strv_extend(&arg_property
, optarg
) < 0)
293 r
= parse_sec(optarg
, &arg_on_active
);
295 log_error("Failed to parse timer value: %s", optarg
);
303 r
= parse_sec(optarg
, &arg_on_boot
);
305 log_error("Failed to parse timer value: %s", optarg
);
313 r
= parse_sec(optarg
, &arg_on_startup
);
315 log_error("Failed to parse timer value: %s", optarg
);
321 case ARG_ON_UNIT_ACTIVE
:
323 r
= parse_sec(optarg
, &arg_on_unit_active
);
325 log_error("Failed to parse timer value: %s", optarg
);
331 case ARG_ON_UNIT_INACTIVE
:
333 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
335 log_error("Failed to parse timer value: %s", optarg
);
341 case ARG_ON_CALENDAR
: {
342 CalendarSpec
*spec
= NULL
;
344 r
= calendar_spec_from_string(optarg
, &spec
);
346 log_error("Invalid calendar spec: %s", optarg
);
350 calendar_spec_free(spec
);
351 arg_on_calendar
= optarg
;
355 case ARG_TIMER_PROPERTY
:
357 if (strv_extend(&arg_timer_property
, optarg
) < 0)
370 assert_not_reached("Unhandled option");
373 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
374 log_error("Command line to execute required.");
378 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
379 log_error("Execution in user context is not supported on non-local systems.");
383 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
384 log_error("Scope execution is not supported on non-local systems.");
388 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
389 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
393 if (arg_pty
&& (with_timer() || arg_scope
)) {
394 log_error("--pty is not compatible in timer or --scope mode.");
398 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
399 log_error("--pty is only supported when connecting to the local system or containers.");
403 if (arg_scope
&& with_timer()) {
404 log_error("Timer options are not supported in --scope mode.");
408 if (arg_timer_property
&& !with_timer()) {
409 log_error("--timer-property= has no effect without any other timer options.");
416 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
420 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
424 STRV_FOREACH(i
, properties
) {
425 r
= sd_bus_message_open_container(m
, 'r', "sv");
429 r
= bus_append_unit_property_assignment(m
, *i
);
433 r
= sd_bus_message_close_container(m
);
441 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
445 if (!isempty(arg_slice
)) {
446 _cleanup_free_
char *slice
;
448 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
452 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
460 static int transient_kill_set_properties(sd_bus_message
*m
) {
464 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
469 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
474 r
= transient_unit_set_properties(m
, arg_property
);
478 r
= transient_kill_set_properties(m
);
482 r
= transient_cgroup_set_properties(m
);
486 if (arg_remain_after_exit
) {
487 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
492 if (arg_service_type
) {
493 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
499 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
504 if (arg_exec_group
) {
505 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
511 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
519 r
= sd_bus_message_append(m
,
521 "StandardInput", "s", "tty",
522 "StandardOutput", "s", "tty",
523 "StandardError", "s", "tty",
524 "TTYPath", "s", pty_path
);
532 n
= strjoina("TERM=", e
);
533 r
= sd_bus_message_append(m
,
535 "Environment", "as", 1, n
);
541 if (!strv_isempty(arg_environment
)) {
542 r
= sd_bus_message_open_container(m
, 'r', "sv");
546 r
= sd_bus_message_append(m
, "s", "Environment");
550 r
= sd_bus_message_open_container(m
, 'v', "as");
554 r
= sd_bus_message_append_strv(m
, arg_environment
);
558 r
= sd_bus_message_close_container(m
);
562 r
= sd_bus_message_close_container(m
);
569 r
= sd_bus_message_open_container(m
, 'r', "sv");
573 r
= sd_bus_message_append(m
, "s", "ExecStart");
577 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
581 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
585 r
= sd_bus_message_open_container(m
, 'r', "sasb");
589 r
= sd_bus_message_append(m
, "s", argv
[0]);
593 r
= sd_bus_message_append_strv(m
, argv
);
597 r
= sd_bus_message_append(m
, "b", false);
601 r
= sd_bus_message_close_container(m
);
605 r
= sd_bus_message_close_container(m
);
609 r
= sd_bus_message_close_container(m
);
613 r
= sd_bus_message_close_container(m
);
621 static int transient_scope_set_properties(sd_bus_message
*m
) {
626 r
= transient_unit_set_properties(m
, arg_property
);
630 r
= transient_kill_set_properties(m
);
634 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
641 static int transient_timer_set_properties(sd_bus_message
*m
) {
646 r
= transient_unit_set_properties(m
, arg_timer_property
);
651 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
657 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
662 if (arg_on_startup
) {
663 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
668 if (arg_on_unit_active
) {
669 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
674 if (arg_on_unit_inactive
) {
675 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
680 if (arg_on_calendar
) {
681 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
689 static int start_transient_service(
693 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
694 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
695 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
696 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
697 _cleanup_close_
int master
= -1;
705 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
706 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
708 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
710 r
= ptsname_malloc(master
, &pty_path
);
712 return log_error_errno(r
, "Failed to determine tty name: %m");
714 if (unlockpt(master
) < 0)
715 return log_error_errno(errno
, "Failed to unlock tty: %m");
717 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
718 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
721 r
= sd_bus_default_system(&system_bus
);
723 return log_error_errno(r
, "Failed to connect to system bus: %m");
725 r
= sd_bus_call_method(system_bus
,
726 "org.freedesktop.machine1",
727 "/org/freedesktop/machine1",
728 "org.freedesktop.machine1.Manager",
734 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
738 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
740 return bus_log_parse_error(r
);
742 reply
= sd_bus_message_unref(reply
);
744 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
746 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
748 pty_path
= strdup(s
);
752 assert_not_reached("Can't allocate tty via ssh");
756 r
= bus_wait_for_jobs_new(bus
, &w
);
758 return log_error_errno(r
, "Could not watch jobs: %m");
762 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
764 return log_error_errno(r
, "Failed to mangle unit name: %m");
765 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
768 r
= sd_bus_message_new_method_call(
771 "org.freedesktop.systemd1",
772 "/org/freedesktop/systemd1",
773 "org.freedesktop.systemd1.Manager",
774 "StartTransientUnit");
776 return bus_log_create_error(r
);
778 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
780 return bus_log_create_error(r
);
783 r
= sd_bus_message_append(m
, "ss", service
, "fail");
785 return bus_log_create_error(r
);
788 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
790 return bus_log_create_error(r
);
792 r
= transient_service_set_properties(m
, argv
, pty_path
);
794 return bus_log_create_error(r
);
796 r
= sd_bus_message_close_container(m
);
798 return bus_log_create_error(r
);
800 /* Auxiliary units */
801 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
803 return bus_log_create_error(r
);
805 polkit_agent_open_if_enabled();
807 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
809 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
814 r
= sd_bus_message_read(reply
, "o", &object
);
816 return bus_log_parse_error(r
);
818 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
824 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
825 _cleanup_event_unref_ sd_event
*event
= NULL
;
828 r
= sd_event_default(&event
);
830 return log_error_errno(r
, "Failed to get event loop: %m");
832 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
834 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
835 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
838 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
840 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
842 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
844 r
= sd_event_loop(event
);
846 return log_error_errno(r
, "Failed to run event loop: %m");
848 pty_forward_get_last_char(forward
, &last_char
);
850 forward
= pty_forward_free(forward
);
852 if (!arg_quiet
&& last_char
!= '\n')
855 } else if (!arg_quiet
)
856 log_info("Running as unit %s.", service
);
861 static int start_transient_scope(
865 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
866 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
867 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
868 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
869 _cleanup_free_
char *scope
= NULL
;
870 const char *object
= NULL
;
876 r
= bus_wait_for_jobs_new(bus
, &w
);
881 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
883 return log_error_errno(r
, "Failed to mangle scope name: %m");
884 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
887 r
= sd_bus_message_new_method_call(
890 "org.freedesktop.systemd1",
891 "/org/freedesktop/systemd1",
892 "org.freedesktop.systemd1.Manager",
893 "StartTransientUnit");
895 return bus_log_create_error(r
);
897 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
899 return bus_log_create_error(r
);
902 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
904 return bus_log_create_error(r
);
907 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
909 return bus_log_create_error(r
);
911 r
= transient_scope_set_properties(m
);
913 return bus_log_create_error(r
);
915 r
= sd_bus_message_close_container(m
);
917 return bus_log_create_error(r
);
919 /* Auxiliary units */
920 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
922 return bus_log_create_error(r
);
924 polkit_agent_open_if_enabled();
926 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
928 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
933 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
934 return log_error_errno(errno
, "Failed to set nice level: %m");
937 if (arg_exec_group
) {
940 r
= get_group_creds(&arg_exec_group
, &gid
);
942 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
944 if (setresgid(gid
, gid
, gid
) < 0)
945 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
949 const char *home
, *shell
;
953 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
955 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
957 r
= strv_extendf(&user_env
, "HOME=%s", home
);
961 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
965 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
969 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
973 if (!arg_exec_group
) {
974 if (setresgid(gid
, gid
, gid
) < 0)
975 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
978 if (setresuid(uid
, uid
, uid
) < 0)
979 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
982 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
986 r
= sd_bus_message_read(reply
, "o", &object
);
988 return bus_log_parse_error(r
);
990 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
995 log_info("Running scope as unit %s.", scope
);
997 execvpe(argv
[0], argv
, env
);
999 return log_error_errno(errno
, "Failed to execute: %m");
1002 static int start_transient_timer(
1006 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1007 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1008 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1009 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1010 const char *object
= NULL
;
1016 r
= bus_wait_for_jobs_new(bus
, &w
);
1021 switch (unit_name_to_type(arg_unit
)) {
1024 service
= strdup(arg_unit
);
1028 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1030 return log_error_errno(r
, "Failed to change unit suffix: %m");
1034 timer
= strdup(arg_unit
);
1038 r
= unit_name_change_suffix(timer
, ".service", &service
);
1040 return log_error_errno(r
, "Failed to change unit suffix: %m");
1044 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1046 return log_error_errno(r
, "Failed to mangle unit name: %m");
1048 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1050 return log_error_errno(r
, "Failed to mangle unit name: %m");
1054 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1055 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1058 r
= sd_bus_message_new_method_call(
1061 "org.freedesktop.systemd1",
1062 "/org/freedesktop/systemd1",
1063 "org.freedesktop.systemd1.Manager",
1064 "StartTransientUnit");
1066 return bus_log_create_error(r
);
1068 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1070 return bus_log_create_error(r
);
1073 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1075 return bus_log_create_error(r
);
1078 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1080 return bus_log_create_error(r
);
1082 r
= transient_timer_set_properties(m
);
1084 return bus_log_create_error(r
);
1086 r
= sd_bus_message_close_container(m
);
1088 return bus_log_create_error(r
);
1090 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1092 return bus_log_create_error(r
);
1095 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1097 return bus_log_create_error(r
);
1099 r
= sd_bus_message_append(m
, "s", service
);
1101 return bus_log_create_error(r
);
1103 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1105 return bus_log_create_error(r
);
1107 r
= transient_service_set_properties(m
, argv
, NULL
);
1109 return bus_log_create_error(r
);
1111 r
= sd_bus_message_close_container(m
);
1113 return bus_log_create_error(r
);
1115 r
= sd_bus_message_close_container(m
);
1117 return bus_log_create_error(r
);
1120 r
= sd_bus_message_close_container(m
);
1122 return bus_log_create_error(r
);
1124 polkit_agent_open_if_enabled();
1126 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1128 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1132 r
= sd_bus_message_read(reply
, "o", &object
);
1134 return bus_log_parse_error(r
);
1136 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1140 log_info("Running timer as unit %s.", timer
);
1142 log_info("Will run service as unit %s.", service
);
1147 int main(int argc
, char* argv
[]) {
1148 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1149 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1152 log_parse_environment();
1155 r
= parse_argv(argc
, argv
);
1159 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1160 /* Patch in an absolute path */
1162 r
= find_binary(argv
[optind
], &command
);
1164 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1168 argv
[optind
] = command
;
1171 if (!arg_description
) {
1172 description
= strv_join(argv
+ optind
, " ");
1178 if (arg_unit
&& isempty(description
)) {
1179 r
= free_and_strdup(&description
, arg_unit
);
1184 arg_description
= description
;
1187 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1189 log_error_errno(r
, "Failed to create bus connection: %m");
1194 r
= start_transient_scope(bus
, argv
+ optind
);
1195 else if (with_timer())
1196 r
= start_transient_timer(bus
, argv
+ optind
);
1198 r
= start_transient_service(bus
, argv
+ optind
);
1201 strv_free(arg_environment
);
1202 strv_free(arg_property
);
1203 strv_free(arg_timer_property
);
1205 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;