diff --git a/Makefile b/Makefile index a60f1f19..82cccb59 100644 --- a/Makefile +++ b/Makefile @@ -97,6 +97,7 @@ SRCS= alerts.c \ paste.c \ proc.c \ procname.c \ + pty.c \ resize.c \ screen-redraw.c \ screen-write.c \ diff --git a/client.c b/client.c index 1307b0f7..90b1371c 100644 --- a/client.c +++ b/client.c @@ -303,6 +303,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags, fatal("pledge failed"); /* Free stuff that is not used in the client. */ + if (ptm_fd != -1) + close(ptm_fd); options_free(global_options); options_free(global_s_options); options_free(global_w_options); diff --git a/pty.c b/pty.c new file mode 100644 index 00000000..05a02ef0 --- /dev/null +++ b/pty.c @@ -0,0 +1,67 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2017 Nicholas Marriott + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +int pty_open(int *); +pid_t pty_fork(int, int *, char *, size_t, struct winsize *); + +int +pty_open(int *fd) +{ + *fd = open(PATH_PTMDEV, O_RDWR|O_CLOEXEC); + if (*fd < 0) + return (-1); + return (0); +} + +pid_t +pty_fork(int ptmfd, int *fd, char *name, size_t namelen, struct winsize *ws) +{ + struct ptmget ptm; + pid_t pid; + + if ((ioctl(ptmfd, PTMGET, &ptm) == -1)) + return (-1); + + strlcpy(name, ptm.sn, namelen); + ioctl(ptm.sfd, TIOCSWINSZ, ws); + + switch (pid = fork()) { + case -1: + close(ptm.cfd); + close(ptm.sfd); + return (-1); + case 0: + close(ptm.cfd); + login_tty(ptm.sfd); + return (0); + } + *fd = ptm.cfd; + close(ptm.sfd); + return (pid); +} diff --git a/tmux.c b/tmux.c index e80e2b06..d5e962df 100644 --- a/tmux.c +++ b/tmux.c @@ -43,6 +43,7 @@ struct hooks *global_hooks; struct timeval start_time; const char *socket_path; +int ptm_fd = -1; static __dead void usage(void); static char *make_label(const char *); @@ -258,6 +259,8 @@ main(int argc, char **argv) if (shellcmd != NULL && argc != 0) usage(); + if (pty_open(&ptm_fd) != 0) + errx(1, "open(\"/dev/ptm\""); if (pledge("stdio rpath wpath cpath flock fattr unix getpw sendfd " "recvfd proc exec tty ps", NULL) != 0) err(1, "pledge"); diff --git a/tmux.h b/tmux.h index eb1660dd..2a26f10f 100644 --- a/tmux.h +++ b/tmux.h @@ -1501,6 +1501,7 @@ extern struct options *global_w_options; extern struct environ *global_environ; extern struct timeval start_time; extern const char *socket_path; +extern int ptm_fd; int areshell(const char *); void setblocking(int, int); const char *find_home(void); @@ -2329,4 +2330,8 @@ void style_apply_update(struct grid_cell *, struct options *, int style_equal(const struct grid_cell *, const struct grid_cell *); +/* pty.c */ +int pty_open(int *); +pid_t pty_fork(int, int *, char *, size_t, struct winsize *); + #endif /* TMUX_H */ diff --git a/window.c b/window.c index 3bf05bd6..3eb58bda 100644 --- a/window.c +++ b/window.c @@ -886,7 +886,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, ws.ws_col = screen_size_x(&wp->base); ws.ws_row = screen_size_y(&wp->base); - switch (wp->pid = forkpty(&wp->fd, wp->tty, NULL, &ws)) { + switch (wp->pid = pty_fork(ptm_fd, &wp->fd, wp->tty, sizeof wp->tty, &ws)) { case -1: wp->fd = -1; xasprintf(cause, "%s: %s", cmd, strerror(errno));