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 ommited.\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
;
795 r
= sd_event_default(&event
);
797 return log_error_errno(r
, "Failed to get event loop: %m");
799 assert_se(sigemptyset(&mask
) == 0);
800 sigset_add_many(&mask
, SIGWINCH
, SIGTERM
, SIGINT
, -1);
801 assert_se(sigprocmask(SIG_BLOCK
, &mask
, NULL
) == 0);
803 sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
804 sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
807 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
809 r
= pty_forward_new(event
, master
, false, false, &forward
);
811 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
813 r
= sd_event_loop(event
);
815 return log_error_errno(r
, "Failed to run event loop: %m");
817 pty_forward_get_last_char(forward
, &last_char
);
819 forward
= pty_forward_free(forward
);
821 if (!arg_quiet
&& last_char
!= '\n')
824 } else if (!arg_quiet
)
825 log_info("Running as unit %s.", service
);
830 static int start_transient_scope(
834 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
835 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
836 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
837 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
838 _cleanup_free_
char *scope
= NULL
;
839 const char *object
= NULL
;
845 r
= bus_wait_for_jobs_new(bus
, &w
);
850 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
852 return log_error_errno(r
, "Failed to mangle scope name: %m");
853 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
856 r
= sd_bus_message_new_method_call(
859 "org.freedesktop.systemd1",
860 "/org/freedesktop/systemd1",
861 "org.freedesktop.systemd1.Manager",
862 "StartTransientUnit");
864 return bus_log_create_error(r
);
867 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
869 return bus_log_create_error(r
);
872 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
874 return bus_log_create_error(r
);
876 r
= transient_scope_set_properties(m
);
878 return bus_log_create_error(r
);
880 r
= sd_bus_message_close_container(m
);
882 return bus_log_create_error(r
);
884 /* Auxiliary units */
885 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
887 return bus_log_create_error(r
);
889 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
891 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
896 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
897 return log_error_errno(errno
, "Failed to set nice level: %m");
900 if (arg_exec_group
) {
903 r
= get_group_creds(&arg_exec_group
, &gid
);
905 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
907 if (setresgid(gid
, gid
, gid
) < 0)
908 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
912 const char *home
, *shell
;
916 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
918 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
920 r
= strv_extendf(&user_env
, "HOME=%s", home
);
924 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
928 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
932 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
936 if (!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
);
941 if (setresuid(uid
, uid
, uid
) < 0)
942 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
945 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
949 r
= sd_bus_message_read(reply
, "o", &object
);
951 return bus_log_parse_error(r
);
953 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
958 log_info("Running scope as unit %s.", scope
);
960 execvpe(argv
[0], argv
, env
);
962 return log_error_errno(errno
, "Failed to execute: %m");
965 static int start_transient_timer(
969 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
970 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
971 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
972 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
973 const char *object
= NULL
;
979 r
= bus_wait_for_jobs_new(bus
, &w
);
984 switch (unit_name_to_type(arg_unit
)) {
987 service
= strdup(arg_unit
);
991 r
= unit_name_change_suffix(service
, ".timer", &timer
);
993 return log_error_errno(r
, "Failed to change unit suffix: %m");
997 timer
= strdup(arg_unit
);
1001 r
= unit_name_change_suffix(timer
, ".service", &service
);
1003 return log_error_errno(r
, "Failed to change unit suffix: %m");
1007 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1009 return log_error_errno(r
, "Failed to mangle unit name: %m");
1011 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1013 return log_error_errno(r
, "Failed to mangle unit name: %m");
1017 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1018 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1021 r
= sd_bus_message_new_method_call(
1024 "org.freedesktop.systemd1",
1025 "/org/freedesktop/systemd1",
1026 "org.freedesktop.systemd1.Manager",
1027 "StartTransientUnit");
1029 return bus_log_create_error(r
);
1032 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1034 return bus_log_create_error(r
);
1037 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1039 return bus_log_create_error(r
);
1041 r
= transient_timer_set_properties(m
);
1043 return bus_log_create_error(r
);
1045 r
= sd_bus_message_close_container(m
);
1047 return bus_log_create_error(r
);
1049 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1051 return bus_log_create_error(r
);
1054 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1056 return bus_log_create_error(r
);
1058 r
= sd_bus_message_append(m
, "s", service
);
1060 return bus_log_create_error(r
);
1062 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1064 return bus_log_create_error(r
);
1066 r
= transient_service_set_properties(m
, argv
, NULL
);
1068 return bus_log_create_error(r
);
1070 r
= sd_bus_message_close_container(m
);
1072 return bus_log_create_error(r
);
1074 r
= sd_bus_message_close_container(m
);
1076 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_call(bus
, m
, 0, &error
, &reply
);
1085 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1089 r
= sd_bus_message_read(reply
, "o", &object
);
1091 return bus_log_parse_error(r
);
1093 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1097 log_info("Running timer as unit %s.", timer
);
1099 log_info("Will run service as unit %s.", service
);
1104 int main(int argc
, char* argv
[]) {
1105 _cleanup_bus_close_unref_ sd_bus
*bus
= NULL
;
1106 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1109 log_parse_environment();
1112 r
= parse_argv(argc
, argv
);
1116 if (argc
> optind
) {
1117 r
= find_binary(argv
[optind
], arg_transport
== BUS_TRANSPORT_LOCAL
, &command
);
1119 log_error_errno(r
, "Failed to find executable %s%s: %m",
1121 arg_transport
== BUS_TRANSPORT_LOCAL
? "" : " on local system");
1124 argv
[optind
] = command
;
1127 if (!arg_description
) {
1128 description
= strv_join(argv
+ optind
, " ");
1134 if (arg_unit
&& isempty(description
)) {
1136 description
= strdup(arg_unit
);
1144 arg_description
= description
;
1147 r
= bus_open_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1149 log_error_errno(r
, "Failed to create bus connection: %m");
1154 r
= start_transient_scope(bus
, argv
+ optind
);
1155 else if (with_timer())
1156 r
= start_transient_timer(bus
, argv
+ optind
);
1158 r
= start_transient_service(bus
, argv
+ optind
);
1161 strv_free(arg_environment
);
1162 strv_free(arg_property
);
1163 strv_free(arg_timer_property
);
1165 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;