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 "unit-name.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;
220 case ARG_DESCRIPTION
:
221 arg_description
= optarg
;
228 case ARG_SEND_SIGHUP
:
229 arg_send_sighup
= true;
233 arg_remain_after_exit
= true;
237 arg_transport
= BUS_TRANSPORT_REMOTE
;
242 arg_transport
= BUS_TRANSPORT_MACHINE
;
246 case ARG_SERVICE_TYPE
:
247 arg_service_type
= optarg
;
251 arg_exec_user
= optarg
;
255 arg_exec_group
= optarg
;
259 r
= safe_atoi(optarg
, &arg_nice
);
260 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
261 log_error("Failed to parse nice value");
269 if (strv_extend(&arg_environment
, optarg
) < 0)
275 if (strv_extend(&arg_property
, optarg
) < 0)
290 r
= parse_sec(optarg
, &arg_on_active
);
292 log_error("Failed to parse timer value: %s", optarg
);
300 r
= parse_sec(optarg
, &arg_on_boot
);
302 log_error("Failed to parse timer value: %s", optarg
);
310 r
= parse_sec(optarg
, &arg_on_startup
);
312 log_error("Failed to parse timer value: %s", optarg
);
318 case ARG_ON_UNIT_ACTIVE
:
320 r
= parse_sec(optarg
, &arg_on_unit_active
);
322 log_error("Failed to parse timer value: %s", optarg
);
328 case ARG_ON_UNIT_INACTIVE
:
330 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
332 log_error("Failed to parse timer value: %s", optarg
);
338 case ARG_ON_CALENDAR
:
340 r
= calendar_spec_from_string(optarg
, &spec
);
342 log_error("Invalid calendar spec: %s", optarg
);
346 arg_on_calendar
= optarg
;
349 case ARG_TIMER_PROPERTY
:
351 if (strv_extend(&arg_timer_property
, optarg
) < 0)
364 assert_not_reached("Unhandled option");
367 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
368 log_error("Command line to execute required.");
372 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
373 log_error("Execution in user context is not supported on non-local systems.");
377 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
378 log_error("Scope execution is not supported on non-local systems.");
382 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
383 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
387 if (arg_pty
&& (with_timer() || arg_scope
)) {
388 log_error("--pty is not compatible in timer or --scope mode.");
392 if (arg_scope
&& with_timer()) {
393 log_error("Timer options are not supported in --scope mode.");
397 if (arg_timer_property
&& !with_timer()) {
398 log_error("--timer-property= has no effect without any other timer options.");
405 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
409 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
413 STRV_FOREACH(i
, properties
) {
414 r
= sd_bus_message_open_container(m
, 'r', "sv");
418 r
= bus_append_unit_property_assignment(m
, *i
);
422 r
= sd_bus_message_close_container(m
);
430 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
434 if (!isempty(arg_slice
)) {
435 _cleanup_free_
char *slice
;
437 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
441 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
449 static int transient_kill_set_properties(sd_bus_message
*m
) {
453 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
458 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
463 r
= transient_unit_set_properties(m
, arg_property
);
467 r
= transient_kill_set_properties(m
);
471 r
= transient_cgroup_set_properties(m
);
475 if (arg_remain_after_exit
) {
476 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
481 if (arg_service_type
) {
482 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
488 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
493 if (arg_exec_group
) {
494 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
500 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
508 r
= sd_bus_message_append(m
,
510 "StandardInput", "s", "tty",
511 "StandardOutput", "s", "tty",
512 "StandardError", "s", "tty",
513 "TTYPath", "s", pty_path
);
521 n
= strjoina("TERM=", e
);
522 r
= sd_bus_message_append(m
,
524 "Environment", "as", 1, n
);
530 if (!strv_isempty(arg_environment
)) {
531 r
= sd_bus_message_open_container(m
, 'r', "sv");
535 r
= sd_bus_message_append(m
, "s", "Environment");
539 r
= sd_bus_message_open_container(m
, 'v', "as");
543 r
= sd_bus_message_append_strv(m
, arg_environment
);
547 r
= sd_bus_message_close_container(m
);
551 r
= sd_bus_message_close_container(m
);
558 r
= sd_bus_message_open_container(m
, 'r', "sv");
562 r
= sd_bus_message_append(m
, "s", "ExecStart");
566 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
570 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
574 r
= sd_bus_message_open_container(m
, 'r', "sasb");
578 r
= sd_bus_message_append(m
, "s", argv
[0]);
582 r
= sd_bus_message_append_strv(m
, argv
);
586 r
= sd_bus_message_append(m
, "b", false);
590 r
= sd_bus_message_close_container(m
);
594 r
= sd_bus_message_close_container(m
);
598 r
= sd_bus_message_close_container(m
);
602 r
= sd_bus_message_close_container(m
);
610 static int transient_scope_set_properties(sd_bus_message
*m
) {
615 r
= transient_unit_set_properties(m
, arg_property
);
619 r
= transient_kill_set_properties(m
);
623 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
630 static int transient_timer_set_properties(sd_bus_message
*m
) {
635 r
= transient_unit_set_properties(m
, arg_timer_property
);
640 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
646 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
651 if (arg_on_startup
) {
652 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
657 if (arg_on_unit_active
) {
658 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
663 if (arg_on_unit_inactive
) {
664 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
669 if (arg_on_calendar
) {
670 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
678 static int start_transient_service(
682 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
683 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
684 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
685 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
686 _cleanup_close_
int master
= -1;
694 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
695 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
697 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
699 r
= ptsname_malloc(master
, &pty_path
);
701 return log_error_errno(r
, "Failed to determine tty name: %m");
703 if (unlockpt(master
) < 0)
704 return log_error_errno(errno
, "Failed to unlock tty: %m");
706 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
707 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
710 r
= sd_bus_open_system(&system_bus
);
712 log_error_errno(r
, "Failed to connect to system bus: %m");
714 r
= sd_bus_call_method(system_bus
,
715 "org.freedesktop.machine1",
716 "/org/freedesktop/machine1",
717 "org.freedesktop.machine1.Manager",
723 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
727 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
729 return bus_log_parse_error(r
);
731 reply
= sd_bus_message_unref(reply
);
733 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
735 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
737 pty_path
= strdup(s
);
741 assert_not_reached("Can't allocate tty via ssh");
745 r
= bus_wait_for_jobs_new(bus
, &w
);
747 return log_error_errno(r
, "Could not watch jobs: %m");
751 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
753 return log_error_errno(r
, "Failed to mangle unit name: %m");
754 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
757 r
= sd_bus_message_new_method_call(
760 "org.freedesktop.systemd1",
761 "/org/freedesktop/systemd1",
762 "org.freedesktop.systemd1.Manager",
763 "StartTransientUnit");
765 return bus_log_create_error(r
);
767 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
769 return bus_log_create_error(r
);
772 r
= sd_bus_message_append(m
, "ss", service
, "fail");
774 return bus_log_create_error(r
);
777 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
779 return bus_log_create_error(r
);
781 r
= transient_service_set_properties(m
, argv
, pty_path
);
783 return bus_log_create_error(r
);
785 r
= sd_bus_message_close_container(m
);
787 return bus_log_create_error(r
);
789 /* Auxiliary units */
790 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
792 return bus_log_create_error(r
);
794 polkit_agent_open_if_enabled();
796 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
798 log_error("Failed to start transient service unit: %s", bus_error_message(&error
, -r
));
805 r
= sd_bus_message_read(reply
, "o", &object
);
807 return bus_log_parse_error(r
);
809 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
815 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
816 _cleanup_event_unref_ sd_event
*event
= NULL
;
819 r
= sd_event_default(&event
);
821 return log_error_errno(r
, "Failed to get event loop: %m");
823 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
825 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
826 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
829 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
831 r
= pty_forward_new(event
, master
, false, false, &forward
);
833 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
835 r
= sd_event_loop(event
);
837 return log_error_errno(r
, "Failed to run event loop: %m");
839 pty_forward_get_last_char(forward
, &last_char
);
841 forward
= pty_forward_free(forward
);
843 if (!arg_quiet
&& last_char
!= '\n')
846 } else if (!arg_quiet
)
847 log_info("Running as unit %s.", service
);
852 static int start_transient_scope(
856 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
857 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
858 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
859 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
860 _cleanup_free_
char *scope
= NULL
;
861 const char *object
= NULL
;
867 r
= bus_wait_for_jobs_new(bus
, &w
);
872 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
874 return log_error_errno(r
, "Failed to mangle scope name: %m");
875 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
878 r
= sd_bus_message_new_method_call(
881 "org.freedesktop.systemd1",
882 "/org/freedesktop/systemd1",
883 "org.freedesktop.systemd1.Manager",
884 "StartTransientUnit");
886 return bus_log_create_error(r
);
888 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
890 return bus_log_create_error(r
);
893 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
895 return bus_log_create_error(r
);
898 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
900 return bus_log_create_error(r
);
902 r
= transient_scope_set_properties(m
);
904 return bus_log_create_error(r
);
906 r
= sd_bus_message_close_container(m
);
908 return bus_log_create_error(r
);
910 /* Auxiliary units */
911 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
913 return bus_log_create_error(r
);
915 polkit_agent_open_if_enabled();
917 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
919 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
924 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
925 return log_error_errno(errno
, "Failed to set nice level: %m");
928 if (arg_exec_group
) {
931 r
= get_group_creds(&arg_exec_group
, &gid
);
933 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
935 if (setresgid(gid
, gid
, gid
) < 0)
936 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
940 const char *home
, *shell
;
944 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
946 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
948 r
= strv_extendf(&user_env
, "HOME=%s", home
);
952 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
956 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
960 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
964 if (!arg_exec_group
) {
965 if (setresgid(gid
, gid
, gid
) < 0)
966 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
969 if (setresuid(uid
, uid
, uid
) < 0)
970 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
973 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
977 r
= sd_bus_message_read(reply
, "o", &object
);
979 return bus_log_parse_error(r
);
981 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
986 log_info("Running scope as unit %s.", scope
);
988 execvpe(argv
[0], argv
, env
);
990 return log_error_errno(errno
, "Failed to execute: %m");
993 static int start_transient_timer(
997 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
998 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
999 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1000 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1001 const char *object
= NULL
;
1007 r
= bus_wait_for_jobs_new(bus
, &w
);
1012 switch (unit_name_to_type(arg_unit
)) {
1015 service
= strdup(arg_unit
);
1019 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1021 return log_error_errno(r
, "Failed to change unit suffix: %m");
1025 timer
= strdup(arg_unit
);
1029 r
= unit_name_change_suffix(timer
, ".service", &service
);
1031 return log_error_errno(r
, "Failed to change unit suffix: %m");
1035 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1037 return log_error_errno(r
, "Failed to mangle unit name: %m");
1039 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1041 return log_error_errno(r
, "Failed to mangle unit name: %m");
1045 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1046 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1049 r
= sd_bus_message_new_method_call(
1052 "org.freedesktop.systemd1",
1053 "/org/freedesktop/systemd1",
1054 "org.freedesktop.systemd1.Manager",
1055 "StartTransientUnit");
1057 return bus_log_create_error(r
);
1059 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1061 return bus_log_create_error(r
);
1064 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1066 return bus_log_create_error(r
);
1069 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1071 return bus_log_create_error(r
);
1073 r
= transient_timer_set_properties(m
);
1075 return bus_log_create_error(r
);
1077 r
= sd_bus_message_close_container(m
);
1079 return bus_log_create_error(r
);
1081 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1083 return bus_log_create_error(r
);
1086 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1088 return bus_log_create_error(r
);
1090 r
= sd_bus_message_append(m
, "s", service
);
1092 return bus_log_create_error(r
);
1094 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1096 return bus_log_create_error(r
);
1098 r
= transient_service_set_properties(m
, argv
, NULL
);
1100 return bus_log_create_error(r
);
1102 r
= sd_bus_message_close_container(m
);
1104 return bus_log_create_error(r
);
1106 r
= sd_bus_message_close_container(m
);
1108 return bus_log_create_error(r
);
1111 r
= sd_bus_message_close_container(m
);
1113 return bus_log_create_error(r
);
1115 polkit_agent_open_if_enabled();
1117 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1119 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1123 r
= sd_bus_message_read(reply
, "o", &object
);
1125 return bus_log_parse_error(r
);
1127 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1131 log_info("Running timer as unit %s.", timer
);
1133 log_info("Will run service as unit %s.", service
);
1138 int main(int argc
, char* argv
[]) {
1139 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1140 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1143 log_parse_environment();
1146 r
= parse_argv(argc
, argv
);
1150 if (argc
> optind
) {
1151 r
= find_binary(argv
[optind
], arg_transport
== BUS_TRANSPORT_LOCAL
, &command
);
1153 log_error_errno(r
, "Failed to find executable %s%s: %m",
1155 arg_transport
== BUS_TRANSPORT_LOCAL
? "" : " on local system");
1158 argv
[optind
] = command
;
1161 if (!arg_description
) {
1162 description
= strv_join(argv
+ optind
, " ");
1168 if (arg_unit
&& isempty(description
)) {
1169 r
= free_and_strdup(&description
, arg_unit
);
1174 arg_description
= description
;
1177 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1179 log_error_errno(r
, "Failed to create bus connection: %m");
1184 r
= start_transient_scope(bus
, argv
+ optind
);
1185 else if (with_timer())
1186 r
= start_transient_timer(bus
, argv
+ optind
);
1188 r
= start_transient_service(bus
, argv
+ optind
);
1191 strv_free(arg_environment
);
1192 strv_free(arg_property
);
1193 strv_free(arg_timer_property
);
1195 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;