run: add a new "-t" mode for invoking a binary on an allocated TTY

This commit is contained in:
Lennart Poettering
2014-12-22 19:45:32 +01:00
parent 91f4347ef7
commit 9b15b7846d
7 changed files with 419 additions and 168 deletions

View File

@@ -225,10 +225,16 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
</listitem>
</varlistentry>
<xi:include href="user-system-options.xml" xpointer="user" />
<xi:include href="user-system-options.xml" xpointer="system" />
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />
<varlistentry>
<term><option>--pty</option></term>
<term><option>-t</option></term>
<listitem><para>When invoking a command as service connects
its standard input and output to the invoking tty via a
pseudo TTY device. This allows invoking binaries as services
that expect interactive user input, such as an interactive
command shells.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--on-active=</option></term>
@@ -278,6 +284,11 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>.
<command>set-property</command> command.</para> </listitem>
</varlistentry>
<xi:include href="user-system-options.xml" xpointer="user" />
<xi:include href="user-system-options.xml" xpointer="system" />
<xi:include href="user-system-options.xml" xpointer="host" />
<xi:include href="user-system-options.xml" xpointer="machine" />
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
@@ -333,6 +344,13 @@ Dec 08 20:44:38 container systemd[1]: Started /bin/touch /tmp/foo.
-- Logs begin at Fri 2014-12-05 19:09:21 KST, end at Mon 2014-12-08 20:44:54 KST. --
Dec 08 20:44:48 container systemd[1]: Starting /bin/touch /tmp/foo...
Dec 08 20:44:48 container systemd[1]: Started /bin/touch /tmp/foo.</programlisting>
<para>The following command invokes <filename>/bin/bash</filename>
as a service passing its standard input, output and error to
the calling TTY.</para>
<programlisting># systemd-run -t /bin/bash</programlisting>
</refsect1>
<refsect1>

View File

@@ -31,11 +31,12 @@
#include "strv.h"
#include "fileio.h"
#include "execute.h"
#include "dbus-execute.h"
#include "capability.h"
#include "env-util.h"
#include "af-list.h"
#include "namespace.h"
#include "path-util.h"
#include "dbus-execute.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
@@ -845,6 +846,92 @@ int bus_exec_context_set_transient_property(
return 1;
} else if (streq(name, "TTYPath")) {
const char *tty;
r = sd_bus_message_read(message, "s", &tty);
if (r < 0)
return r;
if (!path_is_absolute(tty))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY device not absolute path");
if (mode != UNIT_CHECK) {
char *t;
t = strdup(tty);
if (!t)
return -ENOMEM;
free(c->tty_path);
c->tty_path = t;
unit_write_drop_in_private_format(u, mode, name, "TTYPath=%s\n", tty);
}
return 1;
} else if (streq(name, "StandardInput")) {
const char *s;
ExecInput p;
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
p = exec_input_from_string(s);
if (p < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard input name");
if (mode != UNIT_CHECK) {
c->std_input = p;
unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s\n", exec_input_to_string(p));
}
return 1;
} else if (streq(name, "StandardOutput")) {
const char *s;
ExecOutput p;
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
p = exec_output_from_string(s);
if (p < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard output name");
if (mode != UNIT_CHECK) {
c->std_output = p;
unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s\n", exec_output_to_string(p));
}
return 1;
} else if (streq(name, "StandardError")) {
const char *s;
ExecOutput p;
r = sd_bus_message_read(message, "s", &s);
if (r < 0)
return r;
p = exec_output_from_string(s);
if (p < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard error name");
if (mode != UNIT_CHECK) {
c->std_error = p;
unit_write_drop_in_private_format(u, mode, name, "StandardError=%s\n", exec_output_to_string(p));
}
return 1;
} else if (streq(name, "Environment")) {
_cleanup_strv_free_ char **l = NULL;

View File

@@ -1178,7 +1178,7 @@ static int login_machine(int argc, char *argv[], void *userdata) {
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
r = pty_forward_new(event, master, &forward);
r = pty_forward_new(event, master, true, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");

View File

@@ -3519,7 +3519,7 @@ int main(int argc, char *argv[]) {
/* simply exit on sigchld */
sd_event_add_signal(event, NULL, SIGCHLD, NULL, NULL);
r = pty_forward_new(event, master, &forward);
r = pty_forward_new(event, master, true, &forward);
if (r < 0) {
log_error_errno(r, "Failed to create PTY forwarder: %m");
goto finish;

File diff suppressed because it is too large Load Diff

View File

@@ -53,6 +53,11 @@ struct PTYForward {
bool master_writable:1;
bool master_hangup:1;
bool repeat:1;
bool last_char_set:1;
char last_char;
char in_buffer[LINE_MAX], out_buffer[LINE_MAX];
size_t in_buffer_full, out_buffer_full;
@@ -169,11 +174,12 @@ static int shovel(PTYForward *f) {
* might be cause by vhangup() or
* temporary closing of everything on
* the other side, we treat it like
* EAGAIN here and try again. */
* EAGAIN here and try again, unless
* repeat is off. */
if (errno == EAGAIN || errno == EIO)
if (errno == EAGAIN || (errno == EIO && f->repeat))
f->master_readable = false;
else if (errno == EPIPE || errno == ECONNRESET) {
else if (errno == EPIPE || errno == ECONNRESET || errno == EIO) {
f->master_readable = f->master_writable = false;
f->master_hangup = true;
@@ -203,6 +209,12 @@ static int shovel(PTYForward *f) {
}
} else {
if (k > 0) {
f->last_char = f->out_buffer[k-1];
f->last_char_set = true;
}
assert(f->out_buffer_full >= (size_t) k);
memmove(f->out_buffer, f->out_buffer + k, f->out_buffer_full - k);
f->out_buffer_full -= k;
@@ -285,7 +297,7 @@ static int on_sigwinch_event(sd_event_source *e, const struct signalfd_siginfo *
return 0;
}
int pty_forward_new(sd_event *event, int master, PTYForward **ret) {
int pty_forward_new(sd_event *event, int master, bool repeat, PTYForward **ret) {
_cleanup_(pty_forward_freep) PTYForward *f = NULL;
struct winsize ws;
int r;
@@ -294,6 +306,8 @@ int pty_forward_new(sd_event *event, int master, PTYForward **ret) {
if (!f)
return -ENOMEM;
f->repeat = repeat;
if (event)
f->event = sd_event_ref(event);
else {
@@ -388,3 +402,14 @@ PTYForward *pty_forward_free(PTYForward *f) {
return NULL;
}
int pty_forward_last_char(PTYForward *f, char *ch) {
assert(f);
assert(ch);
if (!f->last_char_set)
return -ENXIO;
*ch = f->last_char;
return 0;
}

View File

@@ -28,7 +28,9 @@
typedef struct PTYForward PTYForward;
int pty_forward_new(sd_event *event, int master, PTYForward **f);
int pty_forward_new(sd_event *event, int master, bool repeat, PTYForward **f);
PTYForward *pty_forward_free(PTYForward *f);
int pty_forward_last_char(PTYForward *f, char *ch);
DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);