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 "alloc-util.h"
29 #include "bus-error.h"
31 #include "calendarspec.h"
33 #include "event-util.h"
35 #include "formats-util.h"
36 #include "path-util.h"
38 #include "signal-util.h"
39 #include "spawn-polkit-agent.h"
41 #include "terminal-util.h"
42 #include "unit-name.h"
43 #include "user-util.h"
44 #include "parse-util.h"
46 static bool arg_ask_password
= true;
47 static bool arg_scope
= false;
48 static bool arg_remain_after_exit
= false;
49 static bool arg_no_block
= false;
50 static const char *arg_unit
= NULL
;
51 static const char *arg_description
= NULL
;
52 static const char *arg_slice
= NULL
;
53 static bool arg_send_sighup
= false;
54 static BusTransport arg_transport
= BUS_TRANSPORT_LOCAL
;
55 static const char *arg_host
= NULL
;
56 static bool arg_user
= false;
57 static const char *arg_service_type
= NULL
;
58 static const char *arg_exec_user
= NULL
;
59 static const char *arg_exec_group
= NULL
;
60 static int arg_nice
= 0;
61 static bool arg_nice_set
= false;
62 static char **arg_environment
= NULL
;
63 static char **arg_property
= NULL
;
64 static bool arg_pty
= false;
65 static usec_t arg_on_active
= 0;
66 static usec_t arg_on_boot
= 0;
67 static usec_t arg_on_startup
= 0;
68 static usec_t arg_on_unit_active
= 0;
69 static usec_t arg_on_unit_inactive
= 0;
70 static const char *arg_on_calendar
= NULL
;
71 static char **arg_timer_property
= NULL
;
72 static bool arg_quiet
= false;
74 static void polkit_agent_open_if_enabled(void) {
76 /* Open the polkit agent as a child process if necessary */
77 if (!arg_ask_password
)
80 if (arg_transport
!= BUS_TRANSPORT_LOCAL
)
86 static void help(void) {
87 printf("%s [OPTIONS...] {COMMAND} [ARGS...]\n\n"
88 "Run the specified command in a transient scope or service or timer\n"
89 "unit. If timer option is specified and unit is exist which is\n"
90 "specified with --unit option then command can be omitted.\n\n"
91 " -h --help Show this help\n"
92 " --version Show package version\n"
93 " --no-ask-password Do not prompt for password\n"
94 " --user Run as user unit\n"
95 " -H --host=[USER@]HOST Operate on remote host\n"
96 " -M --machine=CONTAINER Operate on local container\n"
97 " --scope Run this as scope rather than service\n"
98 " --unit=UNIT Run under the specified unit name\n"
99 " -p --property=NAME=VALUE Set unit property\n"
100 " --description=TEXT Description for unit\n"
101 " --slice=SLICE Run in the specified slice\n"
102 " --no-block Do not wait until operation finished\n"
103 " -r --remain-after-exit Leave service around until explicitly stopped\n"
104 " --send-sighup Send SIGHUP when terminating\n"
105 " --service-type=TYPE Service type\n"
106 " --uid=USER Run as system user\n"
107 " --gid=GROUP Run as system group\n"
108 " --nice=NICE Nice level\n"
109 " --setenv=NAME=VALUE Set environment\n"
110 " -t --pty Run service on pseudo tty\n"
111 " -q --quiet Suppress information messages during runtime\n\n"
113 " --on-active=SECONDS Run after SECONDS delay\n"
114 " --on-boot=SECONDS Run SECONDS after machine was booted up\n"
115 " --on-startup=SECONDS Run SECONDS after systemd activation\n"
116 " --on-unit-active=SECONDS Run SECONDS after the last activation\n"
117 " --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
118 " --on-calendar=SPEC Realtime timer\n"
119 " --timer-property=NAME=VALUE Set timer unit property\n",
120 program_invocation_short_name
);
123 static bool with_timer(void) {
124 return arg_on_active
|| arg_on_boot
|| arg_on_startup
|| arg_on_unit_active
|| arg_on_unit_inactive
|| arg_on_calendar
;
127 static int parse_argv(int argc
, char *argv
[]) {
149 ARG_ON_UNIT_INACTIVE
,
155 static const struct option options
[] = {
156 { "help", no_argument
, NULL
, 'h' },
157 { "version", no_argument
, NULL
, ARG_VERSION
},
158 { "user", no_argument
, NULL
, ARG_USER
},
159 { "system", no_argument
, NULL
, ARG_SYSTEM
},
160 { "scope", no_argument
, NULL
, ARG_SCOPE
},
161 { "unit", required_argument
, NULL
, ARG_UNIT
},
162 { "description", required_argument
, NULL
, ARG_DESCRIPTION
},
163 { "slice", required_argument
, NULL
, ARG_SLICE
},
164 { "remain-after-exit", no_argument
, NULL
, 'r' },
165 { "send-sighup", no_argument
, NULL
, ARG_SEND_SIGHUP
},
166 { "host", required_argument
, NULL
, 'H' },
167 { "machine", required_argument
, NULL
, 'M' },
168 { "service-type", required_argument
, NULL
, ARG_SERVICE_TYPE
},
169 { "uid", required_argument
, NULL
, ARG_EXEC_USER
},
170 { "gid", required_argument
, NULL
, ARG_EXEC_GROUP
},
171 { "nice", required_argument
, NULL
, ARG_NICE
},
172 { "setenv", required_argument
, NULL
, ARG_SETENV
},
173 { "property", required_argument
, NULL
, 'p' },
174 { "tty", no_argument
, NULL
, 't' },
175 { "quiet", no_argument
, NULL
, 'q' },
176 { "on-active", required_argument
, NULL
, ARG_ON_ACTIVE
},
177 { "on-boot", required_argument
, NULL
, ARG_ON_BOOT
},
178 { "on-startup", required_argument
, NULL
, ARG_ON_STARTUP
},
179 { "on-unit-active", required_argument
, NULL
, ARG_ON_UNIT_ACTIVE
},
180 { "on-unit-inactive", required_argument
, NULL
, ARG_ON_UNIT_INACTIVE
},
181 { "on-calendar", required_argument
, NULL
, ARG_ON_CALENDAR
},
182 { "timer-property", required_argument
, NULL
, ARG_TIMER_PROPERTY
},
183 { "no-block", no_argument
, NULL
, ARG_NO_BLOCK
},
184 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
193 while ((c
= getopt_long(argc
, argv
, "+hrH:M:p:tq", options
, NULL
)) >= 0)
201 case ARG_NO_ASK_PASSWORD
:
202 arg_ask_password
= false;
224 case ARG_DESCRIPTION
:
225 arg_description
= optarg
;
232 case ARG_SEND_SIGHUP
:
233 arg_send_sighup
= true;
237 arg_remain_after_exit
= true;
241 arg_transport
= BUS_TRANSPORT_REMOTE
;
246 arg_transport
= BUS_TRANSPORT_MACHINE
;
250 case ARG_SERVICE_TYPE
:
251 arg_service_type
= optarg
;
255 arg_exec_user
= optarg
;
259 arg_exec_group
= optarg
;
263 r
= safe_atoi(optarg
, &arg_nice
);
264 if (r
< 0 || arg_nice
< PRIO_MIN
|| arg_nice
>= PRIO_MAX
) {
265 log_error("Failed to parse nice value");
273 if (strv_extend(&arg_environment
, optarg
) < 0)
279 if (strv_extend(&arg_property
, optarg
) < 0)
294 r
= parse_sec(optarg
, &arg_on_active
);
296 log_error("Failed to parse timer value: %s", optarg
);
304 r
= parse_sec(optarg
, &arg_on_boot
);
306 log_error("Failed to parse timer value: %s", optarg
);
314 r
= parse_sec(optarg
, &arg_on_startup
);
316 log_error("Failed to parse timer value: %s", optarg
);
322 case ARG_ON_UNIT_ACTIVE
:
324 r
= parse_sec(optarg
, &arg_on_unit_active
);
326 log_error("Failed to parse timer value: %s", optarg
);
332 case ARG_ON_UNIT_INACTIVE
:
334 r
= parse_sec(optarg
, &arg_on_unit_inactive
);
336 log_error("Failed to parse timer value: %s", optarg
);
342 case ARG_ON_CALENDAR
: {
343 CalendarSpec
*spec
= NULL
;
345 r
= calendar_spec_from_string(optarg
, &spec
);
347 log_error("Invalid calendar spec: %s", optarg
);
351 calendar_spec_free(spec
);
352 arg_on_calendar
= optarg
;
356 case ARG_TIMER_PROPERTY
:
358 if (strv_extend(&arg_timer_property
, optarg
) < 0)
371 assert_not_reached("Unhandled option");
374 if ((optind
>= argc
) && (!arg_unit
|| !with_timer())) {
375 log_error("Command line to execute required.");
379 if (arg_user
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
380 log_error("Execution in user context is not supported on non-local systems.");
384 if (arg_scope
&& arg_transport
!= BUS_TRANSPORT_LOCAL
) {
385 log_error("Scope execution is not supported on non-local systems.");
389 if (arg_scope
&& (arg_remain_after_exit
|| arg_service_type
)) {
390 log_error("--remain-after-exit and --service-type= are not supported in --scope mode.");
394 if (arg_pty
&& (with_timer() || arg_scope
)) {
395 log_error("--pty is not compatible in timer or --scope mode.");
399 if (arg_pty
&& arg_transport
== BUS_TRANSPORT_REMOTE
) {
400 log_error("--pty is only supported when connecting to the local system or containers.");
404 if (arg_scope
&& with_timer()) {
405 log_error("Timer options are not supported in --scope mode.");
409 if (arg_timer_property
&& !with_timer()) {
410 log_error("--timer-property= has no effect without any other timer options.");
417 static int transient_unit_set_properties(sd_bus_message
*m
, char **properties
) {
421 r
= sd_bus_message_append(m
, "(sv)", "Description", "s", arg_description
);
425 STRV_FOREACH(i
, properties
) {
426 r
= sd_bus_message_open_container(m
, 'r', "sv");
430 r
= bus_append_unit_property_assignment(m
, *i
);
434 r
= sd_bus_message_close_container(m
);
442 static int transient_cgroup_set_properties(sd_bus_message
*m
) {
446 if (!isempty(arg_slice
)) {
447 _cleanup_free_
char *slice
;
449 r
= unit_name_mangle_with_suffix(arg_slice
, UNIT_NAME_NOGLOB
, ".slice", &slice
);
453 r
= sd_bus_message_append(m
, "(sv)", "Slice", "s", slice
);
461 static int transient_kill_set_properties(sd_bus_message
*m
) {
465 return sd_bus_message_append(m
, "(sv)", "SendSIGHUP", "b", arg_send_sighup
);
470 static int transient_service_set_properties(sd_bus_message
*m
, char **argv
, const char *pty_path
) {
475 r
= transient_unit_set_properties(m
, arg_property
);
479 r
= transient_kill_set_properties(m
);
483 r
= transient_cgroup_set_properties(m
);
487 if (arg_remain_after_exit
) {
488 r
= sd_bus_message_append(m
, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit
);
493 if (arg_service_type
) {
494 r
= sd_bus_message_append(m
, "(sv)", "Type", "s", arg_service_type
);
500 r
= sd_bus_message_append(m
, "(sv)", "User", "s", arg_exec_user
);
505 if (arg_exec_group
) {
506 r
= sd_bus_message_append(m
, "(sv)", "Group", "s", arg_exec_group
);
512 r
= sd_bus_message_append(m
, "(sv)", "Nice", "i", arg_nice
);
520 r
= sd_bus_message_append(m
,
522 "StandardInput", "s", "tty",
523 "StandardOutput", "s", "tty",
524 "StandardError", "s", "tty",
525 "TTYPath", "s", pty_path
);
533 n
= strjoina("TERM=", e
);
534 r
= sd_bus_message_append(m
,
536 "Environment", "as", 1, n
);
542 if (!strv_isempty(arg_environment
)) {
543 r
= sd_bus_message_open_container(m
, 'r', "sv");
547 r
= sd_bus_message_append(m
, "s", "Environment");
551 r
= sd_bus_message_open_container(m
, 'v', "as");
555 r
= sd_bus_message_append_strv(m
, arg_environment
);
559 r
= sd_bus_message_close_container(m
);
563 r
= sd_bus_message_close_container(m
);
570 r
= sd_bus_message_open_container(m
, 'r', "sv");
574 r
= sd_bus_message_append(m
, "s", "ExecStart");
578 r
= sd_bus_message_open_container(m
, 'v', "a(sasb)");
582 r
= sd_bus_message_open_container(m
, 'a', "(sasb)");
586 r
= sd_bus_message_open_container(m
, 'r', "sasb");
590 r
= sd_bus_message_append(m
, "s", argv
[0]);
594 r
= sd_bus_message_append_strv(m
, argv
);
598 r
= sd_bus_message_append(m
, "b", false);
602 r
= sd_bus_message_close_container(m
);
606 r
= sd_bus_message_close_container(m
);
610 r
= sd_bus_message_close_container(m
);
614 r
= sd_bus_message_close_container(m
);
622 static int transient_scope_set_properties(sd_bus_message
*m
) {
627 r
= transient_unit_set_properties(m
, arg_property
);
631 r
= transient_kill_set_properties(m
);
635 r
= sd_bus_message_append(m
, "(sv)", "PIDs", "au", 1, (uint32_t) getpid());
642 static int transient_timer_set_properties(sd_bus_message
*m
) {
647 r
= transient_unit_set_properties(m
, arg_timer_property
);
652 r
= sd_bus_message_append(m
, "(sv)", "OnActiveSec", "t", arg_on_active
);
658 r
= sd_bus_message_append(m
, "(sv)", "OnBootSec", "t", arg_on_boot
);
663 if (arg_on_startup
) {
664 r
= sd_bus_message_append(m
, "(sv)", "OnStartupSec", "t", arg_on_startup
);
669 if (arg_on_unit_active
) {
670 r
= sd_bus_message_append(m
, "(sv)", "OnUnitActiveSec", "t", arg_on_unit_active
);
675 if (arg_on_unit_inactive
) {
676 r
= sd_bus_message_append(m
, "(sv)", "OnUnitInactiveSec", "t", arg_on_unit_inactive
);
681 if (arg_on_calendar
) {
682 r
= sd_bus_message_append(m
, "(sv)", "OnCalendar", "s", arg_on_calendar
);
690 static int start_transient_service(
694 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
695 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
696 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
697 _cleanup_free_
char *service
= NULL
, *pty_path
= NULL
;
698 _cleanup_close_
int master
= -1;
706 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
707 master
= posix_openpt(O_RDWR
|O_NOCTTY
|O_CLOEXEC
|O_NDELAY
);
709 return log_error_errno(errno
, "Failed to acquire pseudo tty: %m");
711 r
= ptsname_malloc(master
, &pty_path
);
713 return log_error_errno(r
, "Failed to determine tty name: %m");
715 if (unlockpt(master
) < 0)
716 return log_error_errno(errno
, "Failed to unlock tty: %m");
718 } else if (arg_transport
== BUS_TRANSPORT_MACHINE
) {
719 _cleanup_bus_unref_ sd_bus
*system_bus
= NULL
;
722 r
= sd_bus_default_system(&system_bus
);
724 return log_error_errno(r
, "Failed to connect to system bus: %m");
726 r
= sd_bus_call_method(system_bus
,
727 "org.freedesktop.machine1",
728 "/org/freedesktop/machine1",
729 "org.freedesktop.machine1.Manager",
735 log_error("Failed to get machine PTY: %s", bus_error_message(&error
, -r
));
739 r
= sd_bus_message_read(reply
, "hs", &master
, &s
);
741 return bus_log_parse_error(r
);
743 reply
= sd_bus_message_unref(reply
);
745 master
= fcntl(master
, F_DUPFD_CLOEXEC
, 3);
747 return log_error_errno(errno
, "Failed to duplicate master fd: %m");
749 pty_path
= strdup(s
);
753 assert_not_reached("Can't allocate tty via ssh");
757 r
= bus_wait_for_jobs_new(bus
, &w
);
759 return log_error_errno(r
, "Could not watch jobs: %m");
763 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
765 return log_error_errno(r
, "Failed to mangle unit name: %m");
766 } else if (asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0)
769 r
= sd_bus_message_new_method_call(
772 "org.freedesktop.systemd1",
773 "/org/freedesktop/systemd1",
774 "org.freedesktop.systemd1.Manager",
775 "StartTransientUnit");
777 return bus_log_create_error(r
);
779 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
781 return bus_log_create_error(r
);
784 r
= sd_bus_message_append(m
, "ss", service
, "fail");
786 return bus_log_create_error(r
);
789 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
791 return bus_log_create_error(r
);
793 r
= transient_service_set_properties(m
, argv
, pty_path
);
795 return bus_log_create_error(r
);
797 r
= sd_bus_message_close_container(m
);
799 return bus_log_create_error(r
);
801 /* Auxiliary units */
802 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
804 return bus_log_create_error(r
);
806 polkit_agent_open_if_enabled();
808 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
810 return log_error_errno(r
, "Failed to start transient service unit: %s", bus_error_message(&error
, r
));
815 r
= sd_bus_message_read(reply
, "o", &object
);
817 return bus_log_parse_error(r
);
819 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
825 _cleanup_(pty_forward_freep
) PTYForward
*forward
= NULL
;
826 _cleanup_event_unref_ sd_event
*event
= NULL
;
829 r
= sd_event_default(&event
);
831 return log_error_errno(r
, "Failed to get event loop: %m");
833 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGWINCH
, SIGTERM
, SIGINT
, -1) >= 0);
835 (void) sd_event_add_signal(event
, NULL
, SIGINT
, NULL
, NULL
);
836 (void) sd_event_add_signal(event
, NULL
, SIGTERM
, NULL
, NULL
);
839 log_info("Running as unit %s.\nPress ^] three times within 1s to disconnect TTY.", service
);
841 r
= pty_forward_new(event
, master
, PTY_FORWARD_IGNORE_INITIAL_VHANGUP
, &forward
);
843 return log_error_errno(r
, "Failed to create PTY forwarder: %m");
845 r
= sd_event_loop(event
);
847 return log_error_errno(r
, "Failed to run event loop: %m");
849 pty_forward_get_last_char(forward
, &last_char
);
851 forward
= pty_forward_free(forward
);
853 if (!arg_quiet
&& last_char
!= '\n')
856 } else if (!arg_quiet
)
857 log_info("Running as unit %s.", service
);
862 static int start_transient_scope(
866 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
867 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
868 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
869 _cleanup_strv_free_
char **env
= NULL
, **user_env
= NULL
;
870 _cleanup_free_
char *scope
= NULL
;
871 const char *object
= NULL
;
877 r
= bus_wait_for_jobs_new(bus
, &w
);
882 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".scope", &scope
);
884 return log_error_errno(r
, "Failed to mangle scope name: %m");
885 } else if (asprintf(&scope
, "run-"PID_FMT
".scope", getpid()) < 0)
888 r
= sd_bus_message_new_method_call(
891 "org.freedesktop.systemd1",
892 "/org/freedesktop/systemd1",
893 "org.freedesktop.systemd1.Manager",
894 "StartTransientUnit");
896 return bus_log_create_error(r
);
898 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
900 return bus_log_create_error(r
);
903 r
= sd_bus_message_append(m
, "ss", scope
, "fail");
905 return bus_log_create_error(r
);
908 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
910 return bus_log_create_error(r
);
912 r
= transient_scope_set_properties(m
);
914 return bus_log_create_error(r
);
916 r
= sd_bus_message_close_container(m
);
918 return bus_log_create_error(r
);
920 /* Auxiliary units */
921 r
= sd_bus_message_append(m
, "a(sa(sv))", 0);
923 return bus_log_create_error(r
);
925 polkit_agent_open_if_enabled();
927 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
929 log_error("Failed to start transient scope unit: %s", bus_error_message(&error
, -r
));
934 if (setpriority(PRIO_PROCESS
, 0, arg_nice
) < 0)
935 return log_error_errno(errno
, "Failed to set nice level: %m");
938 if (arg_exec_group
) {
941 r
= get_group_creds(&arg_exec_group
, &gid
);
943 return log_error_errno(r
, "Failed to resolve group %s: %m", arg_exec_group
);
945 if (setresgid(gid
, gid
, gid
) < 0)
946 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
950 const char *home
, *shell
;
954 r
= get_user_creds(&arg_exec_user
, &uid
, &gid
, &home
, &shell
);
956 return log_error_errno(r
, "Failed to resolve user %s: %m", arg_exec_user
);
958 r
= strv_extendf(&user_env
, "HOME=%s", home
);
962 r
= strv_extendf(&user_env
, "SHELL=%s", shell
);
966 r
= strv_extendf(&user_env
, "USER=%s", arg_exec_user
);
970 r
= strv_extendf(&user_env
, "LOGNAME=%s", arg_exec_user
);
974 if (!arg_exec_group
) {
975 if (setresgid(gid
, gid
, gid
) < 0)
976 return log_error_errno(errno
, "Failed to change GID to " GID_FMT
": %m", gid
);
979 if (setresuid(uid
, uid
, uid
) < 0)
980 return log_error_errno(errno
, "Failed to change UID to " UID_FMT
": %m", uid
);
983 env
= strv_env_merge(3, environ
, user_env
, arg_environment
);
987 r
= sd_bus_message_read(reply
, "o", &object
);
989 return bus_log_parse_error(r
);
991 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
996 log_info("Running scope as unit %s.", scope
);
998 execvpe(argv
[0], argv
, env
);
1000 return log_error_errno(errno
, "Failed to execute: %m");
1003 static int start_transient_timer(
1007 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
1008 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
, *reply
= NULL
;
1009 _cleanup_(bus_wait_for_jobs_freep
) BusWaitForJobs
*w
= NULL
;
1010 _cleanup_free_
char *timer
= NULL
, *service
= NULL
;
1011 const char *object
= NULL
;
1017 r
= bus_wait_for_jobs_new(bus
, &w
);
1022 switch (unit_name_to_type(arg_unit
)) {
1025 service
= strdup(arg_unit
);
1029 r
= unit_name_change_suffix(service
, ".timer", &timer
);
1031 return log_error_errno(r
, "Failed to change unit suffix: %m");
1035 timer
= strdup(arg_unit
);
1039 r
= unit_name_change_suffix(timer
, ".service", &service
);
1041 return log_error_errno(r
, "Failed to change unit suffix: %m");
1045 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".service", &service
);
1047 return log_error_errno(r
, "Failed to mangle unit name: %m");
1049 r
= unit_name_mangle_with_suffix(arg_unit
, UNIT_NAME_NOGLOB
, ".timer", &timer
);
1051 return log_error_errno(r
, "Failed to mangle unit name: %m");
1055 } else if ((asprintf(&service
, "run-"PID_FMT
".service", getpid()) < 0) ||
1056 (asprintf(&timer
, "run-"PID_FMT
".timer", getpid()) < 0))
1059 r
= sd_bus_message_new_method_call(
1062 "org.freedesktop.systemd1",
1063 "/org/freedesktop/systemd1",
1064 "org.freedesktop.systemd1.Manager",
1065 "StartTransientUnit");
1067 return bus_log_create_error(r
);
1069 r
= sd_bus_message_set_allow_interactive_authorization(m
, arg_ask_password
);
1071 return bus_log_create_error(r
);
1074 r
= sd_bus_message_append(m
, "ss", timer
, "fail");
1076 return bus_log_create_error(r
);
1079 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1081 return bus_log_create_error(r
);
1083 r
= transient_timer_set_properties(m
);
1085 return bus_log_create_error(r
);
1087 r
= sd_bus_message_close_container(m
);
1089 return bus_log_create_error(r
);
1091 r
= sd_bus_message_open_container(m
, 'a', "(sa(sv))");
1093 return bus_log_create_error(r
);
1096 r
= sd_bus_message_open_container(m
, 'r', "sa(sv)");
1098 return bus_log_create_error(r
);
1100 r
= sd_bus_message_append(m
, "s", service
);
1102 return bus_log_create_error(r
);
1104 r
= sd_bus_message_open_container(m
, 'a', "(sv)");
1106 return bus_log_create_error(r
);
1108 r
= transient_service_set_properties(m
, argv
, NULL
);
1110 return bus_log_create_error(r
);
1112 r
= sd_bus_message_close_container(m
);
1114 return bus_log_create_error(r
);
1116 r
= sd_bus_message_close_container(m
);
1118 return bus_log_create_error(r
);
1121 r
= sd_bus_message_close_container(m
);
1123 return bus_log_create_error(r
);
1125 polkit_agent_open_if_enabled();
1127 r
= sd_bus_call(bus
, m
, 0, &error
, &reply
);
1129 log_error("Failed to start transient timer unit: %s", bus_error_message(&error
, -r
));
1133 r
= sd_bus_message_read(reply
, "o", &object
);
1135 return bus_log_parse_error(r
);
1137 r
= bus_wait_for_jobs_one(w
, object
, arg_quiet
);
1141 log_info("Running timer as unit %s.", timer
);
1143 log_info("Will run service as unit %s.", service
);
1148 int main(int argc
, char* argv
[]) {
1149 _cleanup_bus_flush_close_unref_ sd_bus
*bus
= NULL
;
1150 _cleanup_free_
char *description
= NULL
, *command
= NULL
;
1153 log_parse_environment();
1156 r
= parse_argv(argc
, argv
);
1160 if (argc
> optind
&& arg_transport
== BUS_TRANSPORT_LOCAL
) {
1161 /* Patch in an absolute path */
1163 r
= find_binary(argv
[optind
], &command
);
1165 log_error_errno(r
, "Failed to find executable %s: %m", argv
[optind
]);
1169 argv
[optind
] = command
;
1172 if (!arg_description
) {
1173 description
= strv_join(argv
+ optind
, " ");
1179 if (arg_unit
&& isempty(description
)) {
1180 r
= free_and_strdup(&description
, arg_unit
);
1185 arg_description
= description
;
1188 r
= bus_connect_transport_systemd(arg_transport
, arg_host
, arg_user
, &bus
);
1190 log_error_errno(r
, "Failed to create bus connection: %m");
1195 r
= start_transient_scope(bus
, argv
+ optind
);
1196 else if (with_timer())
1197 r
= start_transient_timer(bus
, argv
+ optind
);
1199 r
= start_transient_service(bus
, argv
+ optind
);
1202 strv_free(arg_environment
);
1203 strv_free(arg_property
);
1204 strv_free(arg_timer_property
);
1206 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;