1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "bus-error.h"
30 #include "calendarspec.h"
32 #include "event-util.h"
33 #include "formats-util.h"
34 #include "path-util.h"
36 #include "signal-util.h"
37 #include "spawn-polkit-agent.h"
39 #include "terminal-util.h"
40 #include "unit-name.h"
42 static bool arg_ask_password
= true;
43 static bool arg_scope
= false;
44 static bool arg_remain_after_exit
= false;
45 static bool arg_no_block
= false;
46 static const char *arg_unit
= NULL
;
47 static const char *arg_description
= NULL
;
48 static const char *arg_slice
= NULL
;
49 static bool arg_send_sighup
= false;
50 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
51 static const char *arg_host
= NULL
;
52 static bool arg_user
= false;
53 static const char *arg_service_type
= NULL
;
54 static const char *arg_exec_user
= NULL
;
55 static const char *arg_exec_group
= NULL
;
56 static int arg_nice
= 0;
57 static bool arg_nice_set
= false;
58 static char **arg_environment
= NULL
;
59 static char **arg_property
= NULL
;
60 static bool arg_pty
= false;
61 static usec_t arg_on_active
= 0;
62 static usec_t arg_on_boot
= 0;
63 static usec_t arg_on_startup
= 0;
64 static usec_t arg_on_unit_active
= 0;
65 static usec_t arg_on_unit_inactive
= 0;
66 static const char *arg_on_calendar
= NULL
;
67 static char **arg_timer_property
= NULL
;
68 static bool arg_quiet
= false;
70 static void polkit_agent_open_if_enabled(void) {
72 /* Open the polkit agent as a child process if necessary */
73 if (!arg_ask_password
)
76 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
82 static void help(void) {
83 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
84 "Run the specified command in a transient scope or service or timer\n"
85 "unit. If timer option is specified and unit is exist which is\n"
86 "specified with --unit option then command can be omitted.\n\n"
87 " -h --help Show this help\n"
88 " --version Show package version\n"
89 " --no-ask-password Do not prompt for password\n"
90 " --user Run as user unit\n"
91 " -H --host=[USER@]HOST Operate on remote host\n"
92 " -M --machine=CONTAINER Operate on local container\n"
93 " --scope Run this as scope rather than service\n"
94 " --unit=UNIT Run under the specified unit name\n"
95 " -p --property=NAME=VALUE Set unit property\n"
96 " --description=TEXT Description for unit\n"
97 " --slice=SLICE Run in the specified slice\n"
98 " --no-block Do not wait until operation finished\n"
99 " -r --remain-after-exit Leave service around until explicitly stopped\n"
100 " --send-sighup Send SIGHUP when terminating\n"
101 " --service-type=TYPE Service type\n"
102 " --uid=USER Run as system user\n"
103 " --gid=GROUP Run as system group\n"
104 " --nice=NICE Nice level\n"
105 " --setenv=NAME=VALUE Set environment\n"
106 " -t --pty Run service on pseudo tty\n"
107 " -q --quiet Suppress information messages during runtime\n\n"
109 " --on-active=SECONDS Run after SECONDS delay\n"
110 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
111 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
112 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
113 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
114 " --on-calendar=SPEC Realtime timer\n"
115 " --timer-property=NAME=VALUE Set timer unit property\n",
116 program_invocation_short_name
);
119 static bool with_timer(void) {
120 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
123 static int parse_argv(int argc
, char *argv
[]) {
145 ARG_ON_UNIT_INACTIVE
,
151 static const struct option options
[] = {
152 { "help", no_argument
, NULL
, 'h' },
153 { "version", no_argument
, NULL
, ARG_VERSION
},
154 { "user", no_argument
, NULL
, ARG_USER
},
155 { "system", no_argument
, NULL
, ARG_SYSTEM
},
156 { "scope", no_argument
, NULL
, ARG_SCOPE
},
157 { "unit", required_argument
, NULL
, ARG_UNIT
},
158 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
159 { "slice", required_argument
, NULL
, ARG_SLICE
},
160 { "remain-after-exit", no_argument
, NULL
, 'r' },
161 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
162 { "host", required_argument
, NULL
, 'H' },
163 { "machine", required_argument
, NULL
, 'M' },
164 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
165 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
166 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
167 { "nice", required_argument
, NULL
, ARG_NICE
},
168 { "setenv", required_argument
, NULL
, ARG_SETENV
},
169 { "property", required_argument
, NULL
, 'p' },
170 { "tty", no_argument
, NULL
, 't' },
171 { "quiet", no_argument
, NULL
, 'q' },
172 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
173 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
174 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
175 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
176 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
177 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
178 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
179 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
180 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
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
: {
339 CalendarSpec
*spec
= NULL
;
341 r
= calendar_spec_from_string(optarg
, &spec
);
343 log_error("Invalid calendar spec: %s", optarg
);
347 calendar_spec_free(spec
);
348 arg_on_calendar
= optarg
;
352 case ARG_TIMER_PROPERTY
:
354 if (strv_extend(&arg_timer_property
, optarg
) < 0)
367 assert_not_reached("Unhandled option");
370 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
371 log_error("Command line to execute required.");
375 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
376 log_error("Execution in user context is not supported on non-local systems.");
380 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
381 log_error("Scope execution is not supported on non-local systems.");
385 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
386 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
390 if (arg_pty
&& (with_timer() || arg_scope
)) {
391 log_error("--pty is not compatible in timer or --scope mode.");
395 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
396 log_error("--pty is only supported when connecting to the local system or containers.");
400 if (arg_scope
&& with_timer()) {
401 log_error("Timer options are not supported in --scope mode.");
405 if (arg_timer_property
&& !with_timer()) {
406 log_error("--timer-property= has no effect without any other timer options.");
413 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
417 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
421 STRV_FOREACH(i
, properties
) {
422 r
= sd_bus_message_open_container(m
, 'r', "sv");
426 r
= bus_append_unit_property_assignment(m
, *i
);
430 r
= sd_bus_message_close_container(m
);
438 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
442 if (!isempty(arg_slice
)) {
443 _cleanup_free_
char *slice
;
445 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
449 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
457 static int transient_kill_set_properties(sd_bus_message
*m
) {
461 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
466 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
471 r
= transient_unit_set_properties(m
, arg_property
);
475 r
= transient_kill_set_properties(m
);
479 r
= transient_cgroup_set_properties(m
);
483 if (arg_remain_after_exit
) {
484 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
489 if (arg_service_type
) {
490 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
496 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
501 if (arg_exec_group
) {
502 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
508 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
516 r
= sd_bus_message_append(m
,
518 "StandardInput", "s", "tty",
519 "StandardOutput", "s", "tty",
520 "StandardError", "s", "tty",
521 "TTYPath", "s", pty_path
);
529 n
= strjoina("TERM=", e
);
530 r
= sd_bus_message_append(m
,
532 "Environment", "as", 1, n
);
538 if (!strv_isempty(arg_environment
)) {
539 r
= sd_bus_message_open_container(m
, 'r', "sv");
543 r
= sd_bus_message_append(m
, "s", "Environment");
547 r
= sd_bus_message_open_container(m
, 'v', "as");
551 r
= sd_bus_message_append_strv(m
, arg_environment
);
555 r
= sd_bus_message_close_container(m
);
559 r
= sd_bus_message_close_container(m
);
566 r
= sd_bus_message_open_container(m
, 'r', "sv");
570 r
= sd_bus_message_append(m
, "s", "ExecStart");
574 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
578 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
582 r
= sd_bus_message_open_container(m
, 'r', "sasb");
586 r
= sd_bus_message_append(m
, "s", argv
[0]);
590 r
= sd_bus_message_append_strv(m
, argv
);
594 r
= sd_bus_message_append(m
, "b", false);
598 r
= sd_bus_message_close_container(m
);
602 r
= sd_bus_message_close_container(m
);
606 r
= sd_bus_message_close_container(m
);
610 r
= sd_bus_message_close_container(m
);
618 static int transient_scope_set_properties(sd_bus_message
*m
) {
623 r
= transient_unit_set_properties(m
, arg_property
);
627 r
= transient_kill_set_properties(m
);
631 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
638 static int transient_timer_set_properties(sd_bus_message
*m
) {
643 r
= transient_unit_set_properties(m
, arg_timer_property
);
648 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
654 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
659 if (arg_on_startup
) {
660 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
665 if (arg_on_unit_active
) {
666 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
671 if (arg_on_unit_inactive
) {
672 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
677 if (arg_on_calendar
) {
678 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
686 static int start_transient_service(
690 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
691 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
692 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
693 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
694 _cleanup_close_
int master
= -1;
702 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
703 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
705 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
707 r
= ptsname_malloc(master
, &pty_path
);
709 return log_error_errno(r
, "Failed to determine tty name: %m");
711 if (unlockpt(master
) < 0)
712 return log_error_errno(errno
, "Failed to unlock tty: %m");
714 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
715 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
718 r
= sd_bus_default_system(&system_bus
);
720 return log_error_errno(r
, "Failed to connect to system bus: %m");
722 r
= sd_bus_call_method(system_bus
,
723 "org.freedesktop.machine1",
724 "/org/freedesktop/machine1",
725 "org.freedesktop.machine1.Manager",
731 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
735 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
737 return bus_log_parse_error(r
);
739 reply
= sd_bus_message_unref(reply
);
741 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
743 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
745 pty_path
= strdup(s
);
749 assert_not_reached("Can't allocate tty via ssh");
753 r
= bus_wait_for_jobs_new(bus
, &w
);
755 return log_error_errno(r
, "Could not watch jobs: %m");
759 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
761 return log_error_errno(r
, "Failed to mangle unit name: %m");
762 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
765 r
= sd_bus_message_new_method_call(
768 "org.freedesktop.systemd1",
769 "/org/freedesktop/systemd1",
770 "org.freedesktop.systemd1.Manager",
771 "StartTransientUnit");
773 return bus_log_create_error(r
);
775 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
777 return bus_log_create_error(r
);
780 r
= sd_bus_message_append(m
, "ss", service
, "fail");
782 return bus_log_create_error(r
);
785 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
787 return bus_log_create_error(r
);
789 r
= transient_service_set_properties(m
, argv
, pty_path
);
791 return bus_log_create_error(r
);
793 r
= sd_bus_message_close_container(m
);
795 return bus_log_create_error(r
);
797 /* Auxiliary units */
798 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
800 return bus_log_create_error(r
);
802 polkit_agent_open_if_enabled();
804 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
806 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
811 r
= sd_bus_message_read(reply
, "o", &object
);
813 return bus_log_parse_error(r
);
815 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
821 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
822 _cleanup_event_unref_ sd_event
*event
= NULL
;
825 r
= sd_event_default(&event
);
827 return log_error_errno(r
, "Failed to get event loop: %m");
829 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
831 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
832 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
835 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
837 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
839 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
841 r
= sd_event_loop(event
);
843 return log_error_errno(r
, "Failed to run event loop: %m");
845 pty_forward_get_last_char(forward
, &last_char
);
847 forward
= pty_forward_free(forward
);
849 if (!arg_quiet
&& last_char
!= '\n')
852 } else if (!arg_quiet
)
853 log_info("Running as unit %s.", service
);
858 static int start_transient_scope(
862 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
863 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
864 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
865 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
866 _cleanup_free_
char *scope
= NULL
;
867 const char *object
= NULL
;
873 r
= bus_wait_for_jobs_new(bus
, &w
);
878 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
880 return log_error_errno(r
, "Failed to mangle scope name: %m");
881 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
884 r
= sd_bus_message_new_method_call(
887 "org.freedesktop.systemd1",
888 "/org/freedesktop/systemd1",
889 "org.freedesktop.systemd1.Manager",
890 "StartTransientUnit");
892 return bus_log_create_error(r
);
894 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
896 return bus_log_create_error(r
);
899 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
901 return bus_log_create_error(r
);
904 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
906 return bus_log_create_error(r
);
908 r
= transient_scope_set_properties(m
);
910 return bus_log_create_error(r
);
912 r
= sd_bus_message_close_container(m
);
914 return bus_log_create_error(r
);
916 /* Auxiliary units */
917 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
919 return bus_log_create_error(r
);
921 polkit_agent_open_if_enabled();
923 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
925 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
930 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
931 return log_error_errno(errno
, "Failed to set nice level: %m");
934 if (arg_exec_group
) {
937 r
= get_group_creds(&arg_exec_group
, &gid
);
939 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
941 if (setresgid(gid
, gid
, gid
) < 0)
942 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
946 const char *home
, *shell
;
950 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
952 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
954 r
= strv_extendf(&user_env
, "HOME=%s", home
);
958 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
962 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
966 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
970 if (!arg_exec_group
) {
971 if (setresgid(gid
, gid
, gid
) < 0)
972 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
975 if (setresuid(uid
, uid
, uid
) < 0)
976 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
979 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
983 r
= sd_bus_message_read(reply
, "o", &object
);
985 return bus_log_parse_error(r
);
987 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
992 log_info("Running scope as unit %s.", scope
);
994 execvpe(argv
[0], argv
, env
);
996 return log_error_errno(errno
, "Failed to execute: %m");
999 static int start_transient_timer(
1003 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1004 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1005 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1006 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1007 const char *object
= NULL
;
1013 r
= bus_wait_for_jobs_new(bus
, &w
);
1018 switch (unit_name_to_type(arg_unit
)) {
1021 service
= strdup(arg_unit
);
1025 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1027 return log_error_errno(r
, "Failed to change unit suffix: %m");
1031 timer
= strdup(arg_unit
);
1035 r
= unit_name_change_suffix(timer
, ".service", &service
);
1037 return log_error_errno(r
, "Failed to change unit suffix: %m");
1041 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1043 return log_error_errno(r
, "Failed to mangle unit name: %m");
1045 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1047 return log_error_errno(r
, "Failed to mangle unit name: %m");
1051 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1052 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1055 r
= sd_bus_message_new_method_call(
1058 "org.freedesktop.systemd1",
1059 "/org/freedesktop/systemd1",
1060 "org.freedesktop.systemd1.Manager",
1061 "StartTransientUnit");
1063 return bus_log_create_error(r
);
1065 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1067 return bus_log_create_error(r
);
1070 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1072 return bus_log_create_error(r
);
1075 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1077 return bus_log_create_error(r
);
1079 r
= transient_timer_set_properties(m
);
1081 return bus_log_create_error(r
);
1083 r
= sd_bus_message_close_container(m
);
1085 return bus_log_create_error(r
);
1087 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1089 return bus_log_create_error(r
);
1092 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1094 return bus_log_create_error(r
);
1096 r
= sd_bus_message_append(m
, "s", service
);
1098 return bus_log_create_error(r
);
1100 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1102 return bus_log_create_error(r
);
1104 r
= transient_service_set_properties(m
, argv
, NULL
);
1106 return bus_log_create_error(r
);
1108 r
= sd_bus_message_close_container(m
);
1110 return bus_log_create_error(r
);
1112 r
= sd_bus_message_close_container(m
);
1114 return bus_log_create_error(r
);
1117 r
= sd_bus_message_close_container(m
);
1119 return bus_log_create_error(r
);
1121 polkit_agent_open_if_enabled();
1123 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1125 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1129 r
= sd_bus_message_read(reply
, "o", &object
);
1131 return bus_log_parse_error(r
);
1133 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1137 log_info("Running timer as unit %s.", timer
);
1139 log_info("Will run service as unit %s.", service
);
1144 int main(int argc
, char* argv
[]) {
1145 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1146 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1149 log_parse_environment();
1152 r
= parse_argv(argc
, argv
);
1156 if (argc
> optind
) {
1157 r
= find_binary(argv
[optind
], arg_transport
== BUS_TRANSPORT_LOCAL
, &command
);
1159 log_error_errno(r
, "Failed to find executable %s%s: %m",
1161 arg_transport
== BUS_TRANSPORT_LOCAL
? "" : " on local system");
1164 argv
[optind
] = command
;
1167 if (!arg_description
) {
1168 description
= strv_join(argv
+ optind
, " ");
1174 if (arg_unit
&& isempty(description
)) {
1175 r
= free_and_strdup(&description
, arg_unit
);
1180 arg_description
= description
;
1183 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1185 log_error_errno(r
, "Failed to create bus connection: %m");
1190 r
= start_transient_scope(bus
, argv
+ optind
);
1191 else if (with_timer())
1192 r
= start_transient_timer(bus
, argv
+ optind
);
1194 r
= start_transient_service(bus
, argv
+ optind
);
1197 strv_free(arg_environment
);
1198 strv_free(arg_property
);
1199 strv_free(arg_timer_property
);
1201 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;