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"
40 static bool arg_scope
= false;
41 static bool arg_remain_after_exit
= false;
42 static bool arg_no_block
= false;
43 static const char *arg_unit
= NULL
;
44 static const char *arg_description
= NULL
;
45 static const char *arg_slice
= NULL
;
46 static bool arg_send_sighup
= false;
47 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
48 static const char *arg_host
= NULL
;
49 static bool arg_user
= false;
50 static const char *arg_service_type
= NULL
;
51 static const char *arg_exec_user
= NULL
;
52 static const char *arg_exec_group
= NULL
;
53 static int arg_nice
= 0;
54 static bool arg_nice_set
= false;
55 static char **arg_environment
= NULL
;
56 static char **arg_property
= NULL
;
57 static bool arg_pty
= false;
58 static usec_t arg_on_active
= 0;
59 static usec_t arg_on_boot
= 0;
60 static usec_t arg_on_startup
= 0;
61 static usec_t arg_on_unit_active
= 0;
62 static usec_t arg_on_unit_inactive
= 0;
63 static char *arg_on_calendar
= NULL
;
64 static char **arg_timer_property
= NULL
;
65 static bool arg_quiet
= false;
67 static void help(void) {
68 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
69 "Run the specified command in a transient scope or service or timer\n"
70 "unit. If timer option is specified and unit is exist which is\n"
71 "specified with --unit option then command can be omitted.\n\n"
72 " -h --help Show this help\n"
73 " --version Show package version\n"
74 " --user Run as user unit\n"
75 " -H --host=[USER@]HOST Operate on remote host\n"
76 " -M --machine=CONTAINER Operate on local container\n"
77 " --scope Run this as scope rather than service\n"
78 " --unit=UNIT Run under the specified unit name\n"
79 " -p --property=NAME=VALUE Set unit property\n"
80 " --description=TEXT Description for unit\n"
81 " --slice=SLICE Run in the specified slice\n"
82 " --no-block Do not wait until operation finished\n"
83 " -r --remain-after-exit Leave service around until explicitly stopped\n"
84 " --send-sighup Send SIGHUP when terminating\n"
85 " --service-type=TYPE Service type\n"
86 " --uid=USER Run as system user\n"
87 " --gid=GROUP Run as system group\n"
88 " --nice=NICE Nice level\n"
89 " --setenv=NAME=VALUE Set environment\n"
90 " -t --pty Run service on pseudo tty\n"
91 " -q --quiet Suppress information messages during runtime\n\n"
93 " --on-active=SECONDS Run after SECONDS delay\n"
94 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
95 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
96 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
97 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
98 " --on-calendar=SPEC Realtime timer\n"
99 " --timer-property=NAME=VALUE Set timer unit property\n",
100 program_invocation_short_name
);
103 static bool with_timer(void) {
104 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
107 static int parse_argv(int argc
, char *argv
[]) {
128 ARG_ON_UNIT_INACTIVE
,
134 static const struct option options
[] = {
135 { "help", no_argument
, NULL
, 'h' },
136 { "version", no_argument
, NULL
, ARG_VERSION
},
137 { "user", no_argument
, NULL
, ARG_USER
},
138 { "system", no_argument
, NULL
, ARG_SYSTEM
},
139 { "scope", no_argument
, NULL
, ARG_SCOPE
},
140 { "unit", required_argument
, NULL
, ARG_UNIT
},
141 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
142 { "slice", required_argument
, NULL
, ARG_SLICE
},
143 { "remain-after-exit", no_argument
, NULL
, 'r' },
144 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
145 { "host", required_argument
, NULL
, 'H' },
146 { "machine", required_argument
, NULL
, 'M' },
147 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
148 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
149 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
150 { "nice", required_argument
, NULL
, ARG_NICE
},
151 { "setenv", required_argument
, NULL
, ARG_SETENV
},
152 { "property", required_argument
, NULL
, 'p' },
153 { "tty", no_argument
, NULL
, 't' },
154 { "quiet", no_argument
, NULL
, 'q' },
155 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
156 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
157 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
158 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
159 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
160 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
161 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
162 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
167 CalendarSpec
*spec
= NULL
;
172 while ((c
= getopt_long(argc
, argv
, "+hrH:M:p:tq", options
, NULL
)) >= 0)
181 puts(PACKAGE_STRING
);
182 puts(SYSTEMD_FEATURES
);
201 case ARG_DESCRIPTION
:
202 arg_description
= optarg
;
209 case ARG_SEND_SIGHUP
:
210 arg_send_sighup
= true;
214 arg_remain_after_exit
= true;
218 arg_transport
= BUS_TRANSPORT_REMOTE
;
223 arg_transport
= BUS_TRANSPORT_MACHINE
;
227 case ARG_SERVICE_TYPE
:
228 arg_service_type
= optarg
;
232 arg_exec_user
= optarg
;
236 arg_exec_group
= optarg
;
240 r
= safe_atoi(optarg
, &arg_nice
);
241 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
242 log_error("Failed to parse nice value");
250 if (strv_extend(&arg_environment
, optarg
) < 0)
256 if (strv_extend(&arg_property
, optarg
) < 0)
271 r
= parse_sec(optarg
, &arg_on_active
);
273 log_error("Failed to parse timer value: %s", optarg
);
281 r
= parse_sec(optarg
, &arg_on_boot
);
283 log_error("Failed to parse timer value: %s", optarg
);
291 r
= parse_sec(optarg
, &arg_on_startup
);
293 log_error("Failed to parse timer value: %s", optarg
);
299 case ARG_ON_UNIT_ACTIVE
:
301 r
= parse_sec(optarg
, &arg_on_unit_active
);
303 log_error("Failed to parse timer value: %s", optarg
);
309 case ARG_ON_UNIT_INACTIVE
:
311 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
313 log_error("Failed to parse timer value: %s", optarg
);
319 case ARG_ON_CALENDAR
:
321 r
= calendar_spec_from_string(optarg
, &spec
);
323 log_error("Invalid calendar spec: %s", optarg
);
327 arg_on_calendar
= optarg
;
330 case ARG_TIMER_PROPERTY
:
332 if (strv_extend(&arg_timer_property
, optarg
) < 0)
345 assert_not_reached("Unhandled option");
348 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
349 log_error("Command line to execute required.");
353 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
354 log_error("Execution in user context is not supported on non-local systems.");
358 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
359 log_error("Scope execution is not supported on non-local systems.");
363 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
364 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
368 if (arg_pty
&& (with_timer() || arg_scope
)) {
369 log_error("--pty is not compatible in timer or --scope mode.");
373 if (arg_scope
&& with_timer()) {
374 log_error("Timer options are not supported in --scope mode.");
378 if (arg_timer_property
&& !with_timer()) {
379 log_error("--timer-property= has no effect without any other timer options.");
386 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
390 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
394 STRV_FOREACH(i
, properties
) {
395 r
= sd_bus_message_open_container(m
, 'r', "sv");
399 r
= bus_append_unit_property_assignment(m
, *i
);
403 r
= sd_bus_message_close_container(m
);
411 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
415 if (!isempty(arg_slice
)) {
416 _cleanup_free_
char *slice
;
418 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
422 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
430 static int transient_kill_set_properties(sd_bus_message
*m
) {
434 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
439 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
444 r
= transient_unit_set_properties(m
, arg_property
);
448 r
= transient_kill_set_properties(m
);
452 r
= transient_cgroup_set_properties(m
);
456 if (arg_remain_after_exit
) {
457 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
462 if (arg_service_type
) {
463 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
469 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
474 if (arg_exec_group
) {
475 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
481 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
489 r
= sd_bus_message_append(m
,
491 "StandardInput", "s", "tty",
492 "StandardOutput", "s", "tty",
493 "StandardError", "s", "tty",
494 "TTYPath", "s", pty_path
);
502 n
= strjoina("TERM=", e
);
503 r
= sd_bus_message_append(m
,
505 "Environment", "as", 1, n
);
511 if (!strv_isempty(arg_environment
)) {
512 r
= sd_bus_message_open_container(m
, 'r', "sv");
516 r
= sd_bus_message_append(m
, "s", "Environment");
520 r
= sd_bus_message_open_container(m
, 'v', "as");
524 r
= sd_bus_message_append_strv(m
, arg_environment
);
528 r
= sd_bus_message_close_container(m
);
532 r
= sd_bus_message_close_container(m
);
539 r
= sd_bus_message_open_container(m
, 'r', "sv");
543 r
= sd_bus_message_append(m
, "s", "ExecStart");
547 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
551 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
555 r
= sd_bus_message_open_container(m
, 'r', "sasb");
559 r
= sd_bus_message_append(m
, "s", argv
[0]);
563 r
= sd_bus_message_append_strv(m
, argv
);
567 r
= sd_bus_message_append(m
, "b", false);
571 r
= sd_bus_message_close_container(m
);
575 r
= sd_bus_message_close_container(m
);
579 r
= sd_bus_message_close_container(m
);
583 r
= sd_bus_message_close_container(m
);
591 static int transient_scope_set_properties(sd_bus_message
*m
) {
596 r
= transient_unit_set_properties(m
, arg_property
);
600 r
= transient_kill_set_properties(m
);
604 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
611 static int transient_timer_set_properties(sd_bus_message
*m
) {
616 r
= transient_unit_set_properties(m
, arg_timer_property
);
621 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
627 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
632 if (arg_on_startup
) {
633 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
638 if (arg_on_unit_active
) {
639 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
644 if (arg_on_unit_inactive
) {
645 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
650 if (arg_on_calendar
) {
651 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
659 static int start_transient_service(
663 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
664 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
665 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
666 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
667 _cleanup_close_
int master
= -1;
675 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
676 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
678 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
680 r
= ptsname_malloc(master
, &pty_path
);
682 return log_error_errno(r
, "Failed to determine tty name: %m");
684 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
685 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
688 r
= sd_bus_open_system(&system_bus
);
690 log_error_errno(r
, "Failed to connect to system bus: %m");
692 r
= sd_bus_call_method(system_bus
,
693 "org.freedesktop.machine1",
694 "/org/freedesktop/machine1",
695 "org.freedesktop.machine1.Manager",
701 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
705 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
707 return bus_log_parse_error(r
);
709 reply
= sd_bus_message_unref(reply
);
711 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
713 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
715 pty_path
= strdup(s
);
719 assert_not_reached("Can't allocate tty via ssh");
721 if (unlockpt(master
) < 0)
722 return log_error_errno(errno
, "Failed to unlock tty: %m");
726 r
= bus_wait_for_jobs_new(bus
, &w
);
728 return log_error_errno(r
, "Could not watch jobs: %m");
732 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
734 return log_error_errno(r
, "Failed to mangle unit name: %m");
735 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
738 r
= sd_bus_message_new_method_call(
741 "org.freedesktop.systemd1",
742 "/org/freedesktop/systemd1",
743 "org.freedesktop.systemd1.Manager",
744 "StartTransientUnit");
746 return bus_log_create_error(r
);
749 r
= sd_bus_message_append(m
, "ss", service
, "fail");
751 return bus_log_create_error(r
);
754 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
756 return bus_log_create_error(r
);
758 r
= transient_service_set_properties(m
, argv
, pty_path
);
760 return bus_log_create_error(r
);
762 r
= sd_bus_message_close_container(m
);
764 return bus_log_create_error(r
);
766 /* Auxiliary units */
767 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
769 return bus_log_create_error(r
);
771 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
773 log_error("Failed to start transient service unit: %s", bus_error_message(&error
, -r
));
780 r
= sd_bus_message_read(reply
, "o", &object
);
782 return bus_log_parse_error(r
);
784 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
790 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
791 _cleanup_event_unref_ sd_event
*event
= NULL
;
794 r
= sd_event_default(&event
);
796 return log_error_errno(r
, "Failed to get event loop: %m");
798 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
800 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
801 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
804 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
806 r
= pty_forward_new(event
, master
, false, false, &forward
);
808 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
810 r
= sd_event_loop(event
);
812 return log_error_errno(r
, "Failed to run event loop: %m");
814 pty_forward_get_last_char(forward
, &last_char
);
816 forward
= pty_forward_free(forward
);
818 if (!arg_quiet
&& last_char
!= '\n')
821 } else if (!arg_quiet
)
822 log_info("Running as unit %s.", service
);
827 static int start_transient_scope(
831 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
832 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
833 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
834 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
835 _cleanup_free_
char *scope
= NULL
;
836 const char *object
= NULL
;
842 r
= bus_wait_for_jobs_new(bus
, &w
);
847 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
849 return log_error_errno(r
, "Failed to mangle scope name: %m");
850 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
853 r
= sd_bus_message_new_method_call(
856 "org.freedesktop.systemd1",
857 "/org/freedesktop/systemd1",
858 "org.freedesktop.systemd1.Manager",
859 "StartTransientUnit");
861 return bus_log_create_error(r
);
864 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
866 return bus_log_create_error(r
);
869 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
871 return bus_log_create_error(r
);
873 r
= transient_scope_set_properties(m
);
875 return bus_log_create_error(r
);
877 r
= sd_bus_message_close_container(m
);
879 return bus_log_create_error(r
);
881 /* Auxiliary units */
882 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
884 return bus_log_create_error(r
);
886 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
888 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
893 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
894 return log_error_errno(errno
, "Failed to set nice level: %m");
897 if (arg_exec_group
) {
900 r
= get_group_creds(&arg_exec_group
, &gid
);
902 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
904 if (setresgid(gid
, gid
, gid
) < 0)
905 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
909 const char *home
, *shell
;
913 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
915 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
917 r
= strv_extendf(&user_env
, "HOME=%s", home
);
921 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
925 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
929 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
933 if (!arg_exec_group
) {
934 if (setresgid(gid
, gid
, gid
) < 0)
935 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
938 if (setresuid(uid
, uid
, uid
) < 0)
939 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
942 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
946 r
= sd_bus_message_read(reply
, "o", &object
);
948 return bus_log_parse_error(r
);
950 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
955 log_info("Running scope as unit %s.", scope
);
957 execvpe(argv
[0], argv
, env
);
959 return log_error_errno(errno
, "Failed to execute: %m");
962 static int start_transient_timer(
966 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
967 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
968 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
969 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
970 const char *object
= NULL
;
976 r
= bus_wait_for_jobs_new(bus
, &w
);
981 switch (unit_name_to_type(arg_unit
)) {
984 service
= strdup(arg_unit
);
988 r
= unit_name_change_suffix(service
, ".timer", &timer
);
990 return log_error_errno(r
, "Failed to change unit suffix: %m");
994 timer
= strdup(arg_unit
);
998 r
= unit_name_change_suffix(timer
, ".service", &service
);
1000 return log_error_errno(r
, "Failed to change unit suffix: %m");
1004 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1006 return log_error_errno(r
, "Failed to mangle unit name: %m");
1008 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1010 return log_error_errno(r
, "Failed to mangle unit name: %m");
1014 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1015 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1018 r
= sd_bus_message_new_method_call(
1021 "org.freedesktop.systemd1",
1022 "/org/freedesktop/systemd1",
1023 "org.freedesktop.systemd1.Manager",
1024 "StartTransientUnit");
1026 return bus_log_create_error(r
);
1029 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1031 return bus_log_create_error(r
);
1034 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1036 return bus_log_create_error(r
);
1038 r
= transient_timer_set_properties(m
);
1040 return bus_log_create_error(r
);
1042 r
= sd_bus_message_close_container(m
);
1044 return bus_log_create_error(r
);
1046 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1048 return bus_log_create_error(r
);
1051 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1053 return bus_log_create_error(r
);
1055 r
= sd_bus_message_append(m
, "s", service
);
1057 return bus_log_create_error(r
);
1059 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1061 return bus_log_create_error(r
);
1063 r
= transient_service_set_properties(m
, argv
, NULL
);
1065 return bus_log_create_error(r
);
1067 r
= sd_bus_message_close_container(m
);
1069 return bus_log_create_error(r
);
1071 r
= sd_bus_message_close_container(m
);
1073 return bus_log_create_error(r
);
1076 r
= sd_bus_message_close_container(m
);
1078 return bus_log_create_error(r
);
1080 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1082 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1086 r
= sd_bus_message_read(reply
, "o", &object
);
1088 return bus_log_parse_error(r
);
1090 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1094 log_info("Running timer as unit %s.", timer
);
1096 log_info("Will run service as unit %s.", service
);
1101 int main(int argc
, char* argv
[]) {
1102 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1103 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1106 log_parse_environment();
1109 r
= parse_argv(argc
, argv
);
1113 if (argc
> optind
) {
1114 r
= find_binary(argv
[optind
], arg_transport
== BUS_TRANSPORT_LOCAL
, &command
);
1116 log_error_errno(r
, "Failed to find executable %s%s: %m",
1118 arg_transport
== BUS_TRANSPORT_LOCAL
? "" : " on local system");
1121 argv
[optind
] = command
;
1124 if (!arg_description
) {
1125 description
= strv_join(argv
+ optind
, " ");
1131 if (arg_unit
&& isempty(description
)) {
1132 r
= free_and_strdup(&description
, arg_unit
);
1137 arg_description
= description
;
1140 r
= bus_open_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1142 log_error_errno(r
, "Failed to create bus connection: %m");
1147 r
= start_transient_scope(bus
, argv
+ optind
);
1148 else if (with_timer())
1149 r
= start_transient_timer(bus
, argv
+ optind
);
1151 r
= start_transient_service(bus
, argv
+ optind
);
1154 strv_free(arg_environment
);
1155 strv_free(arg_property
);
1156 strv_free(arg_timer_property
);
1158 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;