2020-11-09 13:23:58 +09:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2025-04-28 15:08:57 +02:00
|
|
|
#include <fcntl.h>
|
2013-07-01 00:03:57 +02:00
|
|
|
#include <getopt.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <stdio.h>
|
2025-05-14 22:22:11 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <sys/resource.h>
|
tree-wide: include unistd.h where necessary
We use symbols provided by unistd.h without including it. E.g.
open(), close(), read(), write(), access(), symlink(), unlink(), rmdir(),
fsync(), syncfs(), lseek(), ftruncate(), fchown(), dup2(), pipe2(),
getuid(), getgid(), gettid(), getppid(), pipe2(), execv(), _exit(),
environ, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, F_OK, and their
friends and variants, so on.
Currently, unistd.h is indirectly included mainly in the following two paths:
- through missing_syscall.h, which is planned to covert to .c file.
- through signal.h -> bits/sigstksz.h, which is new since glibc-2.34.
Note, signal.h is included by sd-eevent.h. So, many source files
indirectly include unistd.h if newer glibc is used.
Currently, our baseline on glibc is 2.31. We need to support glibc older
than 2.34, but unfortunately, we do not have any CI environments with
such old glibc. CIFuzz uses glibc-2.31, but it builds only fuzzers, and
many files are even not compiled.
2025-06-25 04:51:20 +09:00
|
|
|
#include <unistd.h>
|
2013-06-28 04:12:58 +02:00
|
|
|
|
|
|
|
|
#include "sd-bus.h"
|
2025-05-05 22:06:17 +02:00
|
|
|
#include "sd-daemon.h"
|
2014-12-22 19:45:32 +01:00
|
|
|
#include "sd-event.h"
|
2024-08-12 15:15:15 +02:00
|
|
|
#include "sd-json.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2025-05-05 22:06:17 +02:00
|
|
|
#include "argv-util.h"
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
#include "ask-password-agent.h"
|
2022-11-06 16:30:58 +01:00
|
|
|
#include "build.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "bus-error.h"
|
2020-06-28 15:59:37 +02:00
|
|
|
#include "bus-locator.h"
|
2020-06-28 16:08:37 +02:00
|
|
|
#include "bus-map-properties.h"
|
2025-01-11 16:52:05 +01:00
|
|
|
#include "bus-message-util.h"
|
2016-04-20 17:43:13 +02:00
|
|
|
#include "bus-unit-util.h"
|
2025-05-22 13:40:43 +02:00
|
|
|
#include "bus-util.h"
|
2019-03-06 19:38:45 +01:00
|
|
|
#include "bus-wait-for-jobs.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "calendarspec.h"
|
2023-10-26 09:19:04 +02:00
|
|
|
#include "capsule-util.h"
|
|
|
|
|
#include "chase.h"
|
2014-03-05 18:57:21 +01:00
|
|
|
#include "env-util.h"
|
2025-05-14 22:22:11 +02:00
|
|
|
#include "errno-util.h"
|
2023-11-25 01:05:41 +09:00
|
|
|
#include "escape.h"
|
2024-10-24 15:08:22 +02:00
|
|
|
#include "event-util.h"
|
2024-07-10 22:27:21 +02:00
|
|
|
#include "exec-util.h"
|
2019-10-29 18:07:07 +01:00
|
|
|
#include "exit-status.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2025-07-02 16:25:15 +02:00
|
|
|
#include "fork-notify.h"
|
2025-03-27 19:08:55 -04:00
|
|
|
#include "format-table.h"
|
2016-11-07 10:14:59 -05:00
|
|
|
#include "format-util.h"
|
2023-10-26 09:19:04 +02:00
|
|
|
#include "fs-util.h"
|
2025-06-04 18:28:35 +02:00
|
|
|
#include "hostname-util.h"
|
2025-04-12 16:47:29 +02:00
|
|
|
#include "log.h"
|
2018-11-22 19:30:03 +01:00
|
|
|
#include "main-func.h"
|
2024-11-18 12:46:50 +01:00
|
|
|
#include "osc-context.h"
|
2025-07-10 11:30:01 +02:00
|
|
|
#include "pager.h"
|
2021-02-14 11:39:48 +01:00
|
|
|
#include "parse-argument.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "parse-util.h"
|
2013-09-09 17:31:10 -04:00
|
|
|
#include "path-util.h"
|
2025-05-14 22:22:11 +02:00
|
|
|
#include "pidref.h"
|
2024-06-26 12:07:36 +02:00
|
|
|
#include "polkit-agent.h"
|
2018-11-20 15:42:57 +01:00
|
|
|
#include "pretty-print.h"
|
2016-08-17 14:24:17 +02:00
|
|
|
#include "process-util.h"
|
2014-12-22 19:45:32 +01:00
|
|
|
#include "ptyfwd.h"
|
2025-05-14 22:22:11 +02:00
|
|
|
#include "runtime-scope.h"
|
2015-05-29 20:14:11 +02:00
|
|
|
#include "signal-util.h"
|
2024-01-04 15:22:54 +01:00
|
|
|
#include "special.h"
|
2024-10-10 16:07:16 -04:00
|
|
|
#include "string-table.h"
|
2025-05-14 22:22:11 +02:00
|
|
|
#include "string-util.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "strv.h"
|
2015-10-07 22:45:48 +02:00
|
|
|
#include "terminal-util.h"
|
2025-05-14 22:22:11 +02:00
|
|
|
#include "time-util.h"
|
2023-10-26 09:19:04 +02:00
|
|
|
#include "uid-classification.h"
|
2017-12-23 16:59:56 +09:00
|
|
|
#include "unit-def.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "unit-name.h"
|
2015-10-25 22:32:30 +01:00
|
|
|
#include "user-util.h"
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2015-09-01 16:43:08 +00:00
|
|
|
static bool arg_ask_password = true;
|
2013-07-01 00:03:57 +02:00
|
|
|
static bool arg_scope = false;
|
2013-07-26 16:09:25 +02:00
|
|
|
static bool arg_remain_after_exit = false;
|
2015-04-28 12:33:19 +02:00
|
|
|
static bool arg_no_block = false;
|
2016-08-17 14:24:17 +02:00
|
|
|
static bool arg_wait = false;
|
2013-07-01 00:03:57 +02:00
|
|
|
static const char *arg_unit = NULL;
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
static char *arg_description = NULL;
|
2013-07-01 03:02:42 +02:00
|
|
|
static const char *arg_slice = NULL;
|
2020-04-08 14:57:52 +02:00
|
|
|
static bool arg_slice_inherit = false;
|
2024-07-10 21:58:12 +02:00
|
|
|
static bool arg_expand_environment = true;
|
2013-07-30 02:28:22 +02:00
|
|
|
static bool arg_send_sighup = false;
|
2013-10-30 16:44:55 +01:00
|
|
|
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
|
2014-03-05 03:38:36 +01:00
|
|
|
static const char *arg_host = NULL;
|
2023-03-10 09:47:10 +01:00
|
|
|
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
2014-02-05 02:02:00 +01:00
|
|
|
static const char *arg_service_type = NULL;
|
|
|
|
|
static const char *arg_exec_user = NULL;
|
|
|
|
|
static const char *arg_exec_group = NULL;
|
|
|
|
|
static int arg_nice = 0;
|
|
|
|
|
static bool arg_nice_set = false;
|
|
|
|
|
static char **arg_environment = NULL;
|
2014-03-05 03:36:22 +01:00
|
|
|
static char **arg_property = NULL;
|
2017-09-08 15:38:40 +02:00
|
|
|
static enum {
|
2025-03-10 18:22:28 +09:00
|
|
|
ARG_STDIO_NONE = 0, /* The default, as it is for normal services, stdin connected to
|
|
|
|
|
* /dev/null, and stdout+stderr to the journal */
|
|
|
|
|
ARG_STDIO_PTY = 1 << 0, /* Interactive behaviour, requested by --pty/--pty-late: we allocate a pty
|
|
|
|
|
* and connect it to the TTY we are invoked from */
|
|
|
|
|
ARG_STDIO_DIRECT = 1 << 1, /* Directly pass our stdin/stdout/stderr to the activated service, useful
|
|
|
|
|
* for usage in shell pipelines, requested by --pipe */
|
|
|
|
|
ARG_STDIO_AUTO = ARG_STDIO_PTY | ARG_STDIO_DIRECT,
|
|
|
|
|
/* If --pipe and --pty/--pty-late are used together we use --pty/--pty-late
|
|
|
|
|
* when invoked on a TTY, and --pipe otherwise */
|
2017-09-08 15:38:40 +02:00
|
|
|
} arg_stdio = ARG_STDIO_NONE;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
static int arg_pty_late = -1; /* tristate */
|
2017-12-18 23:46:45 +09:00
|
|
|
static char **arg_path_property = NULL;
|
|
|
|
|
static char **arg_socket_property = NULL;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
static char **arg_timer_property = NULL;
|
2019-03-14 19:55:29 +01:00
|
|
|
static bool arg_with_timer = false;
|
2014-12-22 20:39:10 +01:00
|
|
|
static bool arg_quiet = false;
|
2025-03-23 18:37:45 -04:00
|
|
|
static bool arg_verbose = false;
|
2017-11-13 17:17:53 +01:00
|
|
|
static bool arg_aggressive_gc = false;
|
2018-11-22 12:07:25 +01:00
|
|
|
static char *arg_working_directory = NULL;
|
2018-11-22 19:24:48 +01:00
|
|
|
static bool arg_shell = false;
|
2024-10-10 16:07:16 -04:00
|
|
|
static JobMode arg_job_mode = JOB_FAIL;
|
2018-11-22 19:24:48 +01:00
|
|
|
static char **arg_cmdline = NULL;
|
2023-12-19 19:10:52 +01:00
|
|
|
static char *arg_exec_path = NULL;
|
2023-12-19 21:39:50 +01:00
|
|
|
static bool arg_ignore_failure = false;
|
2023-12-20 12:09:27 +01:00
|
|
|
static char *arg_background = NULL;
|
2025-07-10 11:30:01 +02:00
|
|
|
static PagerFlags arg_pager_flags = 0;
|
2024-08-12 15:15:15 +02:00
|
|
|
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
2024-10-24 11:36:48 +02:00
|
|
|
static char *arg_shell_prompt_prefix = NULL;
|
2025-01-14 11:50:52 +01:00
|
|
|
static int arg_lightweight = -1;
|
2025-01-24 10:24:09 +01:00
|
|
|
static char *arg_area = NULL;
|
2025-04-09 00:55:27 +02:00
|
|
|
static bool arg_via_shell = false;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
2018-11-22 19:34:15 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_path_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_socket_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_timer_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_working_directory, freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
|
2023-12-19 19:10:52 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep);
|
2023-12-20 12:09:27 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
|
2024-10-24 11:36:48 +02:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_shell_prompt_prefix, freep);
|
2025-01-24 10:24:09 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_area, freep);
|
2018-11-22 19:34:15 +01:00
|
|
|
|
2018-08-09 10:32:31 +02:00
|
|
|
static int help(void) {
|
|
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
2025-07-10 11:30:01 +02:00
|
|
|
pager_open(arg_pager_flags);
|
|
|
|
|
|
2018-08-09 10:32:31 +02:00
|
|
|
r = terminal_urlify_man("systemd-run", "1", &link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2023-12-19 19:09:59 +01:00
|
|
|
printf("%1$s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
|
|
|
|
"\n%5$sRun the specified command in a transient scope or service.%6$s\n\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" -h --help Show this help\n"
|
|
|
|
|
" --version Show package version\n"
|
2015-09-01 16:43:08 +00:00
|
|
|
" --no-ask-password Do not prompt for password\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --user Run as user unit\n"
|
|
|
|
|
" -H --host=[USER@]HOST Operate on remote host\n"
|
|
|
|
|
" -M --machine=CONTAINER Operate on local container\n"
|
|
|
|
|
" --scope Run this as scope rather than service\n"
|
2019-10-23 09:13:15 +02:00
|
|
|
" -u --unit=UNIT Run under the specified unit name\n"
|
2016-08-06 00:30:12 +02:00
|
|
|
" -p --property=NAME=VALUE Set service or scope unit property\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --description=TEXT Description for unit\n"
|
|
|
|
|
" --slice=SLICE Run in the specified slice\n"
|
2023-12-20 15:01:52 +01:00
|
|
|
" --slice-inherit Inherit the slice from the caller\n"
|
2023-04-04 21:18:33 +02:00
|
|
|
" --expand-environment=BOOL Control expansion of environment variables\n"
|
2015-04-28 12:33:19 +02:00
|
|
|
" --no-block Do not wait until operation finished\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" -r --remain-after-exit Leave service around until explicitly stopped\n"
|
2016-08-17 14:24:17 +02:00
|
|
|
" --wait Wait until service stopped again\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --send-sighup Send SIGHUP when terminating\n"
|
|
|
|
|
" --service-type=TYPE Service type\n"
|
|
|
|
|
" --uid=USER Run as system user\n"
|
|
|
|
|
" --gid=GROUP Run as system group\n"
|
|
|
|
|
" --nice=NICE Nice level\n"
|
2018-11-22 12:07:25 +01:00
|
|
|
" --working-directory=PATH Set working directory\n"
|
|
|
|
|
" -d --same-dir Inherit working directory from caller\n"
|
2021-08-10 17:25:47 +02:00
|
|
|
" -E --setenv=NAME[=VALUE] Set environment variable\n"
|
2017-09-08 15:38:40 +02:00
|
|
|
" -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
|
|
|
|
|
" STDERR\n"
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
" -T --pty-late Just like --pty, but leave TTY access to\n"
|
|
|
|
|
" agents until unit is started up\n"
|
2017-09-08 15:38:40 +02:00
|
|
|
" -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
|
2017-11-13 17:17:53 +01:00
|
|
|
" -q --quiet Suppress information messages during runtime\n"
|
2025-03-23 18:37:45 -04:00
|
|
|
" -v --verbose Show unit logs while executing operation\n"
|
2024-08-12 15:15:15 +02:00
|
|
|
" --json=pretty|short|off Print unit name and invocation id as JSON\n"
|
2018-11-22 19:24:48 +01:00
|
|
|
" -G --collect Unload unit after it ran, even when failed\n"
|
2023-12-19 19:09:59 +01:00
|
|
|
" -S --shell Invoke a $SHELL interactively\n"
|
2024-10-10 16:07:16 -04:00
|
|
|
" --job-mode=MODE Specify how to deal with already queued jobs,\n"
|
|
|
|
|
" when queueing a new job\n"
|
2023-12-19 21:39:50 +01:00
|
|
|
" --ignore-failure Ignore the exit status of the invoked process\n"
|
2023-12-20 12:09:27 +01:00
|
|
|
" --background=COLOR Set ANSI color for background\n"
|
2025-07-10 11:30:01 +02:00
|
|
|
" --no-pager Do not pipe output into a pager\n"
|
2023-12-19 19:09:59 +01:00
|
|
|
"\n%3$sPath options:%4$s\n"
|
|
|
|
|
" --path-property=NAME=VALUE Set path unit property\n"
|
|
|
|
|
"\n%3$sSocket options:%4$s\n"
|
|
|
|
|
" --socket-property=NAME=VALUE Set socket unit property\n"
|
|
|
|
|
"\n%3$sTimer options:%4$s\n"
|
2015-01-27 21:22:57 -05:00
|
|
|
" --on-active=SECONDS Run after SECONDS delay\n"
|
|
|
|
|
" --on-boot=SECONDS Run SECONDS after machine was booted up\n"
|
|
|
|
|
" --on-startup=SECONDS Run SECONDS after systemd activation\n"
|
|
|
|
|
" --on-unit-active=SECONDS Run SECONDS after the last activation\n"
|
|
|
|
|
" --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --on-calendar=SPEC Realtime timer\n"
|
2019-03-14 21:36:47 +01:00
|
|
|
" --on-timezone-change Run when the timezone changes\n"
|
|
|
|
|
" --on-clock-change Run when the realtime clock jumps\n"
|
2016-08-06 00:30:12 +02:00
|
|
|
" --timer-property=NAME=VALUE Set timer unit property\n"
|
2023-12-19 19:09:59 +01:00
|
|
|
"\nSee the %2$s for details.\n",
|
2021-01-30 14:13:04 +00:00
|
|
|
program_invocation_short_name,
|
2023-12-19 19:09:59 +01:00
|
|
|
link,
|
|
|
|
|
ansi_underline(), ansi_normal(),
|
|
|
|
|
ansi_highlight(), ansi_normal());
|
2018-08-09 10:32:31 +02:00
|
|
|
|
|
|
|
|
return 0;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
static int help_sudo_mode(void) {
|
|
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
r = terminal_urlify_man("run0", "1", &link);
|
2023-12-19 19:10:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2024-10-24 23:27:59 +02:00
|
|
|
/* NB: Let's not go overboard with short options: we try to keep a modicum of compatibility with
|
|
|
|
|
* sudo's short switches, hence please do not introduce new short switches unless they have a roughly
|
|
|
|
|
* equivalent purpose on sudo. Use long options for everything private to run0. */
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
printf("%s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
|
|
|
|
"\n%sElevate privileges interactively.%s\n\n"
|
|
|
|
|
" -h --help Show this help\n"
|
|
|
|
|
" -V --version Show package version\n"
|
|
|
|
|
" --no-ask-password Do not prompt for password\n"
|
|
|
|
|
" --machine=CONTAINER Operate on local container\n"
|
|
|
|
|
" --unit=UNIT Run under the specified unit name\n"
|
|
|
|
|
" --property=NAME=VALUE Set service or scope unit property\n"
|
|
|
|
|
" --description=TEXT Description for unit\n"
|
|
|
|
|
" --slice=SLICE Run in the specified slice\n"
|
|
|
|
|
" --slice-inherit Inherit the slice\n"
|
|
|
|
|
" -u --user=USER Run as system user\n"
|
|
|
|
|
" -g --group=GROUP Run as system group\n"
|
|
|
|
|
" --nice=NICE Nice level\n"
|
|
|
|
|
" -D --chdir=PATH Set working directory\n"
|
2025-04-09 00:55:27 +02:00
|
|
|
" --via-shell Invoke command via target user's login shell\n"
|
|
|
|
|
" -i Shortcut for --via-shell --chdir='~'\n"
|
2023-12-19 19:10:52 +01:00
|
|
|
" --setenv=NAME[=VALUE] Set environment variable\n"
|
2023-12-20 12:09:27 +01:00
|
|
|
" --background=COLOR Set ANSI color for background\n"
|
2024-10-24 23:27:59 +02:00
|
|
|
" --pty Request allocation of a pseudo TTY for stdio\n"
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
" --pty-late Just like --pty, but leave TTY access to agents\n"
|
|
|
|
|
" until unit is started up\n"
|
2024-10-24 23:27:59 +02:00
|
|
|
" --pipe Request direct pipe for stdio\n"
|
2024-10-24 11:36:48 +02:00
|
|
|
" --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
|
2025-01-14 11:50:52 +01:00
|
|
|
" --lightweight=BOOLEAN Control whether to register a session with service manager\n"
|
|
|
|
|
" or without\n"
|
2025-05-12 21:47:01 +02:00
|
|
|
" --area=AREA Home area to log into\n"
|
2023-12-19 19:10:52 +01:00
|
|
|
"\nSee the %s for details.\n",
|
|
|
|
|
program_invocation_short_name,
|
|
|
|
|
ansi_highlight(),
|
|
|
|
|
ansi_normal(),
|
|
|
|
|
link);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
static bool privileged_execution(void) {
|
|
|
|
|
if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-11 21:21:10 +09:00
|
|
|
static int add_timer_property(const char *name, const char *val) {
|
2018-01-04 11:12:57 +01:00
|
|
|
char *p;
|
2017-12-11 21:21:10 +09:00
|
|
|
|
|
|
|
|
assert(name);
|
|
|
|
|
assert(val);
|
|
|
|
|
|
|
|
|
|
p = strjoin(name, "=", val);
|
|
|
|
|
if (!p)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (strv_consume(&arg_timer_property, p) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
return 0;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
}
|
|
|
|
|
|
2025-04-09 00:55:27 +02:00
|
|
|
static char** make_login_shell_cmdline(const char *shell) {
|
2023-12-19 19:10:52 +01:00
|
|
|
_cleanup_free_ char *argv0 = NULL;
|
|
|
|
|
|
|
|
|
|
assert(shell);
|
|
|
|
|
|
|
|
|
|
argv0 = strjoin("-", shell); /* The - is how shells determine if they shall be consider login shells */
|
|
|
|
|
if (!argv0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return strv_new(argv0);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
static int parse_argv(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ARG_VERSION = 0x100,
|
|
|
|
|
ARG_USER,
|
2013-11-06 17:31:20 +01:00
|
|
|
ARG_SYSTEM,
|
2013-07-01 00:03:57 +02:00
|
|
|
ARG_SCOPE,
|
2013-07-01 03:02:42 +02:00
|
|
|
ARG_DESCRIPTION,
|
2013-07-30 02:28:22 +02:00
|
|
|
ARG_SLICE,
|
2020-04-08 14:57:52 +02:00
|
|
|
ARG_SLICE_INHERIT,
|
2023-04-02 23:17:58 +02:00
|
|
|
ARG_EXPAND_ENVIRONMENT,
|
2013-07-30 02:28:22 +02:00
|
|
|
ARG_SEND_SIGHUP,
|
2016-04-17 20:46:00 -04:00
|
|
|
ARG_SERVICE_TYPE,
|
2014-02-05 02:02:00 +01:00
|
|
|
ARG_EXEC_USER,
|
|
|
|
|
ARG_EXEC_GROUP,
|
|
|
|
|
ARG_NICE,
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
ARG_ON_ACTIVE,
|
|
|
|
|
ARG_ON_BOOT,
|
|
|
|
|
ARG_ON_STARTUP,
|
|
|
|
|
ARG_ON_UNIT_ACTIVE,
|
|
|
|
|
ARG_ON_UNIT_INACTIVE,
|
|
|
|
|
ARG_ON_CALENDAR,
|
2019-03-14 21:36:47 +01:00
|
|
|
ARG_ON_TIMEZONE_CHANGE,
|
|
|
|
|
ARG_ON_CLOCK_CHANGE,
|
2015-04-28 12:33:19 +02:00
|
|
|
ARG_TIMER_PROPERTY,
|
2017-12-18 23:46:45 +09:00
|
|
|
ARG_PATH_PROPERTY,
|
|
|
|
|
ARG_SOCKET_PROPERTY,
|
2015-04-28 12:33:19 +02:00
|
|
|
ARG_NO_BLOCK,
|
2016-04-17 20:46:00 -04:00
|
|
|
ARG_NO_ASK_PASSWORD,
|
2016-08-17 14:24:17 +02:00
|
|
|
ARG_WAIT,
|
2018-11-22 12:07:25 +01:00
|
|
|
ARG_WORKING_DIRECTORY,
|
2018-11-22 19:24:48 +01:00
|
|
|
ARG_SHELL,
|
2024-10-10 16:07:16 -04:00
|
|
|
ARG_JOB_MODE,
|
2023-12-19 21:39:50 +01:00
|
|
|
ARG_IGNORE_FAILURE,
|
2023-12-20 12:09:27 +01:00
|
|
|
ARG_BACKGROUND,
|
2025-07-10 11:30:01 +02:00
|
|
|
ARG_NO_PAGER,
|
2024-08-12 15:15:15 +02:00
|
|
|
ARG_JSON,
|
2013-07-01 00:03:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
2023-04-02 23:17:58 +02:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
|
{ "version", no_argument, NULL, ARG_VERSION },
|
|
|
|
|
{ "user", no_argument, NULL, ARG_USER },
|
|
|
|
|
{ "system", no_argument, NULL, ARG_SYSTEM },
|
2023-10-26 09:19:04 +02:00
|
|
|
{ "capsule", required_argument, NULL, 'C' },
|
2023-04-02 23:17:58 +02:00
|
|
|
{ "scope", no_argument, NULL, ARG_SCOPE },
|
|
|
|
|
{ "unit", required_argument, NULL, 'u' },
|
|
|
|
|
{ "description", required_argument, NULL, ARG_DESCRIPTION },
|
|
|
|
|
{ "slice", required_argument, NULL, ARG_SLICE },
|
|
|
|
|
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
|
|
|
|
|
{ "remain-after-exit", no_argument, NULL, 'r' },
|
|
|
|
|
{ "expand-environment", required_argument, NULL, ARG_EXPAND_ENVIRONMENT },
|
|
|
|
|
{ "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
|
|
|
|
|
{ "host", required_argument, NULL, 'H' },
|
|
|
|
|
{ "machine", required_argument, NULL, 'M' },
|
|
|
|
|
{ "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
|
|
|
|
|
{ "wait", no_argument, NULL, ARG_WAIT },
|
|
|
|
|
{ "uid", required_argument, NULL, ARG_EXEC_USER },
|
|
|
|
|
{ "gid", required_argument, NULL, ARG_EXEC_GROUP },
|
|
|
|
|
{ "nice", required_argument, NULL, ARG_NICE },
|
|
|
|
|
{ "setenv", required_argument, NULL, 'E' },
|
|
|
|
|
{ "property", required_argument, NULL, 'p' },
|
|
|
|
|
{ "tty", no_argument, NULL, 't' }, /* deprecated alias */
|
|
|
|
|
{ "pty", no_argument, NULL, 't' },
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
{ "pty-late", no_argument, NULL, 'T' },
|
2023-04-02 23:17:58 +02:00
|
|
|
{ "pipe", no_argument, NULL, 'P' },
|
|
|
|
|
{ "quiet", no_argument, NULL, 'q' },
|
2025-03-23 18:37:45 -04:00
|
|
|
{ "verbose", no_argument, NULL, 'v' },
|
2023-04-02 23:17:58 +02:00
|
|
|
{ "on-active", required_argument, NULL, ARG_ON_ACTIVE },
|
|
|
|
|
{ "on-boot", required_argument, NULL, ARG_ON_BOOT },
|
|
|
|
|
{ "on-startup", required_argument, NULL, ARG_ON_STARTUP },
|
|
|
|
|
{ "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
|
|
|
|
|
{ "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
|
|
|
|
|
{ "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
|
|
|
|
|
{ "on-timezone-change", no_argument, NULL, ARG_ON_TIMEZONE_CHANGE },
|
|
|
|
|
{ "on-clock-change", no_argument, NULL, ARG_ON_CLOCK_CHANGE },
|
|
|
|
|
{ "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
|
|
|
|
|
{ "path-property", required_argument, NULL, ARG_PATH_PROPERTY },
|
|
|
|
|
{ "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY },
|
|
|
|
|
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
|
|
|
|
|
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
|
|
|
|
{ "collect", no_argument, NULL, 'G' },
|
|
|
|
|
{ "working-directory", required_argument, NULL, ARG_WORKING_DIRECTORY },
|
|
|
|
|
{ "same-dir", no_argument, NULL, 'd' },
|
|
|
|
|
{ "shell", no_argument, NULL, 'S' },
|
2024-10-10 16:07:16 -04:00
|
|
|
{ "job-mode", required_argument, NULL, ARG_JOB_MODE },
|
2023-12-19 21:39:50 +01:00
|
|
|
{ "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE },
|
2024-01-19 23:41:24 +01:00
|
|
|
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
2025-07-10 11:30:01 +02:00
|
|
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
2024-08-12 15:15:15 +02:00
|
|
|
{ "json", required_argument, NULL, ARG_JSON },
|
2013-11-06 18:28:39 +01:00
|
|
|
{},
|
2013-07-01 00:03:57 +02:00
|
|
|
};
|
|
|
|
|
|
2017-12-18 23:46:45 +09:00
|
|
|
bool with_trigger = false;
|
2014-02-05 02:02:00 +01:00
|
|
|
int r, c;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
|
assert(argv);
|
|
|
|
|
|
2023-03-21 10:05:33 +09:00
|
|
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
|
|
|
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
|
|
|
|
optind = 0;
|
2025-03-23 18:37:45 -04:00
|
|
|
while ((c = getopt_long(argc, argv, "+hrC:H:M:E:p:tTPqvGdSu:", options, NULL)) >= 0)
|
2013-07-01 00:03:57 +02:00
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
|
|
case 'h':
|
2018-08-09 10:32:31 +02:00
|
|
|
return help();
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2016-08-06 00:30:12 +02:00
|
|
|
case ARG_VERSION:
|
|
|
|
|
return version();
|
|
|
|
|
|
2015-09-01 16:43:08 +00:00
|
|
|
case ARG_NO_ASK_PASSWORD:
|
|
|
|
|
arg_ask_password = false;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
case ARG_USER:
|
2023-03-10 09:47:10 +01:00
|
|
|
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
2013-07-01 00:03:57 +02:00
|
|
|
break;
|
|
|
|
|
|
2013-11-06 17:31:20 +01:00
|
|
|
case ARG_SYSTEM:
|
2023-03-10 09:47:10 +01:00
|
|
|
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
2013-11-06 17:31:20 +01:00
|
|
|
break;
|
|
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
case 'C':
|
|
|
|
|
r = capsule_name_is_valid(optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
|
|
|
|
|
if (r == 0)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
|
|
|
|
|
|
|
|
|
|
arg_host = optarg;
|
|
|
|
|
arg_transport = BUS_TRANSPORT_CAPSULE;
|
|
|
|
|
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
case ARG_SCOPE:
|
|
|
|
|
arg_scope = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-10-23 09:13:15 +02:00
|
|
|
case 'u':
|
2013-07-01 00:03:57 +02:00
|
|
|
arg_unit = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:40:56 +02:00
|
|
|
case ARG_DESCRIPTION:
|
2023-12-20 12:09:27 +01:00
|
|
|
r = free_and_strdup_warn(&arg_description, optarg);
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2013-07-01 00:40:56 +02:00
|
|
|
break;
|
|
|
|
|
|
2013-07-01 03:02:42 +02:00
|
|
|
case ARG_SLICE:
|
|
|
|
|
arg_slice = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-04-08 14:57:52 +02:00
|
|
|
case ARG_SLICE_INHERIT:
|
|
|
|
|
arg_slice_inherit = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-07-10 21:58:12 +02:00
|
|
|
case ARG_EXPAND_ENVIRONMENT:
|
|
|
|
|
r = parse_boolean_argument("--expand-environment=", optarg, &arg_expand_environment);
|
2023-04-02 23:17:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-30 02:28:22 +02:00
|
|
|
case ARG_SEND_SIGHUP:
|
|
|
|
|
arg_send_sighup = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-26 16:09:25 +02:00
|
|
|
case 'r':
|
|
|
|
|
arg_remain_after_exit = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-10-30 16:44:55 +01:00
|
|
|
case 'H':
|
|
|
|
|
arg_transport = BUS_TRANSPORT_REMOTE;
|
|
|
|
|
arg_host = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'M':
|
2025-06-17 01:48:08 +02:00
|
|
|
r = parse_machine_argument(optarg, &arg_host, &arg_transport);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2013-10-30 16:44:55 +01:00
|
|
|
break;
|
|
|
|
|
|
2014-02-05 02:02:00 +01:00
|
|
|
case ARG_SERVICE_TYPE:
|
|
|
|
|
arg_service_type = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_EXEC_USER:
|
|
|
|
|
arg_exec_user = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_EXEC_GROUP:
|
|
|
|
|
arg_exec_group = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_NICE:
|
2016-08-05 11:17:08 +02:00
|
|
|
r = parse_nice(optarg, &arg_nice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to parse nice value: %s", optarg);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
arg_nice_set = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2016-04-20 08:38:01 -04:00
|
|
|
case 'E':
|
2021-08-10 17:25:47 +02:00
|
|
|
r = strv_env_replace_strdup_passthrough(&arg_environment, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2014-03-05 03:36:22 +01:00
|
|
|
case 'p':
|
|
|
|
|
if (strv_extend(&arg_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
case 'T': /* --pty-late */
|
2017-09-08 15:38:40 +02:00
|
|
|
case 't': /* --pty */
|
2025-03-10 18:22:28 +09:00
|
|
|
arg_stdio |= ARG_STDIO_PTY;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
arg_pty_late = c == 'T';
|
2017-09-08 15:38:40 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'P': /* --pipe */
|
2025-03-10 18:22:28 +09:00
|
|
|
arg_stdio |= ARG_STDIO_DIRECT;
|
2014-12-22 19:45:32 +01:00
|
|
|
break;
|
|
|
|
|
|
2014-12-22 20:39:10 +01:00
|
|
|
case 'q':
|
|
|
|
|
arg_quiet = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2025-03-23 18:37:45 -04:00
|
|
|
case 'v':
|
|
|
|
|
arg_verbose = true;
|
|
|
|
|
break;
|
|
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
case ARG_ON_ACTIVE:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnActiveSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_BOOT:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnBootSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_STARTUP:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnStartupSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_UNIT_ACTIVE:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnUnitActiveSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_UNIT_INACTIVE:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnUnitInactiveSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
2019-04-12 20:57:51 +02:00
|
|
|
case ARG_ON_CALENDAR: {
|
|
|
|
|
_cleanup_(calendar_spec_freep) CalendarSpec *cs = NULL;
|
|
|
|
|
|
|
|
|
|
r = calendar_spec_from_string(optarg, &cs);
|
|
|
|
|
if (r < 0)
|
2019-04-25 13:22:55 +02:00
|
|
|
return log_error_errno(r, "Failed to parse calendar event specification: %m");
|
|
|
|
|
|
2019-07-16 12:22:37 +02:00
|
|
|
/* Let's make sure the given calendar event is not in the past */
|
2019-04-25 13:22:55 +02:00
|
|
|
r = calendar_spec_next_usec(cs, now(CLOCK_REALTIME), NULL);
|
|
|
|
|
if (r == -ENOENT)
|
2019-04-26 08:46:01 +02:00
|
|
|
/* The calendar event is in the past — let's warn about this, but install it
|
|
|
|
|
* anyway as is. The service manager will trigger the service right away.
|
|
|
|
|
* Moreover, the server side might have a different clock or timezone than we
|
|
|
|
|
* do, hence it should decide when or whether to run something. */
|
2019-04-25 13:22:55 +02:00
|
|
|
log_warning("Specified calendar expression is in the past, proceeding anyway.");
|
|
|
|
|
else if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to calculate next time calendar expression elapses: %m");
|
2019-04-12 20:57:51 +02:00
|
|
|
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnCalendar", optarg);
|
|
|
|
|
if (r < 0)
|
2019-03-14 21:36:47 +01:00
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
arg_with_timer = true;
|
|
|
|
|
break;
|
2019-04-12 20:57:51 +02:00
|
|
|
}
|
2019-03-14 21:36:47 +01:00
|
|
|
|
|
|
|
|
case ARG_ON_TIMEZONE_CHANGE:
|
|
|
|
|
r = add_timer_property("OnTimezoneChange", "yes");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
arg_with_timer = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_CLOCK_CHANGE:
|
|
|
|
|
r = add_timer_property("OnClockChange", "yes");
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
2015-10-08 15:01:42 +02:00
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_TIMER_PROPERTY:
|
|
|
|
|
|
|
|
|
|
if (strv_extend(&arg_timer_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = arg_with_timer ||
|
2018-11-23 16:30:23 +01:00
|
|
|
STARTSWITH_SET(optarg,
|
|
|
|
|
"OnActiveSec=",
|
|
|
|
|
"OnBootSec=",
|
|
|
|
|
"OnStartupSec=",
|
|
|
|
|
"OnUnitActiveSec=",
|
|
|
|
|
"OnUnitInactiveSec=",
|
|
|
|
|
"OnCalendar=");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
2017-12-18 23:46:45 +09:00
|
|
|
case ARG_PATH_PROPERTY:
|
|
|
|
|
|
|
|
|
|
if (strv_extend(&arg_path_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SOCKET_PROPERTY:
|
|
|
|
|
|
|
|
|
|
if (strv_extend(&arg_socket_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2015-04-28 12:33:19 +02:00
|
|
|
case ARG_NO_BLOCK:
|
|
|
|
|
arg_no_block = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
case ARG_WAIT:
|
|
|
|
|
arg_wait = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2018-11-22 12:07:25 +01:00
|
|
|
case ARG_WORKING_DIRECTORY:
|
2021-02-14 11:39:48 +01:00
|
|
|
r = parse_path_argument(optarg, true, &arg_working_directory);
|
2018-11-22 12:07:25 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'd': {
|
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
|
|
|
|
|
r = safe_getcwd(&p);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get current working directory: %m");
|
|
|
|
|
|
|
|
|
|
if (empty_or_root(p))
|
|
|
|
|
arg_working_directory = mfree(arg_working_directory);
|
|
|
|
|
else
|
|
|
|
|
free_and_replace(arg_working_directory, p);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-13 17:17:53 +01:00
|
|
|
case 'G':
|
|
|
|
|
arg_aggressive_gc = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
case 'S':
|
|
|
|
|
arg_shell = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-10-10 16:07:16 -04:00
|
|
|
case ARG_JOB_MODE:
|
|
|
|
|
if (streq(optarg, "help"))
|
|
|
|
|
return DUMP_STRING_TABLE(job_mode, JobMode, _JOB_MODE_MAX);
|
|
|
|
|
|
|
|
|
|
r = job_mode_from_string(optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Invalid job mode: %s", optarg);
|
|
|
|
|
|
|
|
|
|
arg_job_mode = r;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-19 21:39:50 +01:00
|
|
|
case ARG_IGNORE_FAILURE:
|
|
|
|
|
arg_ignore_failure = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-20 12:09:27 +01:00
|
|
|
case ARG_BACKGROUND:
|
|
|
|
|
r = free_and_strdup_warn(&arg_background, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2025-07-10 11:30:01 +02:00
|
|
|
case ARG_NO_PAGER:
|
|
|
|
|
arg_pager_flags |= PAGER_DISABLE;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-08-12 15:15:15 +02:00
|
|
|
case ARG_JSON:
|
|
|
|
|
r = parse_json_argument(optarg, &arg_json_format_flags);
|
|
|
|
|
if (r <= 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
case '?':
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
default:
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-30 13:21:55 +02:00
|
|
|
/* If we are talking to the per-user instance PolicyKit isn't going to help */
|
2023-03-10 09:47:10 +01:00
|
|
|
if (arg_runtime_scope == RUNTIME_SCOPE_USER)
|
2021-08-30 13:21:55 +02:00
|
|
|
arg_ask_password = false;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
with_trigger = !!arg_path_property || !!arg_socket_property || arg_with_timer;
|
2017-12-18 23:46:45 +09:00
|
|
|
|
|
|
|
|
/* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
|
2019-03-14 19:55:29 +01:00
|
|
|
if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) arg_with_timer > 1)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"Only single trigger (path, socket, timer) unit can be created.");
|
2017-09-08 15:38:40 +02:00
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
if (arg_shell) {
|
|
|
|
|
/* If --shell is imply --pty --pipe --same-dir --service-type=exec --wait --collect, unless otherwise
|
|
|
|
|
* specified. */
|
|
|
|
|
|
|
|
|
|
if (!arg_scope) {
|
|
|
|
|
if (arg_stdio == ARG_STDIO_NONE)
|
|
|
|
|
arg_stdio = ARG_STDIO_AUTO;
|
|
|
|
|
|
|
|
|
|
if (!arg_working_directory) {
|
|
|
|
|
r = safe_getcwd(&arg_working_directory);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get current working directory: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:36 +01:00
|
|
|
if (!arg_service_type)
|
|
|
|
|
arg_service_type = "exec";
|
2018-11-22 19:24:48 +01:00
|
|
|
|
|
|
|
|
arg_wait = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg_aggressive_gc = true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-09 15:06:34 +02:00
|
|
|
if (arg_stdio == ARG_STDIO_AUTO)
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
/* If we both --pty/--pty-late and --pipe are specified we'll automatically pick --pty/--pty-late if we
|
|
|
|
|
* are connected fully to a TTY and pick direct fd passing otherwise. This way, we
|
|
|
|
|
* automatically adapt to usage in a shell pipeline, but we are neatly interactive with
|
|
|
|
|
* tty-level isolation otherwise. */
|
2024-10-24 23:12:31 +02:00
|
|
|
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ?
|
2017-09-08 15:38:40 +02:00
|
|
|
ARG_STDIO_PTY :
|
|
|
|
|
ARG_STDIO_DIRECT;
|
|
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (arg_pty_late < 0)
|
|
|
|
|
arg_pty_late = false; /* For systemd-run this defaults to false, for compat reasons */
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
if (argc > optind) {
|
|
|
|
|
char **l;
|
|
|
|
|
|
|
|
|
|
if (arg_shell)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "If --shell is used, no command line is expected.");
|
|
|
|
|
|
|
|
|
|
l = strv_copy(argv + optind);
|
|
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(arg_cmdline, l);
|
|
|
|
|
|
|
|
|
|
} else if (arg_shell) {
|
|
|
|
|
_cleanup_free_ char *s = NULL;
|
|
|
|
|
char **l;
|
|
|
|
|
|
|
|
|
|
r = get_shell(&s);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to determine shell: %m");
|
|
|
|
|
|
|
|
|
|
l = strv_new(s);
|
|
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(arg_cmdline, l);
|
|
|
|
|
|
|
|
|
|
} else if (!arg_unit || !with_trigger)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Command line to execute required.");
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2023-03-10 09:47:10 +01:00
|
|
|
if (arg_runtime_scope == RUNTIME_SCOPE_USER && arg_transport == BUS_TRANSPORT_REMOTE)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
2021-05-13 01:17:51 -07:00
|
|
|
"Execution in user context is not supported on remote systems.");
|
2013-10-30 16:44:55 +01:00
|
|
|
|
2021-05-13 01:17:51 -07:00
|
|
|
if (arg_scope && arg_transport == BUS_TRANSPORT_REMOTE)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
2021-05-13 01:17:51 -07:00
|
|
|
"Scope execution is not supported on remote systems.");
|
2013-10-30 16:44:55 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_scope && (arg_remain_after_exit || arg_service_type))
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--remain-after-exit and --service-type= are not supported in --scope mode.");
|
2014-02-05 02:02:00 +01:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (arg_stdio != ARG_STDIO_NONE) {
|
|
|
|
|
if (with_trigger || arg_scope)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
2025-03-17 00:26:45 +01:00
|
|
|
"--pty/--pty-late/--pipe is not compatible in trigger (path/socket/timer units) or --scope mode.");
|
2014-12-22 19:45:32 +01:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (arg_transport == BUS_TRANSPORT_REMOTE)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--pty/--pty-late/--pipe is only supported when connecting to the local system or containers.");
|
2015-10-08 15:01:42 +02:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (arg_no_block)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--pty/--pty-late/--pipe is not compatible with --no-block.");
|
|
|
|
|
}
|
2016-12-24 00:30:49 +01:00
|
|
|
|
2025-03-17 00:21:46 +01:00
|
|
|
if (arg_stdio == ARG_STDIO_PTY && arg_pty_late && streq_ptr(arg_service_type, "oneshot"))
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--pty-late is not compatible with --service-type=oneshot.");
|
|
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_scope && with_trigger)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"Path, socket or timer options are not supported in --scope mode.");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
if (arg_timer_property && !arg_with_timer)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--timer-property= has no effect without any other timer options.");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
if (arg_wait) {
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_no_block)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--wait may not be combined with --no-block.");
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (with_trigger)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--wait may not be combined with path, socket or timer operations.");
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_scope)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--wait may not be combined with --scope.");
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ARG_NO_ASK_PASSWORD = 0x100,
|
|
|
|
|
ARG_HOST,
|
|
|
|
|
ARG_MACHINE,
|
|
|
|
|
ARG_UNIT,
|
|
|
|
|
ARG_PROPERTY,
|
|
|
|
|
ARG_DESCRIPTION,
|
|
|
|
|
ARG_SLICE,
|
|
|
|
|
ARG_SLICE_INHERIT,
|
|
|
|
|
ARG_NICE,
|
|
|
|
|
ARG_SETENV,
|
2023-12-20 12:09:27 +01:00
|
|
|
ARG_BACKGROUND,
|
2024-10-24 23:27:59 +02:00
|
|
|
ARG_PTY,
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
ARG_PTY_LATE,
|
2024-10-24 23:27:59 +02:00
|
|
|
ARG_PIPE,
|
2024-10-24 11:36:48 +02:00
|
|
|
ARG_SHELL_PROMPT_PREFIX,
|
2025-01-14 11:50:52 +01:00
|
|
|
ARG_LIGHTWEIGHT,
|
2025-05-12 21:47:01 +02:00
|
|
|
ARG_AREA,
|
2025-04-09 00:55:27 +02:00
|
|
|
ARG_VIA_SHELL,
|
2023-12-19 19:10:52 +01:00
|
|
|
};
|
|
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
2023-12-19 19:10:52 +01:00
|
|
|
* though (but limit the extension to long options). */
|
|
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
2024-10-24 11:36:48 +02:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
|
{ "version", no_argument, NULL, 'V' },
|
|
|
|
|
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
|
|
|
|
{ "machine", required_argument, NULL, ARG_MACHINE },
|
|
|
|
|
{ "unit", required_argument, NULL, ARG_UNIT },
|
|
|
|
|
{ "property", required_argument, NULL, ARG_PROPERTY },
|
|
|
|
|
{ "description", required_argument, NULL, ARG_DESCRIPTION },
|
|
|
|
|
{ "slice", required_argument, NULL, ARG_SLICE },
|
|
|
|
|
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
|
|
|
|
|
{ "user", required_argument, NULL, 'u' },
|
|
|
|
|
{ "group", required_argument, NULL, 'g' },
|
|
|
|
|
{ "nice", required_argument, NULL, ARG_NICE },
|
|
|
|
|
{ "chdir", required_argument, NULL, 'D' },
|
2025-04-09 00:55:27 +02:00
|
|
|
{ "via-shell", no_argument, NULL, ARG_VIA_SHELL },
|
|
|
|
|
{ "login", no_argument, NULL, 'i' }, /* compat with sudo, --via-shell + --chdir='~' */
|
2024-10-24 11:36:48 +02:00
|
|
|
{ "setenv", required_argument, NULL, ARG_SETENV },
|
|
|
|
|
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
|
|
|
|
{ "pty", no_argument, NULL, ARG_PTY },
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
{ "pty-late", no_argument, NULL, ARG_PTY_LATE },
|
2024-10-24 11:36:48 +02:00
|
|
|
{ "pipe", no_argument, NULL, ARG_PIPE },
|
|
|
|
|
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
|
2025-01-14 11:50:52 +01:00
|
|
|
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
|
2025-05-12 21:47:01 +02:00
|
|
|
{ "area", required_argument, NULL, ARG_AREA },
|
2023-12-19 19:10:52 +01:00
|
|
|
{},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int r, c;
|
|
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
|
assert(argv);
|
|
|
|
|
|
|
|
|
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
|
|
|
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
|
|
|
|
optind = 0;
|
2025-05-12 21:47:01 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "+hVu:g:D:i", options, NULL)) >= 0)
|
2023-12-19 19:10:52 +01:00
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
|
return help_sudo_mode();
|
|
|
|
|
|
|
|
|
|
case 'V':
|
|
|
|
|
return version();
|
|
|
|
|
|
|
|
|
|
case ARG_NO_ASK_PASSWORD:
|
|
|
|
|
arg_ask_password = false;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_MACHINE:
|
2025-06-17 01:48:08 +02:00
|
|
|
r = parse_machine_argument(optarg, &arg_host, &arg_transport);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-12-19 19:10:52 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_UNIT:
|
|
|
|
|
arg_unit = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_PROPERTY:
|
|
|
|
|
if (strv_extend(&arg_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_DESCRIPTION:
|
|
|
|
|
r = free_and_strdup_warn(&arg_description, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SLICE:
|
|
|
|
|
arg_slice = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SLICE_INHERIT:
|
|
|
|
|
arg_slice_inherit = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
|
arg_exec_user = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'g':
|
|
|
|
|
arg_exec_group = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_NICE:
|
|
|
|
|
r = parse_nice(optarg, &arg_nice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to parse nice value: %s", optarg);
|
|
|
|
|
|
|
|
|
|
arg_nice_set = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'D':
|
2025-05-07 00:36:41 +02:00
|
|
|
if (streq(optarg, "~"))
|
|
|
|
|
r = free_and_strdup_warn(&arg_working_directory, optarg);
|
|
|
|
|
else
|
|
|
|
|
/* Root will be manually suppressed later. */
|
|
|
|
|
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_working_directory);
|
2023-12-19 19:10:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SETENV:
|
|
|
|
|
r = strv_env_replace_strdup_passthrough(&arg_environment, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-20 12:09:27 +01:00
|
|
|
case ARG_BACKGROUND:
|
|
|
|
|
r = free_and_strdup_warn(&arg_background, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2024-10-24 23:27:59 +02:00
|
|
|
case ARG_PTY:
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
case ARG_PTY_LATE:
|
2025-03-10 18:22:28 +09:00
|
|
|
arg_stdio |= ARG_STDIO_PTY;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
arg_pty_late = c == ARG_PTY_LATE;
|
2024-10-24 23:27:59 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_PIPE:
|
2025-03-10 18:22:28 +09:00
|
|
|
arg_stdio |= ARG_STDIO_DIRECT;
|
2024-10-24 23:27:59 +02:00
|
|
|
break;
|
|
|
|
|
|
2024-10-24 11:36:48 +02:00
|
|
|
case ARG_SHELL_PROMPT_PREFIX:
|
|
|
|
|
r = free_and_strdup_warn(&arg_shell_prompt_prefix, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2025-01-14 11:50:52 +01:00
|
|
|
case ARG_LIGHTWEIGHT:
|
|
|
|
|
r = parse_tristate_argument("--lightweight=", optarg, &arg_lightweight);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2025-05-12 21:47:01 +02:00
|
|
|
case ARG_AREA:
|
2025-01-24 10:24:09 +01:00
|
|
|
/* We allow an empty --area= specification to allow logging into the primary home directory */
|
|
|
|
|
if (!isempty(optarg) && !filename_is_valid(optarg))
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid area name, refusing: %s", optarg);
|
|
|
|
|
|
|
|
|
|
r = free_and_strdup_warn(&arg_area, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2025-04-09 00:55:27 +02:00
|
|
|
case 'i':
|
|
|
|
|
r = free_and_strdup_warn(&arg_working_directory, "~");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
_fallthrough_;
|
|
|
|
|
case ARG_VIA_SHELL:
|
|
|
|
|
arg_via_shell = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
case '?':
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-24 10:24:09 +01:00
|
|
|
if (!arg_exec_user && arg_area) {
|
|
|
|
|
/* If the user specifies --area= but not --user= then consider this an area switch request,
|
|
|
|
|
* and default to logging into our own account */
|
|
|
|
|
arg_exec_user = getusername_malloc();
|
|
|
|
|
if (!arg_exec_user)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
if (!arg_working_directory) {
|
|
|
|
|
if (arg_exec_user) {
|
|
|
|
|
/* When switching to a specific user, also switch to its home directory. */
|
|
|
|
|
arg_working_directory = strdup("~");
|
|
|
|
|
if (!arg_working_directory)
|
|
|
|
|
return log_oom();
|
|
|
|
|
} else {
|
|
|
|
|
/* When switching to root without this being specified, then stay in the current directory */
|
|
|
|
|
r = safe_getcwd(&arg_working_directory);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get current working directory: %m");
|
|
|
|
|
}
|
2024-10-15 00:57:52 -04:00
|
|
|
} else {
|
|
|
|
|
/* Root was not suppressed earlier, to allow the above check to work properly. */
|
|
|
|
|
if (empty_or_root(arg_working_directory))
|
|
|
|
|
arg_working_directory = mfree(arg_working_directory);
|
2023-12-19 19:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg_service_type = "exec";
|
|
|
|
|
arg_quiet = true;
|
|
|
|
|
arg_wait = true;
|
|
|
|
|
arg_aggressive_gc = true;
|
|
|
|
|
|
2024-10-24 23:27:59 +02:00
|
|
|
if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO))
|
|
|
|
|
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
2025-01-14 11:50:52 +01:00
|
|
|
log_debug("Using %s stdio mode.", arg_stdio == ARG_STDIO_PTY ? "pty" : "direct");
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (arg_pty_late < 0)
|
|
|
|
|
arg_pty_late = arg_ask_password; /* for run0 this defaults to on, except if --no-ask-pasword is used */
|
2025-01-14 11:50:52 +01:00
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
arg_expand_environment = false;
|
|
|
|
|
arg_send_sighup = true;
|
|
|
|
|
|
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
2025-04-09 00:55:27 +02:00
|
|
|
if (argc > optind) {
|
2023-12-19 19:10:52 +01:00
|
|
|
l = strv_copy(argv + optind);
|
2025-04-09 00:55:27 +02:00
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
} else if (!arg_via_shell) {
|
2023-12-19 19:10:52 +01:00
|
|
|
const char *e;
|
|
|
|
|
|
|
|
|
|
e = strv_env_get(arg_environment, "SHELL");
|
2025-04-08 22:35:14 +02:00
|
|
|
if (e) {
|
2023-12-19 19:10:52 +01:00
|
|
|
arg_exec_path = strdup(e);
|
2025-04-08 22:35:14 +02:00
|
|
|
if (!arg_exec_path)
|
|
|
|
|
return log_oom();
|
|
|
|
|
} else {
|
2023-12-19 19:10:52 +01:00
|
|
|
if (arg_transport == BUS_TRANSPORT_LOCAL) {
|
|
|
|
|
r = get_shell(&arg_exec_path);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to determine shell: %m");
|
2025-04-08 22:35:14 +02:00
|
|
|
} else {
|
2023-12-19 19:10:52 +01:00
|
|
|
arg_exec_path = strdup("/bin/sh");
|
2025-04-08 22:35:14 +02:00
|
|
|
if (!arg_exec_path)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = strv_env_assign(&arg_environment, "SHELL", arg_exec_path);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SHELL environment variable: %m");
|
2023-12-19 19:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
l = make_login_shell_cmdline(arg_exec_path);
|
2025-04-09 00:55:27 +02:00
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_via_shell) {
|
|
|
|
|
arg_exec_path = strdup(_PATH_BSHELL);
|
|
|
|
|
if (!arg_exec_path)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = strv_prepend(&l, "-sh");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
2023-12-19 19:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(arg_cmdline, l);
|
|
|
|
|
|
|
|
|
|
if (!arg_slice) {
|
2024-01-04 15:22:54 +01:00
|
|
|
arg_slice = strdup(SPECIAL_USER_SLICE);
|
2023-12-19 19:10:52 +01:00
|
|
|
if (!arg_slice)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cleanup_free_ char *un = NULL;
|
|
|
|
|
un = getusername_malloc();
|
|
|
|
|
if (!un)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
/* Set a bunch of environment variables in a roughly sudo-compatible way */
|
|
|
|
|
r = strv_env_assign(&arg_environment, "SUDO_USER", un);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SUDO_USER environment variable: %m");
|
|
|
|
|
|
|
|
|
|
r = strv_env_assignf(&arg_environment, "SUDO_UID", UID_FMT, getuid());
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SUDO_UID environment variable: %m");
|
|
|
|
|
|
|
|
|
|
r = strv_env_assignf(&arg_environment, "SUDO_GID", GID_FMT, getgid());
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SUDO_GID environment variable: %m");
|
|
|
|
|
|
|
|
|
|
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_UID=" UID_FMT, getuid()) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_GID=" GID_FMT, getgid()) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_USER=%s", un) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
if (strv_extend(&arg_property, "PAMName=systemd-run0") < 0)
|
2023-12-19 19:10:52 +01:00
|
|
|
return log_oom();
|
|
|
|
|
|
2025-04-15 21:19:25 +02:00
|
|
|
/* The service manager ignores SIGPIPE for all spawned processes by default. Let's explicitly override
|
|
|
|
|
* that here, since we're primarily invoked in interactive environments where this does matter. */
|
|
|
|
|
if (strv_extend(&arg_property, "IgnoreSIGPIPE=no") < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2024-05-02 17:07:51 +02:00
|
|
|
if (!arg_background && arg_stdio == ARG_STDIO_PTY && shall_tint_background()) {
|
2024-01-19 23:59:54 +01:00
|
|
|
double hue;
|
2023-12-20 12:09:27 +01:00
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
if (privileged_execution())
|
2024-01-19 23:59:54 +01:00
|
|
|
hue = 0; /* red */
|
|
|
|
|
else
|
|
|
|
|
hue = 60 /* yellow */;
|
|
|
|
|
|
|
|
|
|
r = terminal_tint_color(hue, &arg_background);
|
2023-12-20 12:09:27 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 11:36:48 +02:00
|
|
|
if (!arg_shell_prompt_prefix) {
|
|
|
|
|
const char *e = secure_getenv("SYSTEMD_RUN_SHELL_PROMPT_PREFIX");
|
|
|
|
|
if (e) {
|
|
|
|
|
arg_shell_prompt_prefix = strdup(e);
|
|
|
|
|
if (!arg_shell_prompt_prefix)
|
|
|
|
|
return log_oom();
|
|
|
|
|
} else if (emoji_enabled()) {
|
2025-03-14 10:42:04 +01:00
|
|
|
arg_shell_prompt_prefix = strjoin(glyph(privileged_execution() ? GLYPH_SUPERHERO : GLYPH_IDCARD), " ");
|
2024-10-24 11:36:48 +02:00
|
|
|
if (!arg_shell_prompt_prefix)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!isempty(arg_shell_prompt_prefix)) {
|
|
|
|
|
r = strv_env_assign(&arg_environment, "SHELL_PROMPT_PREFIX", arg_shell_prompt_prefix);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-24 10:24:09 +01:00
|
|
|
if (!strv_env_get(arg_environment, "XDG_SESSION_CLASS")) {
|
|
|
|
|
|
|
|
|
|
/* If logging into an area, imply lightweight mode */
|
|
|
|
|
if (arg_lightweight < 0 && !isempty(arg_area))
|
|
|
|
|
arg_lightweight = true;
|
|
|
|
|
|
|
|
|
|
/* When using run0 to acquire privileges temporarily, let's not pull in session manager by
|
|
|
|
|
* default. Note that pam_logind/systemd-logind doesn't distinguish between run0-style privilege
|
|
|
|
|
* escalation on a TTY and first class (getty-style) TTY logins (and thus gives root a per-session
|
|
|
|
|
* manager for interactive TTY sessions), hence let's override the logic explicitly here. We only do
|
|
|
|
|
* this for root though, under the assumption that if a regular user temporarily transitions into
|
|
|
|
|
* another regular user it's a better default that the full user environment is uniformly
|
|
|
|
|
* available. */
|
|
|
|
|
if (arg_lightweight < 0 && privileged_execution())
|
|
|
|
|
arg_lightweight = true;
|
|
|
|
|
|
|
|
|
|
if (arg_lightweight >= 0) {
|
|
|
|
|
const char *class =
|
|
|
|
|
arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early-light" : "user-light") : "background-light") :
|
|
|
|
|
(arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early" : "user") : "background");
|
2025-01-14 11:50:52 +01:00
|
|
|
|
2025-01-24 10:24:09 +01:00
|
|
|
log_debug("Setting XDG_SESSION_CLASS to '%s'.", class);
|
2025-01-14 11:50:52 +01:00
|
|
|
|
2025-01-24 10:24:09 +01:00
|
|
|
r = strv_env_assign(&arg_environment, "XDG_SESSION_CLASS", class);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $XDG_SESSION_CLASS environment variable: %m");
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-14 11:50:52 +01:00
|
|
|
|
2025-01-24 10:24:09 +01:00
|
|
|
if (arg_area) {
|
|
|
|
|
r = strv_env_assign(&arg_environment, "XDG_AREA", arg_area);
|
2025-01-14 11:50:52 +01:00
|
|
|
if (r < 0)
|
2025-01-24 10:24:09 +01:00
|
|
|
return log_error_errno(r, "Failed to set $XDG_AREA environment variable: %m");
|
2025-01-14 11:50:52 +01:00
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
|
2013-06-28 04:12:58 +02:00
|
|
|
int r;
|
|
|
|
|
|
2023-10-16 11:31:38 +02:00
|
|
|
assert(m);
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2017-11-13 17:17:53 +01:00
|
|
|
if (arg_aggressive_gc) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "CollectMode", "s", "inactive-or-failed");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2017-11-13 17:17:53 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-16 11:31:38 +02:00
|
|
|
r = sd_bus_is_bus_client(sd_bus_message_get_bus(m));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Can't determine if bus connection is direct or to broker: %m");
|
|
|
|
|
if (r > 0) {
|
|
|
|
|
/* Pin the object as least as long as we are around. Note that AddRef (currently) only works
|
|
|
|
|
* if we talk via the bus though. */
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "AddRef", "b", 1);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-16 18:41:00 +02:00
|
|
|
return bus_append_unit_property_assignment_many(m, t, properties);
|
2014-12-22 19:45:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int transient_cgroup_set_properties(sd_bus_message *m) {
|
2020-04-08 14:57:52 +02:00
|
|
|
_cleanup_free_ char *name = NULL;
|
|
|
|
|
_cleanup_free_ char *slice = NULL;
|
2014-12-22 19:45:32 +01:00
|
|
|
int r;
|
2024-07-10 21:58:12 +02:00
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
assert(m);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2020-04-08 14:57:52 +02:00
|
|
|
if (arg_slice_inherit) {
|
|
|
|
|
char *end;
|
2013-07-01 03:02:42 +02:00
|
|
|
|
2023-03-10 09:47:10 +01:00
|
|
|
switch (arg_runtime_scope) {
|
|
|
|
|
|
|
|
|
|
case RUNTIME_SCOPE_USER:
|
2020-04-08 14:57:52 +02:00
|
|
|
r = cg_pid_get_user_slice(0, &name);
|
2023-03-10 09:47:10 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RUNTIME_SCOPE_SYSTEM:
|
2020-04-08 14:57:52 +02:00
|
|
|
r = cg_pid_get_slice(0, &name);
|
2023-03-10 09:47:10 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
2020-04-08 14:57:52 +02:00
|
|
|
return log_error_errno(r, "Failed to get PID slice: %m");
|
2013-07-01 03:02:42 +02:00
|
|
|
|
2020-04-08 14:57:52 +02:00
|
|
|
end = endswith(name, ".slice");
|
|
|
|
|
if (!end)
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
*end = 0;
|
2013-07-01 03:02:42 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-20 14:41:48 +09:00
|
|
|
if (!isempty(arg_slice) && !strextend_with_separator(&name, "-", arg_slice))
|
|
|
|
|
return log_oom();
|
2020-04-08 14:57:52 +02:00
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = unit_name_mangle_with_suffix(name, "as slice",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".slice", &slice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle name '%s': %m", arg_slice);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int transient_kill_set_properties(sd_bus_message *m) {
|
2017-11-29 20:05:22 +01:00
|
|
|
int r;
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
assert(m);
|
|
|
|
|
|
2017-11-29 20:05:22 +01:00
|
|
|
if (arg_send_sighup) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
static int transient_service_set_properties(sd_bus_message *m, const char *pty_path, int pty_fd) {
|
2025-03-02 14:35:59 +01:00
|
|
|
int r, send_term; /* tri-state */
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2025-04-09 00:55:27 +02:00
|
|
|
/* Use ExecStartEx if new exec flags are required. */
|
|
|
|
|
bool use_ex_prop = !arg_expand_environment || arg_via_shell;
|
2023-04-02 23:17:58 +02:00
|
|
|
|
2013-11-08 19:49:49 +01:00
|
|
|
assert(m);
|
2025-01-15 17:27:25 +01:00
|
|
|
assert((!!pty_path) == (pty_fd >= 0));
|
2013-11-08 19:49:49 +01:00
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
r = transient_unit_set_properties(m, UNIT_SERVICE, arg_property);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = transient_kill_set_properties(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = transient_cgroup_set_properties(m);
|
2013-11-21 20:05:49 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2014-03-05 03:36:22 +01:00
|
|
|
if (arg_remain_after_exit) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-03-05 03:36:22 +01:00
|
|
|
}
|
2013-07-26 16:09:25 +02:00
|
|
|
|
2014-02-05 02:02:00 +01:00
|
|
|
if (arg_service_type) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_user) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_group) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_nice_set) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 12:07:25 +01:00
|
|
|
if (arg_working_directory) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "WorkingDirectory", "s", arg_working_directory);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
if (pty_path) {
|
2025-01-15 17:27:25 +01:00
|
|
|
r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)",
|
|
|
|
|
"TTYPath", "s", pty_path,
|
|
|
|
|
"StandardInputFileDescriptor", "h", pty_fd,
|
|
|
|
|
"StandardOutputFileDescriptor", "h", pty_fd,
|
|
|
|
|
"StandardErrorFileDescriptor", "h", pty_fd);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
send_term = true;
|
|
|
|
|
|
|
|
|
|
} else if (arg_stdio == ARG_STDIO_DIRECT) {
|
|
|
|
|
r = sd_bus_message_append(m,
|
|
|
|
|
"(sv)(sv)(sv)",
|
|
|
|
|
"StandardInputFileDescriptor", "h", STDIN_FILENO,
|
|
|
|
|
"StandardOutputFileDescriptor", "h", STDOUT_FILENO,
|
|
|
|
|
"StandardErrorFileDescriptor", "h", STDERR_FILENO);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2017-09-08 15:38:40 +02:00
|
|
|
|
2025-01-31 15:06:34 +01:00
|
|
|
send_term = -1;
|
2025-03-02 14:35:59 +01:00
|
|
|
} else
|
|
|
|
|
send_term = false;
|
2017-09-08 15:38:40 +02:00
|
|
|
|
2025-01-31 15:06:34 +01:00
|
|
|
if (send_term != 0) {
|
2025-03-17 09:52:52 +01:00
|
|
|
const char *e, *colorterm = NULL, *no_color = NULL;
|
2017-09-08 15:38:40 +02:00
|
|
|
|
2025-03-17 09:52:52 +01:00
|
|
|
/* Propagate $TERM + $COLORTERM + $NO_COLOR if we are actually connected to a TTY */
|
2025-01-31 15:06:34 +01:00
|
|
|
if (isatty_safe(STDIN_FILENO) || isatty_safe(STDOUT_FILENO) || isatty_safe(STDERR_FILENO)) {
|
2025-03-17 09:52:52 +01:00
|
|
|
e = strv_find_prefix(environ, "TERM=");
|
2025-03-02 14:35:59 +01:00
|
|
|
send_term = !!e;
|
2025-03-17 09:52:52 +01:00
|
|
|
|
|
|
|
|
if (send_term) {
|
|
|
|
|
/* If we send $TERM along, then also propagate $COLORTERM + $NO_COLOR right with it */
|
|
|
|
|
colorterm = strv_find_prefix(environ, "COLORTERM=");
|
|
|
|
|
no_color = strv_find_prefix(environ, "NO_COLOR=");
|
|
|
|
|
}
|
2025-01-31 15:06:34 +01:00
|
|
|
} else
|
|
|
|
|
/* If we are not connected to any TTY ourselves, then send TERM=dumb, but only if we
|
|
|
|
|
* really need to (because we actually allocated a TTY for the service) */
|
2025-03-17 09:52:52 +01:00
|
|
|
e = "TERM=dumb";
|
2025-01-31 15:06:34 +01:00
|
|
|
|
|
|
|
|
if (send_term > 0) {
|
2025-03-17 09:52:52 +01:00
|
|
|
r = sd_bus_message_append(
|
|
|
|
|
m,
|
|
|
|
|
"(sv)",
|
|
|
|
|
"Environment", "as", 1, e);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2025-03-17 09:52:52 +01:00
|
|
|
|
|
|
|
|
if (colorterm) {
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
|
m,
|
|
|
|
|
"(sv)",
|
|
|
|
|
"Environment", "as", 1, colorterm);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (no_color) {
|
|
|
|
|
r = sd_bus_message_append(
|
|
|
|
|
m,
|
|
|
|
|
"(sv)",
|
|
|
|
|
"Environment", "as", 1, no_color);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
2014-12-22 19:45:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-05 02:02:00 +01:00
|
|
|
if (!strv_isempty(arg_environment)) {
|
|
|
|
|
r = sd_bus_message_open_container(m, 'r', "sv");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "s", "Environment");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'v', "as");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, arg_environment);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Exec container */
|
2018-11-22 19:24:48 +01:00
|
|
|
if (!strv_isempty(arg_cmdline)) {
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
r = sd_bus_message_open_container(m, 'r', "sv");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_append(m, "s",
|
|
|
|
|
use_ex_prop ? "ExecStartEx" : "ExecStart");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_open_container(m, 'v',
|
|
|
|
|
use_ex_prop ? "a(sasas)" : "a(sasb)");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_open_container(m, 'a',
|
|
|
|
|
use_ex_prop ? "(sasas)" : "(sasb)");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_open_container(m, 'r',
|
|
|
|
|
use_ex_prop ? "sasas" : "sasb");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
r = sd_bus_message_append(m, "s", arg_exec_path ?: arg_cmdline[0]);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
r = sd_bus_message_append_strv(m, arg_cmdline);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2024-07-10 22:27:21 +02:00
|
|
|
if (use_ex_prop) {
|
|
|
|
|
_cleanup_strv_free_ char **opts = NULL;
|
|
|
|
|
|
|
|
|
|
r = exec_command_flags_to_strv(
|
2025-04-09 00:55:27 +02:00
|
|
|
(arg_expand_environment ? 0 : EXEC_COMMAND_NO_ENV_EXPAND)|
|
|
|
|
|
(arg_ignore_failure ? EXEC_COMMAND_IGNORE_FAILURE : 0)|
|
|
|
|
|
(arg_via_shell ? EXEC_COMMAND_VIA_SHELL : 0),
|
2024-07-10 22:27:21 +02:00
|
|
|
&opts);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to format execute flags: %m");
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, opts);
|
|
|
|
|
} else
|
2023-12-19 21:39:50 +01:00
|
|
|
r = sd_bus_message_append(m, "b", arg_ignore_failure);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
static int transient_scope_set_properties(sd_bus_message *m, bool allow_pidfd) {
|
2014-12-22 19:45:32 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
r = transient_unit_set_properties(m, UNIT_SCOPE, arg_property);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = transient_kill_set_properties(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2016-04-22 17:31:40 +02:00
|
|
|
r = transient_cgroup_set_properties(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2024-03-22 17:03:35 +01:00
|
|
|
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
2023-10-05 09:55:28 +02:00
|
|
|
|
2024-03-22 17:03:35 +01:00
|
|
|
r = pidref_set_self(&pidref);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:02:03 +02:00
|
|
|
|
2024-03-22 17:03:35 +01:00
|
|
|
r = bus_append_scope_pidref(m, &pidref, allow_pidfd);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
static int transient_timer_set_properties(sd_bus_message *m) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
r = transient_unit_set_properties(m, UNIT_TIMER, arg_timer_property);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2015-11-17 20:38:12 +01:00
|
|
|
/* Automatically clean up our transient timers */
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "RemainAfterElapse", "b", false);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2015-11-17 20:38:12 +01:00
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 12:04:43 +02:00
|
|
|
static int make_unit_name(UnitType t, char **ret) {
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(t >= 0);
|
|
|
|
|
assert(t < _UNIT_TYPE_MAX);
|
2024-04-06 00:00:41 +01:00
|
|
|
assert(ret);
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
2024-10-24 12:04:43 +02:00
|
|
|
/* Preferably use our PID + pidfd ID as identifier, if available. It's a boot time unique identifier
|
|
|
|
|
* managed by the kernel. Unfortunately only new kernels support this, hence we keep some fallback
|
|
|
|
|
* logic in place. */
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
2024-10-24 12:04:43 +02:00
|
|
|
_cleanup_(pidref_done) PidRef self = PIDREF_NULL;
|
|
|
|
|
r = pidref_set_self(&self);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get reference to my own process: %m");
|
|
|
|
|
|
|
|
|
|
r = pidref_acquire_pidfd_id(&self);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_debug_errno(r, "Failed to acquire pidfd ID of myself, defaulting to randomized unit name: %m");
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
2024-10-24 12:04:43 +02:00
|
|
|
/* We couldn't get the pidfd id. In that case, just pick a random uuid as name */
|
|
|
|
|
sd_id128_t rnd;
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
r = sd_id128_randomize(&rnd);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to generate random run unit name: %m");
|
|
|
|
|
|
2024-10-24 12:04:43 +02:00
|
|
|
r = asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t));
|
|
|
|
|
} else
|
|
|
|
|
r = asprintf(ret, "run-p" PID_FMT "-i%" PRIu64 ".%s", self.pid, self.fd_id, unit_type_to_string(t));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
static int connect_bus(sd_bus **ret) {
|
|
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
|
|
|
|
|
* limited direct connection */
|
|
|
|
|
if (arg_wait ||
|
|
|
|
|
arg_stdio != ARG_STDIO_NONE ||
|
|
|
|
|
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
|
|
|
|
|
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
|
|
|
|
|
else
|
|
|
|
|
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
|
|
|
|
|
|
|
|
|
|
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
|
|
|
|
|
|
|
|
|
*ret = TAKE_PTR(bus);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
typedef struct RunContext {
|
|
|
|
|
sd_event *event;
|
|
|
|
|
PTYForward *forward;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
char *unit;
|
2024-10-24 15:08:22 +02:00
|
|
|
char *bus_path;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
char *start_job;
|
|
|
|
|
int pty_fd;
|
2024-10-24 15:08:22 +02:00
|
|
|
|
|
|
|
|
/* Bus objects */
|
|
|
|
|
sd_bus *bus;
|
|
|
|
|
sd_bus_slot *match_properties_changed;
|
|
|
|
|
sd_bus_slot *match_disconnected;
|
|
|
|
|
sd_event_source *retry_timer;
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2020-05-26 16:22:36 +02:00
|
|
|
/* Current state of the unit */
|
2016-08-17 14:24:17 +02:00
|
|
|
char *active_state;
|
2025-03-11 05:15:11 +09:00
|
|
|
char *job;
|
2020-05-26 16:22:36 +02:00
|
|
|
|
|
|
|
|
/* The exit data of the unit */
|
2016-08-17 14:24:17 +02:00
|
|
|
uint64_t inactive_exit_usec;
|
|
|
|
|
uint64_t inactive_enter_usec;
|
|
|
|
|
char *result;
|
|
|
|
|
uint64_t cpu_usage_nsec;
|
2023-11-06 17:28:41 +01:00
|
|
|
uint64_t memory_peak;
|
2023-11-08 19:22:06 +01:00
|
|
|
uint64_t memory_swap_peak;
|
2017-09-26 16:33:03 +02:00
|
|
|
uint64_t ip_ingress_bytes;
|
|
|
|
|
uint64_t ip_egress_bytes;
|
2019-03-22 12:18:19 +01:00
|
|
|
uint64_t io_read_bytes;
|
|
|
|
|
uint64_t io_write_bytes;
|
2016-08-17 14:24:17 +02:00
|
|
|
uint32_t exit_code;
|
|
|
|
|
uint32_t exit_status;
|
|
|
|
|
} RunContext;
|
|
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
static int run_context_update(RunContext *c);
|
|
|
|
|
static int run_context_attach_bus(RunContext *c, sd_bus *bus);
|
|
|
|
|
static void run_context_detach_bus(RunContext *c);
|
|
|
|
|
static int run_context_reconnect(RunContext *c);
|
2025-03-11 05:15:11 +09:00
|
|
|
static int run_context_setup_ptyfwd(RunContext *c);
|
2024-10-24 15:08:22 +02:00
|
|
|
|
|
|
|
|
static void run_context_done(RunContext *c) {
|
2016-08-17 14:24:17 +02:00
|
|
|
assert(c);
|
|
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
run_context_detach_bus(c);
|
|
|
|
|
|
|
|
|
|
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
|
2016-08-17 14:24:17 +02:00
|
|
|
c->forward = pty_forward_free(c->forward);
|
|
|
|
|
c->event = sd_event_unref(c->event);
|
|
|
|
|
|
|
|
|
|
free(c->active_state);
|
2025-03-11 05:15:11 +09:00
|
|
|
free(c->job);
|
2016-08-17 14:24:17 +02:00
|
|
|
free(c->result);
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
free(c->unit);
|
2024-10-24 15:08:22 +02:00
|
|
|
free(c->bus_path);
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
free(c->start_job);
|
|
|
|
|
|
|
|
|
|
safe_close(c->pty_fd);
|
2024-10-24 15:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int on_retry_timer(sd_event_source *s, uint64_t usec, void *userdata) {
|
|
|
|
|
RunContext *c = ASSERT_PTR(userdata);
|
|
|
|
|
|
|
|
|
|
c->retry_timer = sd_event_source_disable_unref(c->retry_timer);
|
|
|
|
|
|
|
|
|
|
return run_context_reconnect(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int run_context_reconnect(RunContext *c) {
|
2025-03-17 20:08:51 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
_cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
|
2024-10-24 15:08:22 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
|
|
run_context_detach_bus(c);
|
|
|
|
|
|
|
|
|
|
r = connect_bus(&bus);
|
2025-03-17 20:08:51 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
goto retry_timer;
|
|
|
|
|
|
|
|
|
|
r = sd_bus_call_method(bus,
|
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
|
c->bus_path,
|
|
|
|
|
"org.freedesktop.systemd1.Unit",
|
|
|
|
|
"Ref",
|
|
|
|
|
&error,
|
2025-06-17 22:39:09 +09:00
|
|
|
/* ret_reply = */ NULL, NULL);
|
2024-10-24 15:08:22 +02:00
|
|
|
if (r < 0) {
|
2025-03-17 20:08:51 +01:00
|
|
|
/* Hmm, the service manager probably hasn't finished reexecution just yet? Try again later. */
|
2025-06-06 21:42:01 +09:00
|
|
|
if (bus_error_is_connection(&error) || bus_error_is_unknown_service(&error))
|
2025-03-17 20:08:51 +01:00
|
|
|
goto retry_timer;
|
|
|
|
|
|
|
|
|
|
if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
|
|
|
|
|
log_warning_errno(r, "Unit deactivated during reconnection to the bus, exiting.");
|
|
|
|
|
else
|
|
|
|
|
log_error_errno(r, "Failed to re-add reference to unit: %s", bus_error_message(&error, r));
|
2024-10-24 15:08:22 +02:00
|
|
|
|
2025-03-17 20:08:51 +01:00
|
|
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
|
|
|
|
return r;
|
2024-10-24 15:08:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = run_context_attach_bus(c, bus);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_info("Reconnected to bus.");
|
|
|
|
|
|
|
|
|
|
return run_context_update(c);
|
2025-03-17 20:08:51 +01:00
|
|
|
|
|
|
|
|
retry_timer:
|
|
|
|
|
log_warning_errno(r, "Failed to reconnect, retrying in 2s: %m");
|
|
|
|
|
|
|
|
|
|
r = event_reset_time_relative(
|
|
|
|
|
c->event,
|
|
|
|
|
&c->retry_timer,
|
|
|
|
|
CLOCK_MONOTONIC,
|
|
|
|
|
2 * USEC_PER_SEC, /* accuracy= */ 0,
|
|
|
|
|
on_retry_timer, c,
|
|
|
|
|
SD_EVENT_PRIORITY_NORMAL,
|
|
|
|
|
"retry-timeout",
|
|
|
|
|
/* force_reset= */ false);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
|
|
|
|
return log_error_errno(r, "Failed to install retry timer: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-11 05:15:11 +09:00
|
|
|
static int run_context_check_started(RunContext *c) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
|
|
if (!c->start_job)
|
|
|
|
|
return 0; /* Already started? */
|
|
|
|
|
|
|
|
|
|
if (streq_ptr(c->start_job, c->job))
|
|
|
|
|
return 0; /* The start job is still active. */
|
|
|
|
|
|
|
|
|
|
/* The start job is finished. */
|
|
|
|
|
c->start_job = mfree(c->start_job);
|
|
|
|
|
|
|
|
|
|
/* Setup ptyfwd now if --pty-late is specified. */
|
|
|
|
|
r = run_context_setup_ptyfwd(c);
|
|
|
|
|
if (r < 0) {
|
2025-03-17 00:11:12 +01:00
|
|
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
2025-03-11 05:15:11 +09:00
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (STRPTR_IN_SET(c->active_state, "inactive", "failed"))
|
|
|
|
|
return 0; /* Already finished or failed? */
|
|
|
|
|
|
|
|
|
|
/* Notify our caller that the service is now running, just in case. */
|
|
|
|
|
(void) sd_notifyf(/* unset_environment= */ false,
|
|
|
|
|
"READY=1\n"
|
|
|
|
|
"RUN_UNIT=%s",
|
|
|
|
|
c->unit);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
static void run_context_check_done(RunContext *c) {
|
2025-07-29 05:13:30 +09:00
|
|
|
int r;
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
assert(c);
|
|
|
|
|
|
2025-07-29 05:13:30 +09:00
|
|
|
if (!STRPTR_IN_SET(c->active_state, "inactive", "failed") ||
|
|
|
|
|
c->start_job || /* our start job */
|
|
|
|
|
c->job) /* any other job */
|
|
|
|
|
return;
|
2024-12-25 17:40:04 +09:00
|
|
|
|
2025-07-29 05:13:30 +09:00
|
|
|
if (!c->forward)
|
|
|
|
|
return (void) sd_event_exit(c->event, EXIT_SUCCESS);
|
2024-12-25 17:40:04 +09:00
|
|
|
|
2025-07-29 05:13:30 +09:00
|
|
|
/* If the service is gone, it's time to drain the output */
|
|
|
|
|
r = pty_forward_drain(c->forward);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_error_errno(r, "Failed to drain PTY forwarder: %m");
|
|
|
|
|
return (void) sd_event_exit(c->event, EXIT_FAILURE);
|
|
|
|
|
}
|
2025-07-29 04:34:01 +09:00
|
|
|
|
|
|
|
|
/* Tell the forwarder to exit on the next vhangup(), so that we still flush out what might be queued
|
|
|
|
|
* and exit then. */
|
|
|
|
|
r = pty_forward_honor_vhangup(c->forward);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_error_errno(r, "Failed to make PTY forwarder honor vhangup(): %m");
|
|
|
|
|
return (void) sd_event_exit(c->event, EXIT_FAILURE);
|
|
|
|
|
}
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
2020-05-26 16:22:36 +02:00
|
|
|
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
2025-03-11 05:15:11 +09:00
|
|
|
char **p = ASSERT_PTR(userdata);
|
2020-05-26 16:22:36 +02:00
|
|
|
const char *job;
|
|
|
|
|
uint32_t id;
|
|
|
|
|
int r;
|
|
|
|
|
|
2025-03-11 05:15:11 +09:00
|
|
|
assert(m);
|
|
|
|
|
|
2020-05-26 16:22:36 +02:00
|
|
|
r = sd_bus_message_read(m, "(uo)", &id, &job);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2025-03-11 05:15:11 +09:00
|
|
|
return free_and_strdup(p, id == 0 ? NULL : job);
|
2020-05-26 16:22:36 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
static int run_context_update(RunContext *c) {
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
static const struct bus_properties_map map[] = {
|
2020-05-26 16:22:36 +02:00
|
|
|
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
|
|
|
|
|
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_exit_usec) },
|
|
|
|
|
{ "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_enter_usec) },
|
|
|
|
|
{ "Result", "s", NULL, offsetof(RunContext, result) },
|
|
|
|
|
{ "ExecMainCode", "i", NULL, offsetof(RunContext, exit_code) },
|
|
|
|
|
{ "ExecMainStatus", "i", NULL, offsetof(RunContext, exit_status) },
|
|
|
|
|
{ "CPUUsageNSec", "t", NULL, offsetof(RunContext, cpu_usage_nsec) },
|
2023-11-06 17:28:41 +01:00
|
|
|
{ "MemoryPeak", "t", NULL, offsetof(RunContext, memory_peak) },
|
2023-11-08 19:22:06 +01:00
|
|
|
{ "MemorySwapPeak", "t", NULL, offsetof(RunContext, memory_swap_peak) },
|
2020-05-26 16:22:36 +02:00
|
|
|
{ "IPIngressBytes", "t", NULL, offsetof(RunContext, ip_ingress_bytes) },
|
|
|
|
|
{ "IPEgressBytes", "t", NULL, offsetof(RunContext, ip_egress_bytes) },
|
|
|
|
|
{ "IOReadBytes", "t", NULL, offsetof(RunContext, io_read_bytes) },
|
|
|
|
|
{ "IOWriteBytes", "t", NULL, offsetof(RunContext, io_write_bytes) },
|
2025-03-11 05:15:11 +09:00
|
|
|
{ "Job", "(uo)", map_job, offsetof(RunContext, job) },
|
2016-08-17 14:24:17 +02:00
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
2017-02-08 17:59:58 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2016-08-17 14:24:17 +02:00
|
|
|
int r;
|
|
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
assert(c);
|
|
|
|
|
assert(c->bus);
|
|
|
|
|
|
|
|
|
|
r = bus_map_all_properties(
|
|
|
|
|
c->bus,
|
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
|
c->bus_path,
|
|
|
|
|
map,
|
|
|
|
|
BUS_MAP_STRDUP,
|
|
|
|
|
&error,
|
|
|
|
|
NULL,
|
|
|
|
|
c);
|
2016-08-17 14:24:17 +02:00
|
|
|
if (r < 0) {
|
2024-10-24 15:08:22 +02:00
|
|
|
/* If this is a connection error, then try to reconnect. This might be because the service
|
|
|
|
|
* manager is being restarted. Handle this gracefully. */
|
2025-06-06 21:42:01 +09:00
|
|
|
if (bus_error_is_connection(&error) || bus_error_is_unknown_service(&error)) {
|
2025-03-17 20:08:51 +01:00
|
|
|
log_info_errno(r, "Bus call failed due to connection problems. Trying to reconnect...");
|
2024-10-24 15:08:22 +02:00
|
|
|
/* Not propagating error, because we handled it already, by reconnecting. */
|
|
|
|
|
return run_context_reconnect(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
2017-02-08 17:59:58 +01:00
|
|
|
return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
2025-03-11 05:15:11 +09:00
|
|
|
r = run_context_check_started(c);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
run_context_check_done(c);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-23 22:56:39 +01:00
|
|
|
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2024-10-24 15:08:22 +02:00
|
|
|
return run_context_update(ASSERT_PTR(userdata));
|
|
|
|
|
}
|
2016-12-23 22:56:39 +01:00
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
static int on_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
|
|
|
|
/* If our connection gets terminated, then try to reconnect. This might be because the service
|
|
|
|
|
* manager is being restarted. Handle this gracefully. */
|
|
|
|
|
log_info("Got disconnected from bus connection. Trying to reconnect...");
|
|
|
|
|
return run_context_reconnect(ASSERT_PTR(userdata));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int run_context_attach_bus(RunContext *c, sd_bus *bus) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
|
|
|
|
assert(!c->bus);
|
|
|
|
|
assert(!c->match_properties_changed);
|
|
|
|
|
assert(!c->match_disconnected);
|
|
|
|
|
|
|
|
|
|
c->bus = sd_bus_ref(bus);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_match_signal_async(
|
|
|
|
|
c->bus,
|
|
|
|
|
&c->match_properties_changed,
|
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
|
c->bus_path,
|
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
|
"PropertiesChanged",
|
|
|
|
|
on_properties_changed, NULL, c);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to request PropertiesChanged signal match: %m");
|
|
|
|
|
|
|
|
|
|
r = sd_bus_match_signal_async(
|
|
|
|
|
bus,
|
|
|
|
|
&c->match_disconnected,
|
|
|
|
|
"org.freedesktop.DBus.Local",
|
|
|
|
|
/* path= */ NULL,
|
|
|
|
|
"org.freedesktop.DBus.Local",
|
|
|
|
|
"Disconnected",
|
|
|
|
|
on_disconnected, NULL, c);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to request Disconnected signal match: %m");
|
|
|
|
|
|
|
|
|
|
r = sd_bus_attach_event(c->bus, c->event, SD_EVENT_PRIORITY_NORMAL);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void run_context_detach_bus(RunContext *c) {
|
|
|
|
|
assert(c);
|
2016-12-23 22:56:39 +01:00
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
if (c->bus) {
|
|
|
|
|
(void) sd_bus_detach_event(c->bus);
|
|
|
|
|
c->bus = sd_bus_unref(c->bus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c->match_properties_changed = sd_bus_slot_unref(c->match_properties_changed);
|
|
|
|
|
c->match_disconnected = sd_bus_slot_unref(c->match_disconnected);
|
2016-12-23 22:56:39 +01:00
|
|
|
}
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
2024-05-19 08:53:07 +08:00
|
|
|
RunContext *c = ASSERT_PTR(userdata);
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
|
|
2024-05-21 20:10:24 +08:00
|
|
|
if (rcode == -ECANCELED) {
|
2024-05-19 08:53:07 +08:00
|
|
|
log_debug_errno(rcode, "PTY forwarder disconnected.");
|
2024-05-21 20:10:24 +08:00
|
|
|
if (!arg_wait)
|
|
|
|
|
return sd_event_exit(c->event, EXIT_SUCCESS);
|
|
|
|
|
|
|
|
|
|
/* If --wait is specified, we'll only exit the pty forwarding, but will continue to wait
|
|
|
|
|
* for the service to end. If the user hits ^C we'll exit too. */
|
|
|
|
|
} else if (rcode < 0) {
|
2024-10-24 15:08:22 +02:00
|
|
|
(void) sd_event_exit(c->event, EXIT_FAILURE);
|
2016-08-17 14:24:17 +02:00
|
|
|
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-29 05:13:30 +09:00
|
|
|
c->forward = pty_forward_free(c->forward);
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
run_context_check_done(c);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
static int make_transient_service_unit(
|
|
|
|
|
sd_bus *bus,
|
|
|
|
|
sd_bus_message **message,
|
|
|
|
|
const char *service,
|
2024-06-06 13:30:09 +02:00
|
|
|
const char *pty_path,
|
|
|
|
|
int pty_fd) {
|
2023-04-02 22:27:58 +02:00
|
|
|
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(message);
|
|
|
|
|
assert(service);
|
|
|
|
|
|
|
|
|
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Name and mode */
|
2024-10-10 16:07:16 -04:00
|
|
|
r = sd_bus_message_append(m, "ss", service, job_mode_to_string(arg_job_mode));
|
2023-04-02 22:27:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Properties */
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
r = transient_service_set_properties(m, pty_path, pty_fd);
|
2023-04-02 22:27:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Auxiliary units */
|
|
|
|
|
r = sd_bus_message_append(m, "a(sa(sv))", 0);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
*message = TAKE_PTR(m);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
static int bus_call_with_hint(
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
sd_bus *bus,
|
2023-04-02 23:17:58 +02:00
|
|
|
sd_bus_message *message,
|
|
|
|
|
const char *name,
|
|
|
|
|
sd_bus_message **reply) {
|
|
|
|
|
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
int r;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_call(bus, message, 0, &error, reply);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_error_errno(r, "Failed to start transient %s unit: %s", name, bus_error_message(&error, r));
|
|
|
|
|
|
2024-07-10 21:58:12 +02:00
|
|
|
if (!arg_expand_environment &&
|
2023-04-02 23:17:58 +02:00
|
|
|
sd_bus_error_has_names(&error,
|
|
|
|
|
SD_BUS_ERROR_UNKNOWN_PROPERTY,
|
|
|
|
|
SD_BUS_ERROR_PROPERTY_READ_ONLY))
|
|
|
|
|
log_notice_errno(r, "Hint: --expand-environment=no is not supported by old systemd");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
static int acquire_invocation_id(sd_bus *bus, const char *unit, sd_id128_t *ret) {
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
|
_cleanup_free_ char *object = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
if (unit) {
|
|
|
|
|
object = unit_dbus_path_from_name(unit);
|
|
|
|
|
if (!object)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_bus_get_property(bus,
|
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
|
object ?: "/org/freedesktop/systemd1/unit/self",
|
|
|
|
|
"org.freedesktop.systemd1.Unit",
|
|
|
|
|
"InvocationID",
|
|
|
|
|
&error,
|
|
|
|
|
&reply,
|
|
|
|
|
"ay");
|
2025-06-06 19:50:34 +09:00
|
|
|
if (r < 0) {
|
|
|
|
|
/* Let's ignore connection errors. This might be caused by that the service manager is being
|
|
|
|
|
* restarted. Handle this gracefully. */
|
|
|
|
|
if (bus_error_is_connection(&error) || bus_error_is_unknown_service(&error)) {
|
|
|
|
|
log_debug_errno(r, "Invocation ID request failed due to bus connection problems, ignoring: %s",
|
|
|
|
|
bus_error_message(&error, r));
|
|
|
|
|
*ret = SD_ID128_NULL;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
return log_error_errno(r, "Failed to request invocation ID for unit: %s", bus_error_message(&error, r));
|
2025-06-06 19:50:34 +09:00
|
|
|
}
|
2023-10-12 12:03:03 +02:00
|
|
|
|
2024-03-01 14:47:52 +01:00
|
|
|
r = bus_message_read_id128(reply, ret);
|
2023-10-12 12:03:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2024-04-24 14:58:07 +09:00
|
|
|
return r; /* Return true when we get a non-null invocation ID. */
|
2023-10-12 12:03:03 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-30 16:48:12 +01:00
|
|
|
static int fchown_to_capsule(int fd, const char *capsule) {
|
2023-10-26 09:19:04 +02:00
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
2024-10-30 16:48:12 +01:00
|
|
|
assert(fd >= 0);
|
2023-10-26 09:19:04 +02:00
|
|
|
assert(capsule);
|
|
|
|
|
|
|
|
|
|
p = path_join("/run/capsules/", capsule);
|
|
|
|
|
if (!p)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
|
r = chase_and_stat(p, /* root= */ NULL, CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS, /* ret_path= */ NULL, &st);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
if (uid_is_system(st.st_uid) || gid_is_system(st.st_gid)) /* paranoid safety check */
|
|
|
|
|
return -EPERM;
|
|
|
|
|
|
2024-10-30 16:48:12 +01:00
|
|
|
return fchmod_and_chown(fd, 0600, st.st_uid, st.st_gid);
|
2023-10-26 09:19:04 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-12 15:15:15 +02:00
|
|
|
static int print_unit_invocation(const char *unit, sd_id128_t invocation_id) {
|
|
|
|
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(unit);
|
|
|
|
|
|
sd-json,tree-wide: add sd_json_format_enabled() and use it everwhere
We often used a pattern like if (!FLAGS_SET(flags, SD_JSON_FORMAT_OFF)),
which is rather verbose and also contains a double negative, which we try
to avoid. Add a little helper to avoid an explicit bit check.
This change clarifies an aditional thing: in some cases we treated
SD_JSON_FORMAT_OFF as a flag (flags & SD_JSON_FORMAT_OFF), while in other cases
we treated it as an independent enum value (flags == SD_JSON_FORMAT_OFF).
In the first form, flags like SD_JSON_FORMAT_SSE do _not_ turn the json
output on, while in the second form they do. Let's use the first form
everywhere.
No functional change intended.
Initially I wasn't sure if this helper should be made public or just internal,
but it seems such a common pattern that if we expose the flags, we might just
as well expose it too, to make life easier for any consumers.
2024-10-04 18:08:35 +02:00
|
|
|
if (!sd_json_format_enabled(arg_json_format_flags)) {
|
2024-08-12 15:15:15 +02:00
|
|
|
if (sd_id128_is_null(invocation_id))
|
|
|
|
|
log_info("Running as unit: %s", unit);
|
|
|
|
|
else
|
|
|
|
|
log_info("Running as unit: %s; invocation ID: " SD_ID128_FORMAT_STR, unit, SD_ID128_FORMAT_VAL(invocation_id));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_json_variant_set_field_string(&v, "unit", unit);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
if (!sd_id128_is_null(invocation_id)) {
|
2024-08-14 15:53:42 +09:00
|
|
|
r = sd_json_variant_set_field_id128(&v, "invocation_id", invocation_id);
|
2024-08-12 15:15:15 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
static int run_context_setup_ptyfwd(RunContext *c) {
|
|
|
|
|
int r;
|
2025-01-14 11:48:52 +01:00
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (c->pty_fd < 0 || c->forward)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
/* Stop agents now that we are online, to avoid TTY conflicts */
|
|
|
|
|
polkit_agent_close();
|
|
|
|
|
ask_password_agent_close();
|
|
|
|
|
|
|
|
|
|
if (!arg_quiet)
|
|
|
|
|
log_info("Press ^] three times within 1s to disconnect TTY.");
|
|
|
|
|
|
|
|
|
|
r = pty_forward_new(c->event, c->pty_fd, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c->forward);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
|
|
|
|
|
|
|
|
|
pty_forward_set_hangup_handler(c->forward, pty_forward_handler, c);
|
|
|
|
|
|
|
|
|
|
/* Make sure to process any TTY events before we process bus events */
|
|
|
|
|
(void) pty_forward_set_priority(c->forward, SD_EVENT_PRIORITY_IMPORTANT);
|
|
|
|
|
|
|
|
|
|
if (!isempty(arg_background))
|
|
|
|
|
(void) pty_forward_set_background_color(c->forward, arg_background);
|
|
|
|
|
|
2025-06-05 14:59:40 +09:00
|
|
|
(void) pty_forward_set_window_title(c->forward,
|
|
|
|
|
privileged_execution() ? GLYPH_RED_CIRCLE : GLYPH_YELLOW_CIRCLE,
|
|
|
|
|
arg_host, arg_cmdline);
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
return 0;
|
2025-01-14 11:48:52 +01:00
|
|
|
}
|
|
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
static int run_context_show_result(RunContext *c) {
|
|
|
|
|
int r;
|
|
|
|
|
|
2025-03-27 18:37:48 -04:00
|
|
|
assert(c);
|
|
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
_cleanup_(table_unrefp) Table *t = table_new_vertical();
|
|
|
|
|
if (!t)
|
|
|
|
|
return log_oom();
|
2025-03-27 18:37:48 -04:00
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
if (!isempty(c->result)) {
|
|
|
|
|
r = table_add_many(
|
|
|
|
|
t,
|
|
|
|
|
TABLE_FIELD, "Finished with result",
|
|
|
|
|
TABLE_STRING, c->result,
|
|
|
|
|
TABLE_SET_COLOR, streq(c->result, "success") ? ansi_highlight_green() : ansi_highlight_red());
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (c->exit_code > 0) {
|
|
|
|
|
r = table_add_cell(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
TABLE_FIELD,
|
|
|
|
|
"Main processes terminated with");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
|
|
r = table_add_cell_stringf(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
"code=%s, status=%u/%s",
|
|
|
|
|
sigchld_code_to_string(c->exit_code),
|
|
|
|
|
c->exit_status,
|
|
|
|
|
strna(c->exit_code == CLD_EXITED ?
|
|
|
|
|
exit_status_to_string(c->exit_status, EXIT_STATUS_FULL) :
|
|
|
|
|
signal_to_string(c->exit_status)));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
}
|
2025-03-27 18:37:48 -04:00
|
|
|
|
|
|
|
|
if (timestamp_is_set(c->inactive_enter_usec) &&
|
|
|
|
|
timestamp_is_set(c->inactive_exit_usec) &&
|
2025-03-27 19:08:55 -04:00
|
|
|
c->inactive_enter_usec > c->inactive_exit_usec) {
|
|
|
|
|
r = table_add_many(
|
|
|
|
|
t,
|
|
|
|
|
TABLE_FIELD, "Service runtime",
|
|
|
|
|
TABLE_TIMESPAN_MSEC, c->inactive_enter_usec - c->inactive_exit_usec);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
}
|
2025-03-27 18:37:48 -04:00
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
if (c->cpu_usage_nsec != NSEC_INFINITY) {
|
|
|
|
|
r = table_add_many(
|
|
|
|
|
t,
|
|
|
|
|
TABLE_FIELD, "CPU time consumed",
|
|
|
|
|
TABLE_TIMESPAN_MSEC, DIV_ROUND_UP(c->cpu_usage_nsec, NSEC_PER_USEC));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
}
|
2025-03-27 18:37:48 -04:00
|
|
|
|
|
|
|
|
if (c->memory_peak != UINT64_MAX) {
|
|
|
|
|
const char *swap;
|
|
|
|
|
|
|
|
|
|
if (c->memory_swap_peak != UINT64_MAX)
|
|
|
|
|
swap = strjoina(" (swap: ", FORMAT_BYTES(c->memory_swap_peak), ")");
|
|
|
|
|
else
|
|
|
|
|
swap = "";
|
|
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
r = table_add_cell(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
TABLE_FIELD, "Memory peak");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
|
|
r = table_add_cell_stringf(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
"%s%s",
|
|
|
|
|
FORMAT_BYTES(c->memory_peak), swap);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
2025-03-27 18:37:48 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char *ip_ingress = NULL, *ip_egress = NULL;
|
|
|
|
|
if (!IN_SET(c->ip_ingress_bytes, 0, UINT64_MAX))
|
2025-03-27 19:08:55 -04:00
|
|
|
ip_ingress = strjoina("received ", FORMAT_BYTES(c->ip_ingress_bytes));
|
2025-03-27 18:37:48 -04:00
|
|
|
if (!IN_SET(c->ip_egress_bytes, 0, UINT64_MAX))
|
2025-03-27 19:08:55 -04:00
|
|
|
ip_egress = strjoina("sent ", FORMAT_BYTES(c->ip_egress_bytes));
|
2025-03-27 18:37:48 -04:00
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
if (ip_ingress || ip_egress) {
|
|
|
|
|
r = table_add_cell(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
TABLE_FIELD, "IP Traffic");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
|
|
r = table_add_cell_stringf(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
"%s%s%s", strempty(ip_ingress), ip_ingress && ip_egress ? ", " : "", strempty(ip_egress));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
}
|
2025-03-27 18:37:48 -04:00
|
|
|
|
|
|
|
|
const char *io_read = NULL, *io_write = NULL;
|
|
|
|
|
if (!IN_SET(c->io_read_bytes, 0, UINT64_MAX))
|
2025-03-27 19:08:55 -04:00
|
|
|
io_read = strjoina("read ", FORMAT_BYTES(c->io_read_bytes));
|
2025-03-27 18:37:48 -04:00
|
|
|
if (!IN_SET(c->io_write_bytes, 0, UINT64_MAX))
|
2025-03-27 19:08:55 -04:00
|
|
|
io_write = strjoina("written ", FORMAT_BYTES(c->io_write_bytes));
|
|
|
|
|
|
|
|
|
|
if (io_read || io_write) {
|
|
|
|
|
r = table_add_cell(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
TABLE_FIELD, "IO Bytes");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
|
|
|
|
|
r = table_add_cell_stringf(
|
|
|
|
|
t,
|
|
|
|
|
/* ret_cell= */ NULL,
|
|
|
|
|
"%s%s%s", strempty(io_read), io_read && io_write ? ", " : "", strempty(io_write));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_add_error(r);
|
|
|
|
|
}
|
2025-03-27 18:37:48 -04:00
|
|
|
|
2025-03-27 19:08:55 -04:00
|
|
|
r = table_print(t, stderr);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return table_log_print_error(r);
|
|
|
|
|
|
|
|
|
|
return 0;
|
2025-03-27 18:37:48 -04:00
|
|
|
}
|
|
|
|
|
|
2023-04-02 21:50:19 +02:00
|
|
|
static int start_transient_service(sd_bus *bus) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-04-28 12:33:19 +02:00
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
_cleanup_free_ char *pty_path = NULL;
|
|
|
|
|
_cleanup_close_ int peer_fd = -EBADF;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
2024-08-16 20:00:25 +09:00
|
|
|
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
(void) ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
|
|
|
|
|
|
|
|
|
|
_cleanup_(run_context_done) RunContext c = {
|
|
|
|
|
.pty_fd = -EBADF,
|
|
|
|
|
.cpu_usage_nsec = NSEC_INFINITY,
|
|
|
|
|
.memory_peak = UINT64_MAX,
|
|
|
|
|
.memory_swap_peak = UINT64_MAX,
|
|
|
|
|
.ip_ingress_bytes = UINT64_MAX,
|
|
|
|
|
.ip_egress_bytes = UINT64_MAX,
|
|
|
|
|
.io_read_bytes = UINT64_MAX,
|
|
|
|
|
.io_write_bytes = UINT64_MAX,
|
|
|
|
|
.inactive_exit_usec = USEC_INFINITY,
|
|
|
|
|
.inactive_enter_usec = USEC_INFINITY,
|
|
|
|
|
};
|
2024-08-16 20:00:25 +09:00
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
if (arg_stdio == ARG_STDIO_PTY) {
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)) {
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
c.pty_fd = openpt_allocate(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK, &pty_path);
|
|
|
|
|
if (c.pty_fd < 0)
|
|
|
|
|
return log_error_errno(c.pty_fd, "Failed to acquire pseudo tty: %m");
|
2014-12-23 01:58:49 +01:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
peer_fd = pty_open_peer(c.pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
2024-10-30 16:48:12 +01:00
|
|
|
if (peer_fd < 0)
|
|
|
|
|
return log_error_errno(peer_fd, "Failed to open pty peer: %m");
|
2014-12-23 01:58:49 +01:00
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
if (arg_transport == BUS_TRANSPORT_CAPSULE) {
|
|
|
|
|
/* If we are in capsule mode, we must give the capsule UID/GID access to the PTY we just allocated first. */
|
|
|
|
|
|
2024-10-30 16:48:12 +01:00
|
|
|
r = fchown_to_capsule(peer_fd, arg_host);
|
2023-10-26 09:19:04 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to chown tty to capsule UID/GID: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-23 23:38:13 +01:00
|
|
|
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL;
|
2016-05-21 18:30:33 -04:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL;
|
2014-12-23 01:58:49 +01:00
|
|
|
const char *s;
|
|
|
|
|
|
2015-10-08 15:01:42 +02:00
|
|
|
r = sd_bus_default_system(&system_bus);
|
2014-12-23 01:58:49 +01:00
|
|
|
if (r < 0)
|
2015-10-08 15:01:42 +02:00
|
|
|
return log_error_errno(r, "Failed to connect to system bus: %m");
|
2014-12-23 01:58:49 +01:00
|
|
|
|
2024-08-16 20:00:25 +09:00
|
|
|
(void) sd_bus_set_allow_interactive_authorization(system_bus, arg_ask_password);
|
|
|
|
|
|
2025-06-04 18:28:35 +02:00
|
|
|
/* Chop off a username prefix. We allow this for sd-bus machine connections, hence
|
|
|
|
|
* support that here too. */
|
|
|
|
|
_cleanup_free_ char *h = NULL;
|
|
|
|
|
r = split_user_at_host(arg_host, /* ret_user= */ NULL, &h);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to split host specification '%s': %m", arg_host);
|
|
|
|
|
|
|
|
|
|
r = bus_call_method(
|
|
|
|
|
system_bus,
|
|
|
|
|
bus_machine_mgr,
|
|
|
|
|
"OpenMachinePTY",
|
|
|
|
|
&error,
|
|
|
|
|
&pty_reply,
|
|
|
|
|
"s", h ?: ".host");
|
2018-08-07 10:14:30 +09:00
|
|
|
if (r < 0)
|
2020-09-14 18:16:54 +02:00
|
|
|
return log_error_errno(r, "Failed to get machine PTY: %s", bus_error_message(&error, r));
|
2014-12-23 01:58:49 +01:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = sd_bus_message_read(pty_reply, "hs", &c.pty_fd, &s);
|
2014-12-23 01:58:49 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
c.pty_fd = fcntl(c.pty_fd, F_DUPFD_CLOEXEC, 3);
|
|
|
|
|
if (c.pty_fd < 0)
|
2014-12-23 01:58:49 +01:00
|
|
|
return log_error_errno(errno, "Failed to duplicate master fd: %m");
|
|
|
|
|
|
|
|
|
|
pty_path = strdup(s);
|
|
|
|
|
if (!pty_path)
|
|
|
|
|
return log_oom();
|
2024-06-06 13:30:09 +02:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
peer_fd = pty_open_peer(c.pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
2025-01-14 12:05:05 +01:00
|
|
|
if (peer_fd < 0)
|
2025-01-15 17:21:54 +01:00
|
|
|
return log_error_errno(peer_fd, "Failed to open PTY peer: %m");
|
2014-12-23 01:58:49 +01:00
|
|
|
} else
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2014-12-22 19:45:32 +01:00
|
|
|
}
|
|
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (arg_unit) {
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = unit_name_mangle_with_suffix(
|
|
|
|
|
arg_unit,
|
|
|
|
|
"as unit",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".service",
|
|
|
|
|
&c.unit);
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
} else {
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = make_unit_name(UNIT_SERVICE, &c.unit);
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2025-01-14 11:48:52 +01:00
|
|
|
/* Optionally, wait for the start job to complete. If we are supposed to read the service's stdin
|
|
|
|
|
* lets skip this however, because we should start that already when the start job is running, and
|
|
|
|
|
* there's little point in waiting for the start job to complete in that case anyway, as we'll wait
|
|
|
|
|
* for EOF anyway, which is going to be much later. */
|
2025-03-11 05:15:11 +09:00
|
|
|
if (!arg_no_block && arg_stdio == ARG_STDIO_NONE) {
|
|
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Could not watch jobs: %m");
|
2025-01-14 11:48:52 +01:00
|
|
|
}
|
|
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = make_transient_service_unit(bus, &m, c.unit, pty_path, peer_fd);
|
2013-06-28 04:12:58 +02:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return r;
|
2024-10-30 16:48:12 +01:00
|
|
|
peer_fd = safe_close(peer_fd);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2025-07-02 16:25:15 +02:00
|
|
|
_cleanup_(fork_notify_terminate) PidRef journal_pid = PIDREF_NULL;
|
2025-03-23 18:37:45 -04:00
|
|
|
if (arg_verbose)
|
2025-05-13 22:58:02 +02:00
|
|
|
(void) journal_fork(arg_runtime_scope, STRV_MAKE(c.unit), &journal_pid);
|
2025-03-23 18:37:45 -04:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = bus_call_with_hint(bus, m, "service", &reply);
|
2015-10-08 15:01:42 +02:00
|
|
|
if (r < 0)
|
2023-04-02 23:17:58 +02:00
|
|
|
return r;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2025-01-14 11:48:52 +01:00
|
|
|
const char *object;
|
|
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
2015-04-28 12:33:19 +02:00
|
|
|
|
2025-01-14 11:48:52 +01:00
|
|
|
if (w) {
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = bus_wait_for_jobs_one(
|
|
|
|
|
w,
|
|
|
|
|
object,
|
|
|
|
|
arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
|
|
|
|
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
2015-04-28 12:33:19 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2025-03-11 05:15:11 +09:00
|
|
|
} else if (!arg_no_block) {
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
c.start_job = strdup(object);
|
|
|
|
|
if (!c.start_job)
|
2025-01-14 11:48:52 +01:00
|
|
|
return log_oom();
|
2015-04-28 12:33:19 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
if (!arg_quiet) {
|
2024-08-14 15:45:31 +09:00
|
|
|
sd_id128_t invocation_id;
|
2023-10-12 12:03:03 +02:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = acquire_invocation_id(bus, c.unit, &invocation_id);
|
2023-10-12 12:03:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2024-08-12 15:15:15 +02:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
r = print_unit_invocation(c.unit, invocation_id);
|
2024-08-12 15:15:15 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:03:03 +02:00
|
|
|
}
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
c.bus_path = unit_dbus_path_from_name(c.unit);
|
|
|
|
|
if (!c.bus_path)
|
|
|
|
|
return log_oom();
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
r = sd_event_default(&c.event);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2014-12-22 19:45:32 +01:00
|
|
|
return log_error_errno(r, "Failed to get event loop: %m");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2024-11-18 12:46:50 +01:00
|
|
|
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
if (c.pty_fd >= 0) {
|
2025-03-02 14:45:28 +01:00
|
|
|
if (arg_exec_user && !terminal_is_dumb()) {
|
2024-11-18 12:46:50 +01:00
|
|
|
r = osc_context_open_chpriv(arg_exec_user, /* ret_seq= */ NULL, &osc_context_id);
|
|
|
|
|
if (r < 0)
|
2025-03-02 14:45:28 +01:00
|
|
|
return log_error_errno(r, "Failed to set OSC context: %m");
|
2024-11-18 12:46:50 +01:00
|
|
|
}
|
|
|
|
|
|
2024-02-23 12:19:43 +01:00
|
|
|
(void) sd_event_set_signal_exit(c.event, true);
|
2016-08-17 14:24:17 +02:00
|
|
|
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
assert(arg_pty_late >= 0);
|
|
|
|
|
if (!arg_pty_late) { /* If late PTY mode is off, start pty forwarder immediately */
|
|
|
|
|
r = run_context_setup_ptyfwd(&c);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
r = run_context_attach_bus(&c, bus);
|
2016-12-24 00:35:58 +01:00
|
|
|
if (r < 0)
|
2024-10-24 15:08:22 +02:00
|
|
|
return r;
|
2016-12-23 22:56:39 +01:00
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
r = run_context_update(&c);
|
2016-12-24 00:35:58 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
r = sd_event_loop(c.event);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2014-12-22 19:45:32 +01:00
|
|
|
return log_error_errno(r, "Failed to run event loop: %m");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2025-03-23 18:37:45 -04:00
|
|
|
/* Close the journal watch logic before we output the exit summary */
|
2025-07-02 16:25:15 +02:00
|
|
|
fork_notify_terminate(&journal_pid);
|
2025-03-23 18:37:45 -04:00
|
|
|
|
2025-03-27 18:37:48 -04:00
|
|
|
if (arg_wait && !arg_quiet)
|
|
|
|
|
run_context_show_result(&c);
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2019-10-29 18:07:07 +01:00
|
|
|
/* Try to propagate the service's return value. But if the service defines
|
|
|
|
|
* e.g. SuccessExitStatus, honour this, and return 0 to mean "success". */
|
|
|
|
|
if (streq_ptr(c.result, "success"))
|
2023-04-02 21:50:19 +02:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
if (streq_ptr(c.result, "exit-code") && c.exit_status > 0)
|
|
|
|
|
return c.exit_status;
|
|
|
|
|
if (streq_ptr(c.result, "signal"))
|
|
|
|
|
return EXIT_EXCEPTION;
|
|
|
|
|
return EXIT_FAILURE;
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
2014-03-05 19:02:53 +01:00
|
|
|
|
2023-04-02 21:50:19 +02:00
|
|
|
return EXIT_SUCCESS;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 20:40:00 +01:00
|
|
|
static int start_transient_scope(sd_bus *bus) {
|
2023-10-12 12:02:03 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2015-04-28 12:21:31 +02:00
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
2023-06-26 17:20:49 +02:00
|
|
|
_cleanup_strv_free_ char **env = NULL, **user_env = NULL;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
_cleanup_free_ char *scope = NULL;
|
2015-04-28 12:21:31 +02:00
|
|
|
const char *object = NULL;
|
2024-08-14 15:45:31 +09:00
|
|
|
sd_id128_t invocation_id;
|
2023-10-12 12:02:03 +02:00
|
|
|
bool allow_pidfd = true;
|
2013-07-01 00:03:57 +02:00
|
|
|
int r;
|
|
|
|
|
|
2013-11-08 19:49:49 +01:00
|
|
|
assert(bus);
|
2018-11-22 19:24:48 +01:00
|
|
|
assert(!strv_isempty(arg_cmdline));
|
2013-11-08 19:49:49 +01:00
|
|
|
|
2015-04-28 12:21:31 +02:00
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
|
if (r < 0)
|
2023-05-26 15:09:03 +02:00
|
|
|
return log_error_errno(r, "Could not watch jobs: %m");
|
2015-04-28 12:21:31 +02:00
|
|
|
|
2014-07-25 15:38:31 +02:00
|
|
|
if (arg_unit) {
|
2019-10-24 14:09:11 +02:00
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".scope", &scope);
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle scope name: %m");
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
} else {
|
2024-10-24 12:04:43 +02:00
|
|
|
r = make_unit_name(UNIT_SCOPE, &scope);
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2024-08-16 19:33:41 +09:00
|
|
|
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
(void) ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
for (;;) {
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-09-01 16:43:08 +00:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
/* Name and Mode */
|
2024-10-10 16:07:16 -04:00
|
|
|
r = sd_bus_message_append(m, "ss", scope, job_mode_to_string(arg_job_mode));
|
2023-10-12 12:02:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
/* Properties */
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
r = transient_scope_set_properties(m, allow_pidfd);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
2015-09-01 16:43:08 +00:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
/* Auxiliary units */
|
|
|
|
|
r = sd_bus_message_append(m, "a(sa(sv))", 0);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_call(bus, m, 0, &error, &reply);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
if (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY) && allow_pidfd) {
|
|
|
|
|
log_debug("Retrying with classic PIDs.");
|
|
|
|
|
allow_pidfd = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return log_error_errno(r, "Failed to start transient scope unit: %s", bus_error_message(&error, r));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2018-11-22 20:40:00 +01:00
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2023-12-14 15:22:14 +01:00
|
|
|
r = bus_wait_for_jobs_one(w, object, arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
|
|
|
|
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
2018-11-22 20:40:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
r = acquire_invocation_id(bus, NULL, &invocation_id);
|
2018-11-22 20:40:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:03:03 +02:00
|
|
|
if (r == 0)
|
|
|
|
|
log_debug("No invocation ID set.");
|
|
|
|
|
else {
|
|
|
|
|
if (strv_extendf(&user_env, "INVOCATION_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(invocation_id)) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
2018-11-22 20:40:00 +01:00
|
|
|
|
2025-03-17 16:01:26 +01:00
|
|
|
/* Stop agents before we pass control away and before we drop privileges, to avoid TTY conflicts and
|
|
|
|
|
* before we become unable to stop agents. */
|
|
|
|
|
polkit_agent_close();
|
|
|
|
|
ask_password_agent_close();
|
|
|
|
|
|
2014-03-05 18:57:21 +01:00
|
|
|
if (arg_nice_set) {
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to set nice level: %m");
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_group) {
|
|
|
|
|
gid_t gid;
|
|
|
|
|
|
2018-08-02 18:36:47 +02:00
|
|
|
r = get_group_creds(&arg_exec_group, &gid, 0);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
|
2014-03-05 18:57:21 +01:00
|
|
|
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setresgid(gid, gid, gid) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_user) {
|
|
|
|
|
const char *home, *shell;
|
|
|
|
|
uid_t uid;
|
|
|
|
|
gid_t gid;
|
|
|
|
|
|
2024-11-18 19:30:02 +01:00
|
|
|
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell,
|
|
|
|
|
USER_CREDS_CLEAN|USER_CREDS_SUPPRESS_PLACEHOLDER|USER_CREDS_PREFER_NSS);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
|
2014-03-05 18:57:21 +01:00
|
|
|
|
2016-08-25 10:24:10 +02:00
|
|
|
if (home) {
|
|
|
|
|
r = strv_extendf(&user_env, "HOME=%s", home);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
2014-03-05 18:57:21 +01:00
|
|
|
|
2016-08-25 10:24:10 +02:00
|
|
|
if (shell) {
|
|
|
|
|
r = strv_extendf(&user_env, "SHELL=%s", shell);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
2014-03-05 18:57:21 +01:00
|
|
|
|
|
|
|
|
r = strv_extendf(&user_env, "USER=%s", arg_exec_user);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = strv_extendf(&user_env, "LOGNAME=%s", arg_exec_user);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (!arg_exec_group) {
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setresgid(gid, gid, gid) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setresuid(uid, uid, uid) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid);
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-22 14:21:46 +02:00
|
|
|
if (arg_working_directory && chdir(arg_working_directory) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change directory to '%s': %m", arg_working_directory);
|
|
|
|
|
|
2021-08-07 10:16:19 +02:00
|
|
|
env = strv_env_merge(environ, user_env, arg_environment);
|
2014-03-05 18:57:21 +01:00
|
|
|
if (!env)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
if (!arg_quiet) {
|
2024-08-12 15:15:15 +02:00
|
|
|
r = print_unit_invocation(scope, invocation_id);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:03:03 +02:00
|
|
|
}
|
2014-03-05 19:02:53 +01:00
|
|
|
|
2024-07-10 21:58:12 +02:00
|
|
|
if (arg_expand_environment) {
|
2023-06-26 17:20:49 +02:00
|
|
|
_cleanup_strv_free_ char **expanded_cmdline = NULL, **unset_variables = NULL, **bad_variables = NULL;
|
|
|
|
|
|
|
|
|
|
r = replace_env_argv(arg_cmdline, env, &expanded_cmdline, &unset_variables, &bad_variables);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to expand environment variables: %m");
|
|
|
|
|
|
|
|
|
|
free_and_replace(arg_cmdline, expanded_cmdline);
|
|
|
|
|
|
|
|
|
|
if (!strv_isempty(unset_variables)) {
|
|
|
|
|
_cleanup_free_ char *ju = strv_join(unset_variables, ", ");
|
|
|
|
|
log_warning("Referenced but unset environment variable evaluates to an empty string: %s", strna(ju));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!strv_isempty(bad_variables)) {
|
|
|
|
|
_cleanup_free_ char *jb = strv_join(bad_variables, ", ");
|
|
|
|
|
log_warning("Invalid environment variable name evaluates to an empty string: %s", strna(jb));
|
|
|
|
|
}
|
2023-04-04 21:18:33 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
execvpe(arg_cmdline[0], arg_cmdline, env);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
return log_error_errno(errno, "Failed to execute: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
static int make_transient_trigger_unit(
|
2014-12-22 19:45:32 +01:00
|
|
|
sd_bus *bus,
|
2023-04-02 22:27:58 +02:00
|
|
|
sd_bus_message **message,
|
|
|
|
|
const char *suffix,
|
|
|
|
|
const char *trigger,
|
|
|
|
|
const char *service) {
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2014-12-22 19:45:32 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
2023-04-02 22:27:58 +02:00
|
|
|
assert(message);
|
|
|
|
|
assert(suffix);
|
|
|
|
|
assert(trigger);
|
|
|
|
|
assert(service);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2020-05-02 23:41:14 -07:00
|
|
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Name and Mode */
|
2024-10-10 16:07:16 -04:00
|
|
|
r = sd_bus_message_append(m, "ss", trigger, job_mode_to_string(arg_job_mode));
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Properties */
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2017-12-18 23:46:45 +09:00
|
|
|
if (streq(suffix, ".path"))
|
|
|
|
|
r = transient_unit_set_properties(m, UNIT_PATH, arg_path_property);
|
|
|
|
|
else if (streq(suffix, ".socket"))
|
|
|
|
|
r = transient_unit_set_properties(m, UNIT_SOCKET, arg_socket_property);
|
|
|
|
|
else if (streq(suffix, ".timer"))
|
|
|
|
|
r = transient_timer_set_properties(m);
|
|
|
|
|
else
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return r;
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
if (!strv_isempty(arg_cmdline)) {
|
2014-12-22 19:45:32 +01:00
|
|
|
r = sd_bus_message_open_container(m, 'r', "sa(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "s", service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
r = transient_service_set_properties(m, /* pty_path = */ NULL, /* pty_fd = */ -EBADF);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return r;
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
*message = TAKE_PTR(m);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int start_transient_trigger(sd_bus *bus, const char *suffix) {
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
|
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
|
|
|
|
_cleanup_free_ char *trigger = NULL, *service = NULL;
|
|
|
|
|
const char *object = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(suffix);
|
|
|
|
|
|
|
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
|
if (r < 0)
|
2023-05-26 15:09:03 +02:00
|
|
|
return log_error_errno(r, "Could not watch jobs: %m");
|
2023-04-02 22:27:58 +02:00
|
|
|
|
|
|
|
|
if (arg_unit) {
|
|
|
|
|
switch (unit_name_to_type(arg_unit)) {
|
|
|
|
|
|
|
|
|
|
case UNIT_SERVICE:
|
|
|
|
|
service = strdup(arg_unit);
|
|
|
|
|
if (!service)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = unit_name_change_suffix(service, suffix, &trigger);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to change unit suffix: %m");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case UNIT_TIMER:
|
|
|
|
|
trigger = strdup(arg_unit);
|
|
|
|
|
if (!trigger)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = unit_name_change_suffix(trigger, ".service", &service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to change unit suffix: %m");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".service", &service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
|
|
|
|
|
|
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as trigger",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
suffix, &trigger);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2024-10-24 12:04:43 +02:00
|
|
|
r = make_unit_name(UNIT_SERVICE, &service);
|
2023-04-02 22:27:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = unit_name_change_suffix(service, suffix, &trigger);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to change unit suffix: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = make_transient_trigger_unit(bus, &m, suffix, trigger, service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2024-08-16 19:33:41 +09:00
|
|
|
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
run0: run agents during setup, until pty forwarder takes over
When services start up they might query for passwords, or issue polkit
requests. Hence it makese sense to run the password query agent and
polkit agent from systemd-run. We already ran the polkit agent, this
also ensures we run the password query agent.
There's one tweak to the story though: running the agents and the pty
forwarder concurrently is messy, since they both try to read from stdin
(one potentially, the other definitely). Hence, let's time the agents
properly: invoke them when we initialize, but stop them once the start
job for the unit we are supposed to run is complete, and only then run
the pty forwarder.
With this in place, the following series of commands starts to work
really nicely (which previously deadlocked):
# homectl create foobar
# run0 -u foobar
What happens in the background in run0 is this: a new session is invoked
for "foobar", which pulls in the user@.service instance for the user.
That user@.service instance will need to unlock the homedir first. Since
8af1b296cb2cec8ddbb2cb47f4194269eb6cee2b this will happen via the askpw
logic. With this commit here this prompt will now be shown by run0. Once
the password is entered the directory is unlocked and the real session
begins. Nice!
This new behaviour is conditioned behind --pty-late (distinct from the
existing --pty switches). For systemd-run we will never enable this mode
by default, for compat with command lines that use ExecStartPre=
(because we won't process the pty anymore during that command) For
run0 however this changes the default to --pty-late (unless
--no-ask-password is specified). This reflects the fact that run0 is
more of an interctive tool and unlikely to be used in more complex
service start-up situations with ExecStartPre= and suchlike.
This also merges JobDoneContext into RunContext, since it doesn't really
make sense to have two contexts around to communicate between outer
stack frame and event handlers. Let's just have one, and pass it around
to all handlers the same way. In particular as we should delay exit only
until both the unit's job is complete *and* in case of --wait the unit
is exited, one of the two should not suffice.
2025-02-28 23:32:08 +01:00
|
|
|
(void) ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-09-01 16:43:08 +00:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = bus_call_with_hint(bus, m, suffix + 1, &reply);
|
2018-08-07 10:14:30 +09:00
|
|
|
if (r < 0)
|
2023-04-02 23:17:58 +02:00
|
|
|
return r;
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2015-04-28 12:21:31 +02:00
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2023-12-14 15:22:14 +01:00
|
|
|
r = bus_wait_for_jobs_one(w, object, arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
|
|
|
|
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
2015-04-28 12:21:31 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2016-08-24 03:12:18 -07:00
|
|
|
if (!arg_quiet) {
|
2017-12-18 23:46:45 +09:00
|
|
|
log_info("Running %s as unit: %s", suffix + 1, trigger);
|
2018-11-22 19:24:48 +01:00
|
|
|
if (!strv_isempty(arg_cmdline))
|
2016-08-24 03:12:18 -07:00
|
|
|
log_info("Will run service as unit: %s", service);
|
|
|
|
|
}
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2023-04-02 21:50:19 +02:00
|
|
|
return EXIT_SUCCESS;
|
2013-06-28 04:12:58 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-27 11:59:19 +01:00
|
|
|
static bool shall_make_executable_absolute(void) {
|
2023-12-19 19:10:52 +01:00
|
|
|
if (arg_exec_path)
|
|
|
|
|
return false;
|
2021-10-27 11:59:19 +01:00
|
|
|
if (strv_isempty(arg_cmdline))
|
|
|
|
|
return false;
|
|
|
|
|
if (arg_transport != BUS_TRANSPORT_LOCAL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
FOREACH_STRING(f, "RootDirectory=", "RootImage=", "ExecSearchPath=", "MountImages=", "ExtensionImages=")
|
|
|
|
|
if (strv_find_startswith(arg_property, f))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 19:30:03 +01:00
|
|
|
static int run(int argc, char* argv[]) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2023-04-02 21:50:19 +02:00
|
|
|
int r;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2024-04-25 14:09:09 +02:00
|
|
|
log_setup();
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
if (invoked_as(argv, "run0"))
|
2023-12-19 19:10:52 +01:00
|
|
|
r = parse_argv_sudo_mode(argc, argv);
|
|
|
|
|
else
|
|
|
|
|
r = parse_argv(argc, argv);
|
2013-07-01 00:03:57 +02:00
|
|
|
if (r <= 0)
|
2018-11-22 19:34:15 +01:00
|
|
|
return r;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2021-10-27 11:59:19 +01:00
|
|
|
if (shall_make_executable_absolute()) {
|
2020-09-17 15:44:59 +02:00
|
|
|
/* Patch in an absolute path to fail early for user convenience, but only when we can do it
|
|
|
|
|
* (i.e. we will be running from the same file system). This also uses the user's $PATH,
|
|
|
|
|
* while we use a fixed search path in the manager. */
|
2015-10-22 18:24:59 +02:00
|
|
|
|
2020-09-17 15:44:59 +02:00
|
|
|
_cleanup_free_ char *command = NULL;
|
2020-09-17 13:44:12 +02:00
|
|
|
r = find_executable(arg_cmdline[0], &command);
|
2024-11-05 11:54:14 +01:00
|
|
|
if (ERRNO_IS_NEG_PRIVILEGE(r))
|
|
|
|
|
log_debug_errno(r, "Failed to find executable '%s' due to permission problems, leaving path as is: %m", arg_cmdline[0]);
|
|
|
|
|
else if (r < 0)
|
2018-11-22 19:34:15 +01:00
|
|
|
return log_error_errno(r, "Failed to find executable %s: %m", arg_cmdline[0]);
|
2024-11-05 11:54:14 +01:00
|
|
|
else
|
|
|
|
|
free_and_replace(arg_cmdline[0], command);
|
2013-09-08 07:51:39 -04:00
|
|
|
}
|
|
|
|
|
|
2013-07-01 00:40:56 +02:00
|
|
|
if (!arg_description) {
|
2024-10-24 12:07:24 +02:00
|
|
|
_cleanup_free_ char *t = NULL;
|
2013-07-01 00:40:56 +02:00
|
|
|
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
if (strv_isempty(arg_cmdline))
|
|
|
|
|
t = strdup(arg_unit);
|
2025-04-09 00:55:27 +02:00
|
|
|
else if (arg_via_shell) {
|
|
|
|
|
if (arg_cmdline[1])
|
|
|
|
|
t = quote_command_line(arg_cmdline + 1, SHELL_ESCAPE_EMPTY);
|
|
|
|
|
else
|
|
|
|
|
t = strjoin("LOGIN", arg_exec_user ? ": " : NULL, arg_exec_user);
|
|
|
|
|
} else if (startswith(arg_cmdline[0], "-")) {
|
2024-10-24 12:14:01 +02:00
|
|
|
/* Drop the login shell marker from the command line when generating the description,
|
|
|
|
|
* in order to minimize user confusion. */
|
|
|
|
|
_cleanup_strv_free_ char **l = strv_copy(arg_cmdline);
|
|
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = free_and_strdup_warn(l + 0, l[0] + 1);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
t = quote_command_line(l, SHELL_ESCAPE_EMPTY);
|
|
|
|
|
} else
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
t = quote_command_line(arg_cmdline, SHELL_ESCAPE_EMPTY);
|
|
|
|
|
if (!t)
|
|
|
|
|
return log_oom();
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2024-10-24 12:07:24 +02:00
|
|
|
arg_description = strjoin("[", program_invocation_short_name, "] ", t);
|
|
|
|
|
if (!arg_description)
|
|
|
|
|
return log_oom();
|
2013-07-01 00:40:56 +02:00
|
|
|
}
|
|
|
|
|
|
2024-10-24 15:08:22 +02:00
|
|
|
r = connect_bus(&bus);
|
2018-11-22 19:34:15 +01:00
|
|
|
if (r < 0)
|
2024-10-24 15:08:22 +02:00
|
|
|
return r;
|
2024-08-16 19:59:30 +09:00
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
if (arg_scope)
|
2023-04-02 21:50:19 +02:00
|
|
|
return start_transient_scope(bus);
|
|
|
|
|
if (arg_path_property)
|
|
|
|
|
return start_transient_trigger(bus, ".path");
|
|
|
|
|
if (arg_socket_property)
|
|
|
|
|
return start_transient_trigger(bus, ".socket");
|
|
|
|
|
if (arg_with_timer)
|
|
|
|
|
return start_transient_trigger(bus, ".timer");
|
|
|
|
|
return start_transient_service(bus);
|
2013-06-28 04:12:58 +02:00
|
|
|
}
|
2018-11-22 19:30:03 +01:00
|
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|