1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-06 00:58:29 +03: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.
This commit is contained in:
Lennart Poettering 2025-02-28 23:32:08 +01:00
parent 7eb1cd2f0c
commit b7ba8d55b8
4 changed files with 177 additions and 105 deletions

View File

@ -199,16 +199,23 @@
<varlistentry>
<term><option>--pty</option></term>
<term><option>--pty-late</option></term>
<term><option>--pipe</option></term>
<listitem><para>Request allocation of a pseudo TTY for the <command>run0</command> session (in case
of <option>--pty</option>), or request passing the caller's STDIO file descriptors directly through
(in case of <option>--pipe</option>). If neither switch is specified, or if both switches are
specified, the mode will be picked automatically: if standard input, standard output and standard
error output are all connected to a TTY then a pseudo TTY is allocated, otherwise the relevant file
descriptors are passed through directly.</para>
of <option>--pty</option> or <option>--pty-late</option>), or request passing the caller's STDIO file
descriptors directly through (in case of <option>--pipe</option>). <option>--pty-late</option> is
very similar to <option>--pty</option> but begins the TTY processing only once unit startup is
complete, leaving input to any passwords/polkit agents until that time. If neither switch is
specified, or if both <option>--pipe</option> and one of
<option>--pty</option>/<option>--pty-late</option> are specified, the mode will be picked
automatically: if standard input, standard output, and standard error output are all connected to a
TTY then a pseudo TTY is allocated (in <option>--pty-late</option> mode unless
<option>--no-ask-password</option> is specified in which case <option>--pty</option> is selected),
otherwise the relevant file descriptors are passed through directly.</para>
<xi:include href="version-info.xml" xpointer="v257"/>
<para id="v257"><option>--pty</option> and <option>--pipe</option> were added in v257.</para>
<para id="v258"><option>--pty-late</option> was added in v258.</para>
</listitem>
</varlistentry>

View File

@ -327,6 +327,20 @@
<xi:include href="version-info.xml" xpointer="v219"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--pty-late</option></term>
<term><option>-T</option></term>
<listitem><para>Much like <option>--pty</option>, but the PTY communication only begins once the unit
start is complete. This effectively means PTY input during <varname>ExecStartPre=</varname> of a
service is not available while using <option>--pty-late</option>, while it is available using
<option>--pty</option>, for most service types. However, if this option is used, access to the
invoking TTY is available for password queries (see <option>--no-ask-password</option> below) during
unit start-up.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term><option>--pipe</option></term>
<term><option>-P</option></term>

View File

@ -11,6 +11,7 @@
#include "sd-json.h"
#include "alloc-util.h"
#include "ask-password-agent.h"
#include "build.h"
#include "bus-error.h"
#include "bus-locator.h"
@ -72,10 +73,11 @@ static char **arg_environment = NULL;
static char **arg_property = NULL;
static enum {
ARG_STDIO_NONE, /* The default, as it is for normal services, stdin connected to /dev/null, and stdout+stderr to the journal */
ARG_STDIO_PTY, /* Interactive behaviour, requested by --pty: we allocate a pty and connect it to the TTY we are invoked from */
ARG_STDIO_PTY, /* Interactive behaviour, requested by --pty/--pty-late: we allocate a pty and connect it to the TTY we are invoked from */
ARG_STDIO_DIRECT, /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
ARG_STDIO_AUTO, /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
ARG_STDIO_AUTO, /* If --pipe and --pty/--pty-late are used together we use --pty/--pty-late when invoked on a TTY, and --pipe otherwise */
} arg_stdio = ARG_STDIO_NONE;
static int arg_pty_late = -1; /* tristate */
static char **arg_path_property = NULL;
static char **arg_socket_property = NULL;
static char **arg_timer_property = NULL;
@ -143,6 +145,8 @@ static int help(void) {
" -E --setenv=NAME[=VALUE] Set environment variable\n"
" -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
" STDERR\n"
" -T --pty-late Just like --pty, but leave TTY access to\n"
" agents until unit is started up\n"
" -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
" -q --quiet Suppress information messages during runtime\n"
" --json=pretty|short|off Print unit name and invocation id as JSON\n"
@ -205,6 +209,8 @@ static int help_sudo_mode(void) {
" --setenv=NAME[=VALUE] Set environment variable\n"
" --background=COLOR Set ANSI color for background\n"
" --pty Request allocation of a pseudo TTY for stdio\n"
" --pty-late Just like --pty, but leave TTY access to agents\n"
" until unit is started up\n"
" --pipe Request direct pipe for stdio\n"
" --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
" --lightweight=BOOLEAN Control whether to register a session with service manager\n"
@ -317,6 +323,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "property", required_argument, NULL, 'p' },
{ "tty", no_argument, NULL, 't' }, /* deprecated alias */
{ "pty", no_argument, NULL, 't' },
{ "pty-late", no_argument, NULL, 'T' },
{ "pipe", no_argument, NULL, 'P' },
{ "quiet", no_argument, NULL, 'q' },
{ "on-active", required_argument, NULL, ARG_ON_ACTIVE },
@ -352,7 +359,7 @@ static int parse_argv(int argc, char *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;
while ((c = getopt_long(argc, argv, "+hrC:H:M:E:p:tPqGdSu:", options, NULL)) >= 0)
while ((c = getopt_long(argc, argv, "+hrC:H:M:E:p:tTPqGdSu:", options, NULL)) >= 0)
switch (c) {
@ -465,15 +472,18 @@ static int parse_argv(int argc, char *argv[]) {
break;
case 'T': /* --pty-late */
case 't': /* --pty */
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
arg_stdio = ARG_STDIO_AUTO;
else
arg_stdio = ARG_STDIO_PTY;
arg_pty_late = c == 'T';
break;
case 'P': /* --pipe */
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty/--pty-late is already used, upgrade to auto mode */
arg_stdio = ARG_STDIO_AUTO;
else
arg_stdio = ARG_STDIO_DIRECT;
@ -700,13 +710,17 @@ static int parse_argv(int argc, char *argv[]) {
}
if (arg_stdio == ARG_STDIO_AUTO)
/* If we both --pty and --pipe are specified we'll automatically pick --pty 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. */
/* 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. */
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ?
ARG_STDIO_PTY :
ARG_STDIO_DIRECT;
if (arg_pty_late < 0)
arg_pty_late = false; /* For systemd-run this defaults to false, for compat reasons */
if (argc > optind) {
char **l;
@ -748,17 +762,19 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--remain-after-exit and --service-type= are not supported in --scope mode.");
if (arg_stdio != ARG_STDIO_NONE && (with_trigger || arg_scope))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--pty/--pipe is not compatible in timer or --scope mode.");
if (arg_stdio != ARG_STDIO_NONE) {
if (with_trigger || arg_scope)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--pty/--pty-late/--pipe is not compatible in timer or --scope mode.");
if (arg_stdio != ARG_STDIO_NONE && arg_transport == BUS_TRANSPORT_REMOTE)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--pty/--pipe is only supported when connecting to the local system or containers.");
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.");
if (arg_stdio != ARG_STDIO_NONE && arg_no_block)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--pty/--pipe is not compatible with --no-block.");
if (arg_no_block)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--pty/--pty-late/--pipe is not compatible with --no-block.");
}
if (arg_scope && with_trigger)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
@ -800,6 +816,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
ARG_SETENV,
ARG_BACKGROUND,
ARG_PTY,
ARG_PTY_LATE,
ARG_PIPE,
ARG_SHELL_PROMPT_PREFIX,
ARG_LIGHTWEIGHT,
@ -825,6 +842,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
{ "setenv", required_argument, NULL, ARG_SETENV },
{ "background", required_argument, NULL, ARG_BACKGROUND },
{ "pty", no_argument, NULL, ARG_PTY },
{ "pty-late", no_argument, NULL, ARG_PTY_LATE },
{ "pipe", no_argument, NULL, ARG_PIPE },
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
@ -922,14 +940,17 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
break;
case ARG_PTY:
case ARG_PTY_LATE:
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
arg_stdio = ARG_STDIO_AUTO;
else
arg_stdio = ARG_STDIO_PTY;
arg_pty_late = c == ARG_PTY_LATE;
break;
case ARG_PIPE:
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty/--pty-late is already used, upgrade to auto mode */
arg_stdio = ARG_STDIO_AUTO;
else
arg_stdio = ARG_STDIO_DIRECT;
@ -998,8 +1019,9 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
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;
log_debug("Using %s stdio mode.", arg_stdio == ARG_STDIO_PTY ? "pty" : "direct");
if (arg_pty_late < 0)
arg_pty_late = arg_ask_password; /* for run0 this defaults to on, except if --no-ask-pasword is used */
arg_expand_environment = false;
arg_send_sighup = true;
@ -1545,13 +1567,16 @@ static int connect_bus(sd_bus **ret) {
typedef struct RunContext {
sd_event *event;
PTYForward *forward;
char *service;
char *unit;
char *bus_path;
char *start_job;
int pty_fd;
/* Bus objects */
sd_bus *bus;
sd_bus_slot *match_properties_changed;
sd_bus_slot *match_disconnected;
sd_bus_slot *match_job_removed;
sd_event_source *retry_timer;
/* Current state of the unit */
@ -1589,8 +1614,11 @@ static void run_context_done(RunContext *c) {
free(c->active_state);
free(c->result);
free(c->unit);
free(c->bus_path);
free(c->service);
free(c->start_job);
safe_close(c->pty_fd);
}
static int on_retry_timer(sd_event_source *s, uint64_t usec, void *userdata) {
@ -1644,7 +1672,9 @@ static int run_context_reconnect(RunContext *c) {
static void run_context_check_done(RunContext *c) {
assert(c);
bool done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
bool done = STRPTR_IN_SET(c->active_state, "inactive", "failed") &&
!c->start_job && /* our start job */
!c->has_job; /* any other job */
if (done && c->forward) /* If the service is gone, it's time to drain the output */
done = pty_forward_drain(c->forward);
@ -1788,6 +1818,7 @@ static void run_context_detach_bus(RunContext *c) {
c->match_properties_changed = sd_bus_slot_unref(c->match_properties_changed);
c->match_disconnected = sd_bus_slot_unref(c->match_disconnected);
c->match_job_removed = sd_bus_slot_unref(c->match_job_removed);
}
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
@ -1987,22 +2018,39 @@ static int print_unit_invocation(const char *unit, sd_id128_t invocation_id) {
return sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
}
typedef struct JobDoneContext {
char *unit;
char *start_job;
sd_bus_slot *match;
} JobDoneContext;
static int run_context_setup_ptyfwd(RunContext *c) {
int r;
static void job_done_context_done(JobDoneContext *c) {
assert(c);
c->unit = mfree(c->unit);
c->start_job = mfree(c->start_job);
c->match = sd_bus_slot_unref(c->match);
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);
set_window_title(c->forward);
return 0;
}
static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
JobDoneContext *c = ASSERT_PTR(userdata);
RunContext *c = ASSERT_PTR(userdata);
const char *path;
int r;
@ -2023,7 +2071,14 @@ static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *er
"RUN_UNIT=%s",
c->unit);
job_done_context_done(c);
r = run_context_setup_ptyfwd(c);
if (r < 0)
return sd_event_exit(c->event, r);
c->start_job = mfree(c->start_job);
c->match_job_removed = sd_bus_slot_unref(c->match_job_removed);
run_context_check_done(c);
return 0;
}
@ -2031,22 +2086,36 @@ static int start_transient_service(sd_bus *bus) {
_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;
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
_cleanup_free_ char *service = NULL, *pty_path = NULL;
_cleanup_close_ int pty_fd = -EBADF, peer_fd = -EBADF;
_cleanup_free_ char *pty_path = NULL;
_cleanup_close_ int peer_fd = -EBADF;
int r;
assert(bus);
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
(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,
};
if (arg_stdio == ARG_STDIO_PTY) {
if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)) {
pty_fd = openpt_allocate(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK, &pty_path);
if (pty_fd < 0)
return log_error_errno(pty_fd, "Failed to acquire pseudo tty: %m");
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");
peer_fd = pty_open_peer(pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
peer_fd = pty_open_peer(c.pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (peer_fd < 0)
return log_error_errno(peer_fd, "Failed to open pty peer: %m");
@ -2078,19 +2147,19 @@ static int start_transient_service(sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to get machine PTY: %s", bus_error_message(&error, r));
r = sd_bus_message_read(pty_reply, "hs", &pty_fd, &s);
r = sd_bus_message_read(pty_reply, "hs", &c.pty_fd, &s);
if (r < 0)
return bus_log_parse_error(r);
pty_fd = fcntl(pty_fd, F_DUPFD_CLOEXEC, 3);
if (pty_fd < 0)
c.pty_fd = fcntl(c.pty_fd, F_DUPFD_CLOEXEC, 3);
if (c.pty_fd < 0)
return log_error_errno(errno, "Failed to duplicate master fd: %m");
pty_path = strdup(s);
if (!pty_path)
return log_oom();
peer_fd = pty_open_peer(pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
peer_fd = pty_open_peer(c.pty_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (peer_fd < 0)
return log_error_errno(peer_fd, "Failed to open PTY peer: %m");
} else
@ -2098,13 +2167,16 @@ static int start_transient_service(sd_bus *bus) {
}
if (arg_unit) {
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
".service", &service);
r = unit_name_mangle_with_suffix(
arg_unit,
"as unit",
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
".service",
&c.unit);
if (r < 0)
return log_error_errno(r, "Failed to mangle unit name: %m");
} else {
r = make_unit_name(UNIT_SERVICE, &service);
r = make_unit_name(UNIT_SERVICE, &c.unit);
if (r < 0)
return r;
}
@ -2113,33 +2185,30 @@ static int start_transient_service(sd_bus *bus) {
* 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. */
_cleanup_(job_done_context_done) JobDoneContext job_done_context = {};
if (!arg_no_block) {
if (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");
} else {
job_done_context.unit = strdup(service);
if (!job_done_context.unit)
return log_oom();
/* When we are a bus client we match by sender. Direct connections OTOH have no
* initialized sender field, and hence we ignore the sender then */
r = sd_bus_match_signal_async(
bus,
&job_done_context.match,
&c.match_job_removed,
sd_bus_is_bus_client(bus) ? "org.freedesktop.systemd1" : NULL,
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"JobRemoved",
match_job_removed, NULL, &job_done_context);
match_job_removed,
/* add_callback= */ NULL,
&c);
if (r < 0)
return log_error_errno(r, "Failed to install JobRemove match: %m");
}
}
r = make_transient_service_unit(bus, &m, service, pty_path, peer_fd);
r = make_transient_service_unit(bus, &m, c.unit, pty_path, peer_fd);
if (r < 0)
return r;
peer_fd = safe_close(peer_fd);
@ -2154,57 +2223,42 @@ static int start_transient_service(sd_bus *bus) {
return bus_log_parse_error(r);
if (w) {
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);
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);
if (r < 0)
return r;
} else if (job_done_context.match) {
job_done_context.start_job = strdup(object);
if (!job_done_context.start_job)
} else if (c.match_job_removed) {
c.start_job = strdup(object);
if (!c.start_job)
return log_oom();
}
if (!arg_quiet) {
sd_id128_t invocation_id;
r = acquire_invocation_id(bus, service, &invocation_id);
r = acquire_invocation_id(bus, c.unit, &invocation_id);
if (r < 0)
return r;
r = print_unit_invocation(service, invocation_id);
r = print_unit_invocation(c.unit, invocation_id);
if (r < 0)
return r;
}
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
_cleanup_(run_context_done) RunContext c = {
.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,
};
c.bus_path = unit_dbus_path_from_name(c.unit);
if (!c.bus_path)
return log_oom();
r = sd_event_default(&c.event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
c.service = strdup(service);
if (!c.service)
return log_oom();
c.bus_path = unit_dbus_path_from_name(service);
if (!c.bus_path)
return log_oom();
_cleanup_(osc_context_closep) sd_id128_t osc_context_id = SD_ID128_NULL;
if (pty_fd >= 0) {
if (c.pty_fd >= 0) {
if (arg_exec_user && !terminal_is_dumb()) {
r = osc_context_open_chpriv(arg_exec_user, /* ret_seq= */ NULL, &osc_context_id);
if (r < 0)
@ -2213,22 +2267,12 @@ static int start_transient_service(sd_bus *bus) {
(void) sd_event_set_signal_exit(c.event, true);
if (!arg_quiet)
log_info("Press ^] three times within 1s to disconnect TTY.");
r = pty_forward_new(c.event, 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);
set_window_title(c.forward);
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;
}
}
r = run_context_attach_bus(&c, bus);
@ -2342,6 +2386,7 @@ static int start_transient_scope(sd_bus *bus) {
}
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
(void) ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
for (;;) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@ -2495,6 +2540,10 @@ static int start_transient_scope(sd_bus *bus) {
}
}
/* Stop agents before we pass control away, to avoid TTY conflicts */
polkit_agent_close();
ask_password_agent_close();
execvpe(arg_cmdline[0], arg_cmdline, env);
return log_error_errno(errno, "Failed to execute: %m");
@ -2650,6 +2699,7 @@ static int start_transient_trigger(sd_bus *bus, const char *suffix) {
return r;
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
(void) ask_password_agent_open_if_enabled(arg_transport, arg_ask_password);
r = bus_call_with_hint(bus, m, suffix + 1, &reply);
if (r < 0)

View File

@ -577,3 +577,4 @@ file-hierarchy.xml /refsect1[title="Home Directory"]/variablelist/varlistentry[t
file-hierarchy.xml /refsect1[title="Home Directory"]/variablelist/varlistentry[term="~/.local/state/"]
systemd-measure.xml /refsect1[title="Options"]/variablelist/varlistentry[term="--linux=PATH"]
systemd-nspawn.xml /refsect1[title="Hotkeys"]/variablelist/varlistentry[term="Ctrl-] Ctrl-] Ctrl-]"]
run0.xml /refsect1[title="Options"]/variablelist/varlistentry[term="--pty"]