machined: when opening a shell via machined, pass tty fds in
With this change we'll open the shell's tty right from machined and then pass it to the transient unit we create. This way we make sure the pty is opened exactly as long as the transient service is around, and no longer, and vice versa. This way pty forwarders do not have to deal with EIO problems due to vhangup, as the pty is open all the time from the point we set things up to the point where the service goes away.
This commit is contained in:
parent
a34ceba66f
commit
40e1f4ea74
|
@ -1152,3 +1152,51 @@ int openpt_in_namespace(pid_t pid, int flags) {
|
|||
|
||||
return receive_one_fd(pair[0], 0);
|
||||
}
|
||||
|
||||
int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
|
||||
_cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
|
||||
_cleanup_close_pair_ int pair[2] = { -1, -1 };
|
||||
siginfo_t si;
|
||||
pid_t child;
|
||||
int r;
|
||||
|
||||
r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
|
||||
return -errno;
|
||||
|
||||
child = fork();
|
||||
if (child < 0)
|
||||
return -errno;
|
||||
|
||||
if (child == 0) {
|
||||
int master;
|
||||
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
||||
r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
|
||||
if (r < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
|
||||
if (master < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
if (send_one_fd(pair[1], master, 0) < 0)
|
||||
_exit(EXIT_FAILURE);
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
pair[1] = safe_close(pair[1]);
|
||||
|
||||
r = wait_for_terminate(child, &si);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
|
||||
return -EIO;
|
||||
|
||||
return receive_one_fd(pair[0], 0);
|
||||
}
|
||||
|
|
|
@ -124,3 +124,4 @@ int ptsname_malloc(int fd, char **ret);
|
|||
int ptsname_namespace(int pty, char **ret);
|
||||
|
||||
int openpt_in_namespace(pid_t pid, int flags);
|
||||
int open_terminal_in_namespace(pid_t pid, const char *name, int mode);
|
||||
|
|
|
@ -639,7 +639,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
|
|||
_cleanup_free_ char *pty_name = NULL;
|
||||
_cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL;
|
||||
sd_bus *container_bus = NULL;
|
||||
_cleanup_close_ int master = -1;
|
||||
_cleanup_close_ int master = -1, slave = -1;
|
||||
_cleanup_strv_free_ char **env = NULL, **args = NULL;
|
||||
Machine *m = userdata;
|
||||
const char *p, *unit, *user, *path, *description, *utmp_id;
|
||||
|
@ -700,8 +700,11 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
|
|||
return r;
|
||||
|
||||
p = path_startswith(pty_name, "/dev/pts/");
|
||||
if (!p)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
|
||||
assert(p);
|
||||
|
||||
slave = machine_open_terminal(m, pty_name, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
||||
if (slave < 0)
|
||||
return slave;
|
||||
|
||||
utmp_id = path_startswith(pty_name, "/dev/");
|
||||
assert(utmp_id);
|
||||
|
@ -735,16 +738,14 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
|
|||
|
||||
description = strjoina("Shell for User ", isempty(user) ? "root" : user);
|
||||
r = sd_bus_message_append(tm,
|
||||
"(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
|
||||
"(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
|
||||
"Description", "s", description,
|
||||
"StandardInput", "s", "tty",
|
||||
"StandardOutput", "s", "tty",
|
||||
"StandardError", "s", "tty",
|
||||
"TTYPath", "s", pty_name,
|
||||
"StandardInputFileDescriptor", "h", slave,
|
||||
"StandardOutputFileDescriptor", "h", slave,
|
||||
"StandardErrorFileDescriptor", "h", slave,
|
||||
"SendSIGHUP", "b", true,
|
||||
"IgnoreSIGPIPE", "b", false,
|
||||
"KillMode", "s", "mixed",
|
||||
"TTYVHangup", "b", true,
|
||||
"TTYReset", "b", true,
|
||||
"UtmpIdentifier", "s", utmp_id,
|
||||
"UtmpMode", "s", "user",
|
||||
|
@ -845,6 +846,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
slave = safe_close(slave);
|
||||
|
||||
r = sd_bus_message_new_method_return(message, &reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
@ -572,6 +572,25 @@ int machine_openpt(Machine *m, int flags) {
|
|||
}
|
||||
}
|
||||
|
||||
int machine_open_terminal(Machine *m, const char *path, int mode) {
|
||||
assert(m);
|
||||
|
||||
switch (m->class) {
|
||||
|
||||
case MACHINE_HOST:
|
||||
return open_terminal(path, mode);
|
||||
|
||||
case MACHINE_CONTAINER:
|
||||
if (m->leader <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
return open_terminal_in_namespace(m->leader, path, mode);
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
MachineOperation *machine_operation_unref(MachineOperation *o) {
|
||||
if (!o)
|
||||
return NULL;
|
||||
|
|
|
@ -123,3 +123,4 @@ const char *kill_who_to_string(KillWho k) _const_;
|
|||
KillWho kill_who_from_string(const char *s) _pure_;
|
||||
|
||||
int machine_openpt(Machine *m, int flags);
|
||||
int machine_open_terminal(Machine *m, const char *path, int mode);
|
||||
|
|
|
@ -1390,7 +1390,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) {
|
|||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, machine);
|
||||
return process_forward(event, &forward, master, 0, machine);
|
||||
}
|
||||
|
||||
static int remove_image(int argc, char *argv[], void *userdata) {
|
||||
|
|
Loading…
Reference in New Issue