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 "event-util.h"
31 #include "unit-name.h"
33 #include "path-util.h"
34 #include "bus-error.h"
35 #include "calendarspec.h"
37 #include "formats-util.h"
38 #include "signal-util.h"
39 #include "spawn-polkit-agent.h"
41 static bool arg_ask_password
= true;
42 static bool arg_scope
= false;
43 static bool arg_remain_after_exit
= false;
44 static bool arg_no_block
= false;
45 static const char *arg_unit
= NULL
;
46 static const char *arg_description
= NULL
;
47 static const char *arg_slice
= NULL
;
48 static bool arg_send_sighup
= false;
49 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
50 static const char *arg_host
= NULL
;
51 static bool arg_user
= false;
52 static const char *arg_service_type
= NULL
;
53 static const char *arg_exec_user
= NULL
;
54 static const char *arg_exec_group
= NULL
;
55 static int arg_nice
= 0;
56 static bool arg_nice_set
= false;
57 static char **arg_environment
= NULL
;
58 static char **arg_property
= NULL
;
59 static bool arg_pty
= false;
60 static usec_t arg_on_active
= 0;
61 static usec_t arg_on_boot
= 0;
62 static usec_t arg_on_startup
= 0;
63 static usec_t arg_on_unit_active
= 0;
64 static usec_t arg_on_unit_inactive
= 0;
65 static char *arg_on_calendar
= NULL
;
66 static char **arg_timer_property
= NULL
;
67 static bool arg_quiet
= false;
69 static void polkit_agent_open_if_enabled(void) {
71 /* Open the polkit agent as a child process if necessary */
72 if (!arg_ask_password
)
75 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
81 static void help(void) {
82 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
83 "Run the specified command in a transient scope or service or timer\n"
84 "unit. If timer option is specified and unit is exist which is\n"
85 "specified with --unit option then command can be omitted.\n\n"
86 " -h --help Show this help\n"
87 " --version Show package version\n"
88 " --no-ask-password Do not prompt for password\n"
89 " --user Run as user unit\n"
90 " -H --host=[USER@]HOST Operate on remote host\n"
91 " -M --machine=CONTAINER Operate on local container\n"
92 " --scope Run this as scope rather than service\n"
93 " --unit=UNIT Run under the specified unit name\n"
94 " -p --property=NAME=VALUE Set unit property\n"
95 " --description=TEXT Description for unit\n"
96 " --slice=SLICE Run in the specified slice\n"
97 " --no-block Do not wait until operation finished\n"
98 " -r --remain-after-exit Leave service around until explicitly stopped\n"
99 " --send-sighup Send SIGHUP when terminating\n"
100 " --service-type=TYPE Service type\n"
101 " --uid=USER Run as system user\n"
102 " --gid=GROUP Run as system group\n"
103 " --nice=NICE Nice level\n"
104 " --setenv=NAME=VALUE Set environment\n"
105 " -t --pty Run service on pseudo tty\n"
106 " -q --quiet Suppress information messages during runtime\n\n"
108 " --on-active=SECONDS Run after SECONDS delay\n"
109 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
110 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
111 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
112 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
113 " --on-calendar=SPEC Realtime timer\n"
114 " --timer-property=NAME=VALUE Set timer unit property\n",
115 program_invocation_short_name
);
118 static bool with_timer(void) {
119 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
122 static int parse_argv(int argc
, char *argv
[]) {
144 ARG_ON_UNIT_INACTIVE
,
150 static const struct option options
[] = {
151 { "help", no_argument
, NULL
, 'h' },
152 { "version", no_argument
, NULL
, ARG_VERSION
},
153 { "user", no_argument
, NULL
, ARG_USER
},
154 { "system", no_argument
, NULL
, ARG_SYSTEM
},
155 { "scope", no_argument
, NULL
, ARG_SCOPE
},
156 { "unit", required_argument
, NULL
, ARG_UNIT
},
157 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
158 { "slice", required_argument
, NULL
, ARG_SLICE
},
159 { "remain-after-exit", no_argument
, NULL
, 'r' },
160 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
161 { "host", required_argument
, NULL
, 'H' },
162 { "machine", required_argument
, NULL
, 'M' },
163 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
164 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
165 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
166 { "nice", required_argument
, NULL
, ARG_NICE
},
167 { "setenv", required_argument
, NULL
, ARG_SETENV
},
168 { "property", required_argument
, NULL
, 'p' },
169 { "tty", no_argument
, NULL
, 't' },
170 { "quiet", no_argument
, NULL
, 'q' },
171 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
172 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
173 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
174 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
175 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
176 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
177 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
178 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
179 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
184 CalendarSpec
*spec
= NULL
;
189 while ((c
= getopt_long(argc
, argv
, "+hrH:M:p:tq", options
, NULL
)) >= 0)
197 case ARG_NO_ASK_PASSWORD
:
198 arg_ask_password
= false;
202 puts(PACKAGE_STRING
);
203 puts(SYSTEMD_FEATURES
);
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
:
342 r
= calendar_spec_from_string(optarg
, &spec
);
344 log_error("Invalid calendar spec: %s", optarg
);
348 arg_on_calendar
= optarg
;
351 case ARG_TIMER_PROPERTY
:
353 if (strv_extend(&arg_timer_property
, optarg
) < 0)
366 assert_not_reached("Unhandled option");
369 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
370 log_error("Command line to execute required.");
374 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
375 log_error("Execution in user context is not supported on non-local systems.");
379 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
380 log_error("Scope execution is not supported on non-local systems.");
384 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
385 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
389 if (arg_pty
&& (with_timer() || arg_scope
)) {
390 log_error("--pty is not compatible in timer or --scope mode.");
394 if (arg_scope
&& with_timer()) {
395 log_error("Timer options are not supported in --scope mode.");
399 if (arg_timer_property
&& !with_timer()) {
400 log_error("--timer-property= has no effect without any other timer options.");
407 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
411 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
415 STRV_FOREACH(i
, properties
) {
416 r
= sd_bus_message_open_container(m
, 'r', "sv");
420 r
= bus_append_unit_property_assignment(m
, *i
);
424 r
= sd_bus_message_close_container(m
);
432 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
436 if (!isempty(arg_slice
)) {
437 _cleanup_free_
char *slice
;
439 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
443 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
451 static int transient_kill_set_properties(sd_bus_message
*m
) {
455 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
460 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
465 r
= transient_unit_set_properties(m
, arg_property
);
469 r
= transient_kill_set_properties(m
);
473 r
= transient_cgroup_set_properties(m
);
477 if (arg_remain_after_exit
) {
478 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
483 if (arg_service_type
) {
484 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
490 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
495 if (arg_exec_group
) {
496 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
502 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
510 r
= sd_bus_message_append(m
,
512 "StandardInput", "s", "tty",
513 "StandardOutput", "s", "tty",
514 "StandardError", "s", "tty",
515 "TTYPath", "s", pty_path
);
523 n
= strjoina("TERM=", e
);
524 r
= sd_bus_message_append(m
,
526 "Environment", "as", 1, n
);
532 if (!strv_isempty(arg_environment
)) {
533 r
= sd_bus_message_open_container(m
, 'r', "sv");
537 r
= sd_bus_message_append(m
, "s", "Environment");
541 r
= sd_bus_message_open_container(m
, 'v', "as");
545 r
= sd_bus_message_append_strv(m
, arg_environment
);
549 r
= sd_bus_message_close_container(m
);
553 r
= sd_bus_message_close_container(m
);
560 r
= sd_bus_message_open_container(m
, 'r', "sv");
564 r
= sd_bus_message_append(m
, "s", "ExecStart");
568 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
572 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
576 r
= sd_bus_message_open_container(m
, 'r', "sasb");
580 r
= sd_bus_message_append(m
, "s", argv
[0]);
584 r
= sd_bus_message_append_strv(m
, argv
);
588 r
= sd_bus_message_append(m
, "b", false);
592 r
= sd_bus_message_close_container(m
);
596 r
= sd_bus_message_close_container(m
);
600 r
= sd_bus_message_close_container(m
);
604 r
= sd_bus_message_close_container(m
);
612 static int transient_scope_set_properties(sd_bus_message
*m
) {
617 r
= transient_unit_set_properties(m
, arg_property
);
621 r
= transient_kill_set_properties(m
);
625 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
632 static int transient_timer_set_properties(sd_bus_message
*m
) {
637 r
= transient_unit_set_properties(m
, arg_timer_property
);
642 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
648 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
653 if (arg_on_startup
) {
654 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
659 if (arg_on_unit_active
) {
660 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
665 if (arg_on_unit_inactive
) {
666 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
671 if (arg_on_calendar
) {
672 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
680 static int start_transient_service(
684 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
685 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
686 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
687 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
688 _cleanup_close_
int master
= -1;
696 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
697 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
699 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
701 r
= ptsname_malloc(master
, &pty_path
);
703 return log_error_errno(r
, "Failed to determine tty name: %m");
705 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
706 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
709 r
= sd_bus_open_system(&system_bus
);
711 log_error_errno(r
, "Failed to connect to system bus: %m");
713 r
= sd_bus_call_method(system_bus
,
714 "org.freedesktop.machine1",
715 "/org/freedesktop/machine1",
716 "org.freedesktop.machine1.Manager",
722 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
726 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
728 return bus_log_parse_error(r
);
730 reply
= sd_bus_message_unref(reply
);
732 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
734 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
736 pty_path
= strdup(s
);
740 assert_not_reached("Can't allocate tty via ssh");
742 if (unlockpt(master
) < 0)
743 return log_error_errno(errno
, "Failed to unlock tty: %m");
747 r
= bus_wait_for_jobs_new(bus
, &w
);
749 return log_error_errno(r
, "Could not watch jobs: %m");
753 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
755 return log_error_errno(r
, "Failed to mangle unit name: %m");
756 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
759 r
= sd_bus_message_new_method_call(
762 "org.freedesktop.systemd1",
763 "/org/freedesktop/systemd1",
764 "org.freedesktop.systemd1.Manager",
765 "StartTransientUnit");
767 return bus_log_create_error(r
);
769 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
771 return bus_log_create_error(r
);
774 r
= sd_bus_message_append(m
, "ss", service
, "fail");
776 return bus_log_create_error(r
);
779 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
781 return bus_log_create_error(r
);
783 r
= transient_service_set_properties(m
, argv
, pty_path
);
785 return bus_log_create_error(r
);
787 r
= sd_bus_message_close_container(m
);
789 return bus_log_create_error(r
);
791 /* Auxiliary units */
792 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
794 return bus_log_create_error(r
);
796 polkit_agent_open_if_enabled();
798 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
800 log_error("Failed to start transient service unit: %s", bus_error_message(&error
, -r
));
807 r
= sd_bus_message_read(reply
, "o", &object
);
809 return bus_log_parse_error(r
);
811 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
817 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
818 _cleanup_event_unref_ sd_event
*event
= NULL
;
821 r
= sd_event_default(&event
);
823 return log_error_errno(r
, "Failed to get event loop: %m");
825 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
827 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
828 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
831 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
833 r
= pty_forward_new(event
, master
, false, false, &forward
);
835 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
837 r
= sd_event_loop(event
);
839 return log_error_errno(r
, "Failed to run event loop: %m");
841 pty_forward_get_last_char(forward
, &last_char
);
843 forward
= pty_forward_free(forward
);
845 if (!arg_quiet
&& last_char
!= '\n')
848 } else if (!arg_quiet
)
849 log_info("Running as unit %s.", service
);
854 static int start_transient_scope(
858 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
859 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
860 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
861 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
862 _cleanup_free_
char *scope
= NULL
;
863 const char *object
= NULL
;
869 r
= bus_wait_for_jobs_new(bus
, &w
);
874 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
876 return log_error_errno(r
, "Failed to mangle scope name: %m");
877 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
880 r
= sd_bus_message_new_method_call(
883 "org.freedesktop.systemd1",
884 "/org/freedesktop/systemd1",
885 "org.freedesktop.systemd1.Manager",
886 "StartTransientUnit");
888 return bus_log_create_error(r
);
890 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
892 return bus_log_create_error(r
);
895 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
897 return bus_log_create_error(r
);
900 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
902 return bus_log_create_error(r
);
904 r
= transient_scope_set_properties(m
);
906 return bus_log_create_error(r
);
908 r
= sd_bus_message_close_container(m
);
910 return bus_log_create_error(r
);
912 /* Auxiliary units */
913 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
915 return bus_log_create_error(r
);
917 polkit_agent_open_if_enabled();
919 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
921 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
926 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
927 return log_error_errno(errno
, "Failed to set nice level: %m");
930 if (arg_exec_group
) {
933 r
= get_group_creds(&arg_exec_group
, &gid
);
935 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
937 if (setresgid(gid
, gid
, gid
) < 0)
938 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
942 const char *home
, *shell
;
946 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
948 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
950 r
= strv_extendf(&user_env
, "HOME=%s", home
);
954 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
958 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
962 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
966 if (!arg_exec_group
) {
967 if (setresgid(gid
, gid
, gid
) < 0)
968 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
971 if (setresuid(uid
, uid
, uid
) < 0)
972 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
975 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
979 r
= sd_bus_message_read(reply
, "o", &object
);
981 return bus_log_parse_error(r
);
983 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
988 log_info("Running scope as unit %s.", scope
);
990 execvpe(argv
[0], argv
, env
);
992 return log_error_errno(errno
, "Failed to execute: %m");
995 static int start_transient_timer(
999 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1000 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1001 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1002 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1003 const char *object
= NULL
;
1009 r
= bus_wait_for_jobs_new(bus
, &w
);
1014 switch (unit_name_to_type(arg_unit
)) {
1017 service
= strdup(arg_unit
);
1021 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1023 return log_error_errno(r
, "Failed to change unit suffix: %m");
1027 timer
= strdup(arg_unit
);
1031 r
= unit_name_change_suffix(timer
, ".service", &service
);
1033 return log_error_errno(r
, "Failed to change unit suffix: %m");
1037 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1039 return log_error_errno(r
, "Failed to mangle unit name: %m");
1041 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1043 return log_error_errno(r
, "Failed to mangle unit name: %m");
1047 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1048 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1051 r
= sd_bus_message_new_method_call(
1054 "org.freedesktop.systemd1",
1055 "/org/freedesktop/systemd1",
1056 "org.freedesktop.systemd1.Manager",
1057 "StartTransientUnit");
1059 return bus_log_create_error(r
);
1061 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1063 return bus_log_create_error(r
);
1066 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1068 return bus_log_create_error(r
);
1071 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1073 return bus_log_create_error(r
);
1075 r
= transient_timer_set_properties(m
);
1077 return bus_log_create_error(r
);
1079 r
= sd_bus_message_close_container(m
);
1081 return bus_log_create_error(r
);
1083 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1085 return bus_log_create_error(r
);
1088 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1090 return bus_log_create_error(r
);
1092 r
= sd_bus_message_append(m
, "s", service
);
1094 return bus_log_create_error(r
);
1096 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1098 return bus_log_create_error(r
);
1100 r
= transient_service_set_properties(m
, argv
, NULL
);
1102 return bus_log_create_error(r
);
1104 r
= sd_bus_message_close_container(m
);
1106 return bus_log_create_error(r
);
1108 r
= sd_bus_message_close_container(m
);
1110 return bus_log_create_error(r
);
1113 r
= sd_bus_message_close_container(m
);
1115 return bus_log_create_error(r
);
1117 polkit_agent_open_if_enabled();
1119 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1121 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1125 r
= sd_bus_message_read(reply
, "o", &object
);
1127 return bus_log_parse_error(r
);
1129 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1133 log_info("Running timer as unit %s.", timer
);
1135 log_info("Will run service as unit %s.", service
);
1140 int main(int argc
, char* argv
[]) {
1141 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1142 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1145 log_parse_environment();
1148 r
= parse_argv(argc
, argv
);
1152 if (argc
> optind
) {
1153 r
= find_binary(argv
[optind
], arg_transport
== BUS_TRANSPORT_LOCAL
, &command
);
1155 log_error_errno(r
, "Failed to find executable %s%s: %m",
1157 arg_transport
== BUS_TRANSPORT_LOCAL
? "" : " on local system");
1160 argv
[optind
] = command
;
1163 if (!arg_description
) {
1164 description
= strv_join(argv
+ optind
, " ");
1170 if (arg_unit
&& isempty(description
)) {
1171 r
= free_and_strdup(&description
, arg_unit
);
1176 arg_description
= description
;
1179 r
= bus_open_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1181 log_error_errno(r
, "Failed to create bus connection: %m");
1186 r
= start_transient_scope(bus
, argv
+ optind
);
1187 else if (with_timer())
1188 r
= start_transient_timer(bus
, argv
+ optind
);
1190 r
= start_transient_service(bus
, argv
+ optind
);
1193 strv_free(arg_environment
);
1194 strv_free(arg_property
);
1195 strv_free(arg_timer_property
);
1197 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;