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"
33 #include "formats-util.h"
34 #include "path-util.h"
36 #include "signal-util.h"
37 #include "spawn-polkit-agent.h"
39 #include "terminal-util.h"
40 #include "unit-name.h"
42 static bool arg_ask_password
= true;
43 static bool arg_scope
= false;
44 static bool arg_remain_after_exit
= false;
45 static bool arg_no_block
= false;
46 static const char *arg_unit
= NULL
;
47 static const char *arg_description
= NULL
;
48 static const char *arg_slice
= NULL
;
49 static bool arg_send_sighup
= false;
50 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
51 static const char *arg_host
= NULL
;
52 static bool arg_user
= false;
53 static const char *arg_service_type
= NULL
;
54 static const char *arg_exec_user
= NULL
;
55 static const char *arg_exec_group
= NULL
;
56 static int arg_nice
= 0;
57 static bool arg_nice_set
= false;
58 static char **arg_environment
= NULL
;
59 static char **arg_property
= NULL
;
60 static bool arg_pty
= false;
61 static usec_t arg_on_active
= 0;
62 static usec_t arg_on_boot
= 0;
63 static usec_t arg_on_startup
= 0;
64 static usec_t arg_on_unit_active
= 0;
65 static usec_t arg_on_unit_inactive
= 0;
66 static char *arg_on_calendar
= NULL
;
67 static char **arg_timer_property
= NULL
;
68 static bool arg_quiet
= false;
70 static void polkit_agent_open_if_enabled(void) {
72 /* Open the polkit agent as a child process if necessary */
73 if (!arg_ask_password
)
76 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
82 static void help(void) {
83 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
84 "Run the specified command in a transient scope or service or timer\n"
85 "unit. If timer option is specified and unit is exist which is\n"
86 "specified with --unit option then command can be omitted.\n\n"
87 " -h --help Show this help\n"
88 " --version Show package version\n"
89 " --no-ask-password Do not prompt for password\n"
90 " --user Run as user unit\n"
91 " -H --host=[USER@]HOST Operate on remote host\n"
92 " -M --machine=CONTAINER Operate on local container\n"
93 " --scope Run this as scope rather than service\n"
94 " --unit=UNIT Run under the specified unit name\n"
95 " -p --property=NAME=VALUE Set unit property\n"
96 " --description=TEXT Description for unit\n"
97 " --slice=SLICE Run in the specified slice\n"
98 " --no-block Do not wait until operation finished\n"
99 " -r --remain-after-exit Leave service around until explicitly stopped\n"
100 " --send-sighup Send SIGHUP when terminating\n"
101 " --service-type=TYPE Service type\n"
102 " --uid=USER Run as system user\n"
103 " --gid=GROUP Run as system group\n"
104 " --nice=NICE Nice level\n"
105 " --setenv=NAME=VALUE Set environment\n"
106 " -t --pty Run service on pseudo tty\n"
107 " -q --quiet Suppress information messages during runtime\n\n"
109 " --on-active=SECONDS Run after SECONDS delay\n"
110 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
111 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
112 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
113 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
114 " --on-calendar=SPEC Realtime timer\n"
115 " --timer-property=NAME=VALUE Set timer unit property\n",
116 program_invocation_short_name
);
119 static bool with_timer(void) {
120 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
123 static int parse_argv(int argc
, char *argv
[]) {
145 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
, ARG_SETENV
},
169 { "property", required_argument
, NULL
, 'p' },
170 { "tty", no_argument
, NULL
, 't' },
171 { "quiet", no_argument
, NULL
, 'q' },
172 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
173 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
174 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
175 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
176 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
177 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
178 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
179 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
180 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
185 CalendarSpec
*spec
= NULL
;
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
:
341 r
= calendar_spec_from_string(optarg
, &spec
);
343 log_error("Invalid calendar spec: %s", optarg
);
347 arg_on_calendar
= optarg
;
350 case ARG_TIMER_PROPERTY
:
352 if (strv_extend(&arg_timer_property
, optarg
) < 0)
365 assert_not_reached("Unhandled option");
368 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
369 log_error("Command line to execute required.");
373 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
374 log_error("Execution in user context is not supported on non-local systems.");
378 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
379 log_error("Scope execution is not supported on non-local systems.");
383 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
384 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
388 if (arg_pty
&& (with_timer() || arg_scope
)) {
389 log_error("--pty is not compatible in timer or --scope mode.");
393 if (arg_scope
&& with_timer()) {
394 log_error("Timer options are not supported in --scope mode.");
398 if (arg_timer_property
&& !with_timer()) {
399 log_error("--timer-property= has no effect without any other timer options.");
406 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
410 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
414 STRV_FOREACH(i
, properties
) {
415 r
= sd_bus_message_open_container(m
, 'r', "sv");
419 r
= bus_append_unit_property_assignment(m
, *i
);
423 r
= sd_bus_message_close_container(m
);
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
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
631 static int transient_timer_set_properties(sd_bus_message
*m
) {
636 r
= transient_unit_set_properties(m
, arg_timer_property
);
641 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
647 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
652 if (arg_on_startup
) {
653 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
658 if (arg_on_unit_active
) {
659 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
664 if (arg_on_unit_inactive
) {
665 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
670 if (arg_on_calendar
) {
671 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
679 static int start_transient_service(
683 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
684 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
685 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
686 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
687 _cleanup_close_
int master
= -1;
695 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
696 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
698 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
700 r
= ptsname_malloc(master
, &pty_path
);
702 return log_error_errno(r
, "Failed to determine tty name: %m");
704 if (unlockpt(master
) < 0)
705 return log_error_errno(errno
, "Failed to unlock tty: %m");
707 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
708 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
711 r
= sd_bus_open_system(&system_bus
);
713 log_error_errno(r
, "Failed to connect to system bus: %m");
715 r
= sd_bus_call_method(system_bus
,
716 "org.freedesktop.machine1",
717 "/org/freedesktop/machine1",
718 "org.freedesktop.machine1.Manager",
724 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
728 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
730 return bus_log_parse_error(r
);
732 reply
= sd_bus_message_unref(reply
);
734 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
736 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
738 pty_path
= strdup(s
);
742 assert_not_reached("Can't allocate tty via ssh");
746 r
= bus_wait_for_jobs_new(bus
, &w
);
748 return log_error_errno(r
, "Could not watch jobs: %m");
752 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
754 return log_error_errno(r
, "Failed to mangle unit name: %m");
755 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
758 r
= sd_bus_message_new_method_call(
761 "org.freedesktop.systemd1",
762 "/org/freedesktop/systemd1",
763 "org.freedesktop.systemd1.Manager",
764 "StartTransientUnit");
766 return bus_log_create_error(r
);
768 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
770 return bus_log_create_error(r
);
773 r
= sd_bus_message_append(m
, "ss", service
, "fail");
775 return bus_log_create_error(r
);
778 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
780 return bus_log_create_error(r
);
782 r
= transient_service_set_properties(m
, argv
, pty_path
);
784 return bus_log_create_error(r
);
786 r
= sd_bus_message_close_container(m
);
788 return bus_log_create_error(r
);
790 /* Auxiliary units */
791 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
793 return bus_log_create_error(r
);
795 polkit_agent_open_if_enabled();
797 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
799 log_error("Failed to start transient service unit: %s", bus_error_message(&error
, -r
));
806 r
= sd_bus_message_read(reply
, "o", &object
);
808 return bus_log_parse_error(r
);
810 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
816 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
817 _cleanup_event_unref_ sd_event
*event
= NULL
;
820 r
= sd_event_default(&event
);
822 return log_error_errno(r
, "Failed to get event loop: %m");
824 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
826 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
827 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
830 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
832 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
834 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
836 r
= sd_event_loop(event
);
838 return log_error_errno(r
, "Failed to run event loop: %m");
840 pty_forward_get_last_char(forward
, &last_char
);
842 forward
= pty_forward_free(forward
);
844 if (!arg_quiet
&& last_char
!= '\n')
847 } else if (!arg_quiet
)
848 log_info("Running as unit %s.", service
);
853 static int start_transient_scope(
857 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
858 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
859 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
860 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
861 _cleanup_free_
char *scope
= NULL
;
862 const char *object
= NULL
;
868 r
= bus_wait_for_jobs_new(bus
, &w
);
873 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
875 return log_error_errno(r
, "Failed to mangle scope name: %m");
876 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
879 r
= sd_bus_message_new_method_call(
882 "org.freedesktop.systemd1",
883 "/org/freedesktop/systemd1",
884 "org.freedesktop.systemd1.Manager",
885 "StartTransientUnit");
887 return bus_log_create_error(r
);
889 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
891 return bus_log_create_error(r
);
894 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
896 return bus_log_create_error(r
);
899 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
901 return bus_log_create_error(r
);
903 r
= transient_scope_set_properties(m
);
905 return bus_log_create_error(r
);
907 r
= sd_bus_message_close_container(m
);
909 return bus_log_create_error(r
);
911 /* Auxiliary units */
912 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
914 return bus_log_create_error(r
);
916 polkit_agent_open_if_enabled();
918 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
920 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
925 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
926 return log_error_errno(errno
, "Failed to set nice level: %m");
929 if (arg_exec_group
) {
932 r
= get_group_creds(&arg_exec_group
, &gid
);
934 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
936 if (setresgid(gid
, gid
, gid
) < 0)
937 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
941 const char *home
, *shell
;
945 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
947 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
949 r
= strv_extendf(&user_env
, "HOME=%s", home
);
953 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
957 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
961 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
965 if (!arg_exec_group
) {
966 if (setresgid(gid
, gid
, gid
) < 0)
967 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
970 if (setresuid(uid
, uid
, uid
) < 0)
971 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
974 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
978 r
= sd_bus_message_read(reply
, "o", &object
);
980 return bus_log_parse_error(r
);
982 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
987 log_info("Running scope as unit %s.", scope
);
989 execvpe(argv
[0], argv
, env
);
991 return log_error_errno(errno
, "Failed to execute: %m");
994 static int start_transient_timer(
998 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
999 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1000 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1001 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1002 const char *object
= NULL
;
1008 r
= bus_wait_for_jobs_new(bus
, &w
);
1013 switch (unit_name_to_type(arg_unit
)) {
1016 service
= strdup(arg_unit
);
1020 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1022 return log_error_errno(r
, "Failed to change unit suffix: %m");
1026 timer
= strdup(arg_unit
);
1030 r
= unit_name_change_suffix(timer
, ".service", &service
);
1032 return log_error_errno(r
, "Failed to change unit suffix: %m");
1036 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1038 return log_error_errno(r
, "Failed to mangle unit name: %m");
1040 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1042 return log_error_errno(r
, "Failed to mangle unit name: %m");
1046 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1047 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1050 r
= sd_bus_message_new_method_call(
1053 "org.freedesktop.systemd1",
1054 "/org/freedesktop/systemd1",
1055 "org.freedesktop.systemd1.Manager",
1056 "StartTransientUnit");
1058 return bus_log_create_error(r
);
1060 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1062 return bus_log_create_error(r
);
1065 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1067 return bus_log_create_error(r
);
1070 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1072 return bus_log_create_error(r
);
1074 r
= transient_timer_set_properties(m
);
1076 return bus_log_create_error(r
);
1078 r
= sd_bus_message_close_container(m
);
1080 return bus_log_create_error(r
);
1082 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1084 return bus_log_create_error(r
);
1087 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1089 return bus_log_create_error(r
);
1091 r
= sd_bus_message_append(m
, "s", service
);
1093 return bus_log_create_error(r
);
1095 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1097 return bus_log_create_error(r
);
1099 r
= transient_service_set_properties(m
, argv
, NULL
);
1101 return bus_log_create_error(r
);
1103 r
= sd_bus_message_close_container(m
);
1105 return bus_log_create_error(r
);
1107 r
= sd_bus_message_close_container(m
);
1109 return bus_log_create_error(r
);
1112 r
= sd_bus_message_close_container(m
);
1114 return bus_log_create_error(r
);
1116 polkit_agent_open_if_enabled();
1118 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1120 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1124 r
= sd_bus_message_read(reply
, "o", &object
);
1126 return bus_log_parse_error(r
);
1128 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1132 log_info("Running timer as unit %s.", timer
);
1134 log_info("Will run service as unit %s.", service
);
1139 int main(int argc
, char* argv
[]) {
1140 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1141 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1144 log_parse_environment();
1147 r
= parse_argv(argc
, argv
);
1151 if (argc
> optind
) {
1152 r
= find_binary(argv
[optind
], arg_transport
== BUS_TRANSPORT_LOCAL
, &command
);
1154 log_error_errno(r
, "Failed to find executable %s%s: %m",
1156 arg_transport
== BUS_TRANSPORT_LOCAL
? "" : " on local system");
1159 argv
[optind
] = command
;
1162 if (!arg_description
) {
1163 description
= strv_join(argv
+ optind
, " ");
1169 if (arg_unit
&& isempty(description
)) {
1170 r
= free_and_strdup(&description
, arg_unit
);
1175 arg_description
= description
;
1178 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1180 log_error_errno(r
, "Failed to create bus connection: %m");
1185 r
= start_transient_scope(bus
, argv
+ optind
);
1186 else if (with_timer())
1187 r
= start_transient_timer(bus
, argv
+ optind
);
1189 r
= start_transient_service(bus
, argv
+ optind
);
1192 strv_free(arg_environment
);
1193 strv_free(arg_property
);
1194 strv_free(arg_timer_property
);
1196 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;