nspawn: add hotkey for rebooting/powering off container (#36583)
This commit is contained in:
@@ -1847,6 +1847,35 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Hotkeys</title>
|
||||
|
||||
<para>When invoked in interactive mode (i.e. the default <option>--console=interactive</option>), a few
|
||||
special keyboard shortcuts are understood that control the container runtime. These shortcuts need to be
|
||||
typed within 1s to have effect, otherwise they will be forwarded to the container as regular
|
||||
keypresses.</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>Ctrl-] Ctrl-] Ctrl-]</term>
|
||||
<listitem><para>Immediately terminate the container, killing all processes.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Ctrl-] Ctrl-] r</term>
|
||||
<listitem><para>Issue a reboot request to the container.</para>
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>Ctrl-] Ctrl-] p</term>
|
||||
<listitem><para>Issue a shutdown request to the container.</para>
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<xi:include href="common-variables.xml" />
|
||||
|
||||
<refsect1>
|
||||
|
||||
+36
-1
@@ -4692,6 +4692,37 @@ static void set_window_title(PTYForward *f) {
|
||||
(void) pty_forward_set_title_prefix(f, dot);
|
||||
}
|
||||
|
||||
static int ptyfwd_hotkey(PTYForward *f, char c, void *userdata) {
|
||||
pid_t pid = PTR_TO_PID(userdata);
|
||||
const char *word;
|
||||
int sig = 0;
|
||||
|
||||
assert(f);
|
||||
|
||||
switch (c) {
|
||||
case 'p':
|
||||
sig = SIGRTMIN+4;
|
||||
word = "power off";
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
sig = SIGRTMIN+5;
|
||||
word = "reboot";
|
||||
break;
|
||||
|
||||
default:
|
||||
log_info("Unknown hotkey sequence ^]^]%c, ignoring.", c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (kill(pid, sig) < 0)
|
||||
log_error_errno(errno, "Failed to send %s (%s request) to PID 1 of container: %m", signal_to_string(sig), word);
|
||||
else
|
||||
log_info("Sent %s (%s request) to PID 1 of container.", signal_to_string(sig), word);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int merge_settings(Settings *settings, const char *path) {
|
||||
int rl;
|
||||
|
||||
@@ -5687,6 +5718,8 @@ static int run_container(
|
||||
(void) pty_forward_set_background_color(forward, arg_background);
|
||||
|
||||
set_window_title(forward);
|
||||
|
||||
pty_forward_set_hotkey_handler(forward, ptyfwd_hotkey, PID_TO_PTR(*pid));
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -6364,7 +6397,9 @@ static int run(int argc, char *argv[]) {
|
||||
special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), arg_machine, u ?: t, ansi_normal());
|
||||
|
||||
if (arg_console_mode == CONSOLE_INTERACTIVE)
|
||||
log_info("%s %sPress %sCtrl-]%s three times within 1s to kill container.%s",
|
||||
log_info("%s %sPress %sCtrl-]%s three times within 1s to kill container; two times followed by %sr%s\n"
|
||||
"%s %sto reboot container; two times followed by %sp%s to poweroff container.%s",
|
||||
special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_highlight(), ansi_normal(),
|
||||
special_glyph(SPECIAL_GLYPH_LIGHT_SHADE), ansi_grey(), ansi_highlight(), ansi_grey(), ansi_normal());
|
||||
}
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ static int run(int argc, char *argv[]) {
|
||||
return log_error_errno(r, "Failed to set title: %m");
|
||||
}
|
||||
|
||||
pty_forward_set_handler(forward, pty_forward_handler, event);
|
||||
pty_forward_set_hangup_handler(forward, pty_forward_handler, event);
|
||||
|
||||
r = pidref_safe_fork_full(
|
||||
"(sd-ptyfwd)",
|
||||
|
||||
+1
-1
@@ -2220,7 +2220,7 @@ static int start_transient_service(sd_bus *bus) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
||||
|
||||
pty_forward_set_handler(c.forward, pty_forward_handler, &c);
|
||||
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);
|
||||
|
||||
+59
-20
@@ -101,8 +101,10 @@ struct PTYForward {
|
||||
usec_t escape_timestamp;
|
||||
unsigned escape_counter;
|
||||
|
||||
PTYForwardHandler handler;
|
||||
void *userdata;
|
||||
PTYForwardHangupHandler hangup_handler;
|
||||
void *hangup_userdata;
|
||||
PTYForwardHotkeyHandler hotkey_handler;
|
||||
void *hotkey_userdata;
|
||||
|
||||
char *background_color;
|
||||
AnsiColorState ansi_color_state;
|
||||
@@ -192,23 +194,32 @@ static int pty_forward_done(PTYForward *f, int rcode) {
|
||||
f->done = true;
|
||||
pty_forward_disconnect(f);
|
||||
|
||||
if (f->handler)
|
||||
return f->handler(f, rcode, f->userdata);
|
||||
else
|
||||
return sd_event_exit(e, rcode < 0 ? EXIT_FAILURE : rcode);
|
||||
if (f->hangup_handler)
|
||||
return f->hangup_handler(f, rcode, f->hangup_userdata);
|
||||
|
||||
return sd_event_exit(e, rcode < 0 ? EXIT_FAILURE : rcode);
|
||||
}
|
||||
|
||||
static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
|
||||
const char *p;
|
||||
typedef enum RequestOperation {
|
||||
REQUEST_NOP,
|
||||
REQUEST_EXIT,
|
||||
REQUEST_HOTKEY_BASE,
|
||||
REQUEST_HOTKEY_A = REQUEST_HOTKEY_BASE + 'a',
|
||||
REQUEST_HOTKEY_Z = REQUEST_HOTKEY_BASE + 'z',
|
||||
_REQUEST_OPERATION_MAX,
|
||||
_REQUEST_OPERATION_INVALID = -EINVAL,
|
||||
} RequestOperation;
|
||||
|
||||
static RequestOperation look_for_escape(PTYForward *f, const char *buffer, size_t n) {
|
||||
assert(f);
|
||||
assert(buffer);
|
||||
assert(n > 0);
|
||||
|
||||
for (p = buffer; p < buffer + n; p++) {
|
||||
for (const char *p = buffer; p < buffer + n; p++) {
|
||||
|
||||
/* Check for ^] */
|
||||
if (*p == 0x1D) {
|
||||
switch (*p) {
|
||||
|
||||
case 0x1D: { /* Check for ^] */
|
||||
usec_t nw = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (f->escape_counter == 0 || nw > f->escape_timestamp + ESCAPE_USEC) {
|
||||
@@ -218,15 +229,29 @@ static bool look_for_escape(PTYForward *f, const char *buffer, size_t n) {
|
||||
(f->escape_counter)++;
|
||||
|
||||
if (f->escape_counter >= 3)
|
||||
return true;
|
||||
return REQUEST_EXIT;
|
||||
}
|
||||
} else {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'a'...'z':
|
||||
if (f->escape_counter == 2 &&
|
||||
now(CLOCK_MONOTONIC) <= f->escape_timestamp + ESCAPE_USEC) {
|
||||
f->escape_timestamp = 0;
|
||||
f->escape_counter = 0;
|
||||
return REQUEST_HOTKEY_BASE + *p;
|
||||
}
|
||||
|
||||
_fallthrough_;
|
||||
|
||||
default:
|
||||
f->escape_timestamp = 0;
|
||||
f->escape_counter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return REQUEST_NOP;
|
||||
}
|
||||
|
||||
static bool ignore_vhangup(PTYForward *f) {
|
||||
@@ -654,10 +679,17 @@ static int do_shovel(PTYForward *f) {
|
||||
} else {
|
||||
/* Check if ^] has been pressed three times within one second. If we get this we quite
|
||||
* immediately. */
|
||||
if (look_for_escape(f, f->in_buffer + f->in_buffer_full, k))
|
||||
return -ECANCELED;
|
||||
|
||||
RequestOperation q = look_for_escape(f, f->in_buffer + f->in_buffer_full, k);
|
||||
f->in_buffer_full += (size_t) k;
|
||||
if (q < 0)
|
||||
return q;
|
||||
if (q == REQUEST_EXIT)
|
||||
return -ECANCELED;
|
||||
if (q >= REQUEST_HOTKEY_A && q <= REQUEST_HOTKEY_Z && f->hotkey_handler) {
|
||||
r = f->hotkey_handler(f, q - REQUEST_HOTKEY_BASE, f->hotkey_userdata);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
did_something = true;
|
||||
@@ -1084,11 +1116,18 @@ bool pty_forward_get_ignore_vhangup(PTYForward *f) {
|
||||
return FLAGS_SET(f->flags, PTY_FORWARD_IGNORE_VHANGUP);
|
||||
}
|
||||
|
||||
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler cb, void *userdata) {
|
||||
void pty_forward_set_hangup_handler(PTYForward *f, PTYForwardHangupHandler cb, void *userdata) {
|
||||
assert(f);
|
||||
|
||||
f->handler = cb;
|
||||
f->userdata = userdata;
|
||||
f->hangup_handler = cb;
|
||||
f->hangup_userdata = userdata;
|
||||
}
|
||||
|
||||
void pty_forward_set_hotkey_handler(PTYForward *f, PTYForwardHotkeyHandler cb, void *userdata) {
|
||||
assert(f);
|
||||
|
||||
f->hotkey_handler = cb;
|
||||
f->hotkey_userdata = userdata;
|
||||
}
|
||||
|
||||
bool pty_forward_drain(PTYForward *f) {
|
||||
|
||||
+4
-2
@@ -23,7 +23,8 @@ typedef enum PTYForwardFlags {
|
||||
PTY_FORWARD_DUMB_TERMINAL = 1 << 3,
|
||||
} PTYForwardFlags;
|
||||
|
||||
typedef int (*PTYForwardHandler)(PTYForward *f, int rcode, void *userdata);
|
||||
typedef int (*PTYForwardHangupHandler)(PTYForward *f, int rcode, void *userdata);
|
||||
typedef int (*PTYForwardHotkeyHandler)(PTYForward *f, char key, void *userdata);
|
||||
|
||||
#define N_PTY_FORWARD_SIGNALS 7
|
||||
extern const int pty_forward_signals[N_PTY_FORWARD_SIGNALS];
|
||||
@@ -34,7 +35,8 @@ PTYForward* pty_forward_free(PTYForward *f);
|
||||
int pty_forward_set_ignore_vhangup(PTYForward *f, bool ignore_vhangup);
|
||||
bool pty_forward_get_ignore_vhangup(PTYForward *f);
|
||||
|
||||
void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *userdata);
|
||||
void pty_forward_set_hangup_handler(PTYForward *f, PTYForwardHangupHandler handler, void *userdata);
|
||||
void pty_forward_set_hotkey_handler(PTYForward *f, PTYForwardHotkeyHandler handler, void *userdata);
|
||||
|
||||
bool pty_forward_drain(PTYForward *f);
|
||||
|
||||
|
||||
@@ -576,3 +576,4 @@ file-hierarchy.xml /refsect1[title="Home Directory"]/variablelist/varlistentry[t
|
||||
file-hierarchy.xml /refsect1[title="Home Directory"]/variablelist/varlistentry[term="~/.local/share/"]
|
||||
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-]"]
|
||||
|
||||
Reference in New Issue
Block a user