diff options
-rw-r--r-- | client.c | 4 | ||||
-rw-r--r-- | server-msg.c | 27 | ||||
-rw-r--r-- | tmux.1 | 12 | ||||
-rw-r--r-- | tmux.c | 68 | ||||
-rw-r--r-- | tmux.h | 12 | ||||
-rw-r--r-- | tty.c | 18 |
6 files changed, 118 insertions, 23 deletions
@@ -1,4 +1,4 @@ -/* $Id: client.c,v 1.74 2009-09-23 15:00:08 tcunha Exp $ */ +/* $Id: client.c,v 1.75 2009-09-23 15:18:56 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -95,6 +95,8 @@ server_started: fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) fatal("fcntl failed"); + if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) + fatal("fcntl failed"); imsg_init(&cctx->ibuf, fd); if (cmdflags & CMD_SENDENVIRON) diff --git a/server-msg.c b/server-msg.c index 7cfdc2d9..8a18c4ab 100644 --- a/server-msg.c +++ b/server-msg.c @@ -1,4 +1,4 @@ -/* $Id: server-msg.c,v 1.87 2009-09-23 15:00:08 tcunha Exp $ */ +/* $Id: server-msg.c,v 1.88 2009-09-23 15:18:56 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -20,6 +20,7 @@ #include <sys/ioctl.h> #include <errno.h> +#include <paths.h> #include <stdlib.h> #include <string.h> #include <time.h> @@ -29,6 +30,7 @@ void server_msg_command(struct client *, struct msg_command_data *); void server_msg_identify(struct client *, struct msg_identify_data *, int); +void server_msg_shell(struct client *); void printflike2 server_msg_command_error(struct cmd_ctx *, const char *, ...); void printflike2 server_msg_command_print(struct cmd_ctx *, const char *, ...); @@ -113,6 +115,12 @@ server_msg_dispatch(struct client *c) if (strchr(environdata.var, '=') != NULL) environ_put(&c->environ, environdata.var); break; + case MSG_SHELL: + if (datalen != 0) + fatalx("bad MSG_SHELL size"); + + server_msg_shell(c); + break; default: fatalx("unexpected message"); } @@ -248,3 +256,20 @@ server_msg_identify(struct client *c, struct msg_identify_data *data, int fd) c->flags |= CLIENT_TERMINAL; } + +void +server_msg_shell(struct client *c) +{ + struct msg_shell_data data; + const char *shell; + + shell = options_get_string(&global_s_options, "default-shell"); + + if (*shell == '\0' || areshell(shell)) + shell = _PATH_BSHELL; + if (strlcpy(data.shell, shell, sizeof data.shell) >= sizeof data.shell) + strlcpy(data.shell, _PATH_BSHELL, sizeof data.shell); + + server_write_client(c, MSG_SHELL, &data, sizeof data); + c->flags |= CLIENT_BAD; /* it will die after exec */ +} @@ -1,4 +1,4 @@ -.\" $Id: tmux.1,v 1.172 2009-09-23 15:00:09 tcunha Exp $ +.\" $Id: tmux.1,v 1.173 2009-09-23 15:18:56 tcunha Exp $ .\" .\" Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> .\" @@ -24,6 +24,7 @@ .Nm tmux .Bk -words .Op Fl 28dlquv +.Op Fl c Ar shell-command .Op Fl f Ar file .Op Fl L Ar socket-name .Op Fl S Ar socket-path @@ -101,6 +102,15 @@ to assume the terminal supports 256 colours. Like .Fl 2 , but indicates that the terminal supports 88 colours. +.It Fl c Ar shell-command +Execute +.Ar shell-command +using the default shell. +If necessary, the +.Nm +server will be started to retrieve the +.Ic default-shell +option. .It Fl d Force .Nm @@ -1,4 +1,4 @@ -/* $Id: tmux.c,v 1.174 2009-09-23 15:00:09 tcunha Exp $ */ +/* $Id: tmux.c,v 1.175 2009-09-23 15:18:56 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -62,7 +62,8 @@ int login_shell; __dead void usage(void); char *makesockpath(const char *); int prepare_cmd(enum msgtype *, void **, size_t *, int, char **); -int dispatch_imsg(struct client_ctx *, int *); +int dispatch_imsg(struct client_ctx *, const char *, int *); +__dead void shell_exec(const char *, const char *); #ifndef HAVE_PROGNAME char *__progname = (char *) "tmux"; @@ -72,7 +73,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-28dlquv] [-f file] [-L socket-name]\n" + "usage: %s [-28dlquv] [-c shell-command] [-f file] [-L socket-name]\n" " [-S socket-path] [command [flags]]\n", __progname); exit(1); @@ -284,17 +285,17 @@ main(int argc, char **argv) struct passwd *pw; struct options *so, *wo; struct keylist *keylist; - char *s, *path, *label, *home, *cause, **var; - char cwd[MAXPATHLEN]; + char *s, *shellcmd, *path, *label, *home, *cause; + char cwd[MAXPATHLEN], **var; void *buf; size_t len; int retcode, opt, flags, cmdflags = 0; int nfds; flags = 0; - label = path = NULL; + shellcmd = label = path = NULL; login_shell = (**argv == '-'); - while ((opt = getopt(argc, argv, "28df:lL:qS:uUv")) != -1) { + while ((opt = getopt(argc, argv, "28c:df:lL:qS:uUv")) != -1) { switch (opt) { case '2': flags |= IDENTIFY_256COLOURS; @@ -304,6 +305,11 @@ main(int argc, char **argv) flags |= IDENTIFY_88COLOURS; flags &= ~IDENTIFY_256COLOURS; break; + case 'c': + if (shellcmd != NULL) + xfree(shellcmd); + shellcmd = xstrdup(optarg); + break; case 'd': flags |= IDENTIFY_HASDEFAULTS; break; @@ -341,6 +347,9 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (shellcmd != NULL && argc != 0) + usage(); + log_open_tty(debug_level); siginit(); @@ -486,10 +495,16 @@ main(int argc, char **argv) } xfree(label); - if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) + if (shellcmd != NULL) { + msg = MSG_SHELL; + buf = NULL; + len = 0; + } else if (prepare_cmd(&msg, &buf, &len, argc, argv) != 0) exit(1); - if (argc == 0) /* new-session is the default */ + if (shellcmd != NULL) + cmdflags |= CMD_STARTSERVER; + else if (argc == 0) /* new-session is the default */ cmdflags |= CMD_STARTSERVER|CMD_SENDENVIRON; else { /* @@ -538,7 +553,7 @@ main(int argc, char **argv) fatalx("socket error"); if (pfd.revents & POLLIN) { - if (dispatch_imsg(&cctx, &retcode) != 0) + if (dispatch_imsg(&cctx, shellcmd, &retcode) != 0) break; } @@ -555,11 +570,12 @@ main(int argc, char **argv) } int -dispatch_imsg(struct client_ctx *cctx, int *retcode) +dispatch_imsg(struct client_ctx *cctx, const char *shellcmd, int *retcode) { struct imsg imsg; ssize_t n, datalen; struct msg_print_data printdata; + struct msg_shell_data shelldata; if ((n = imsg_read(&cctx->ibuf)) == -1 || n == 0) fatalx("imsg_read failed"); @@ -603,6 +619,13 @@ dispatch_imsg(struct client_ctx *cctx, int *retcode) "server %u)", PROTOCOL_VERSION, imsg.hdr.peerid); *retcode = 1; return (-1); + case MSG_SHELL: + if (datalen != sizeof shelldata) + fatalx("bad MSG_SHELL size"); + memcpy(&shelldata, imsg.data, sizeof shelldata); + shelldata.shell[(sizeof shelldata.shell) - 1] = '\0'; + + shell_exec(shelldata.shell, shellcmd); default: fatalx("unexpected message"); } @@ -610,3 +633,26 @@ dispatch_imsg(struct client_ctx *cctx, int *retcode) imsg_free(&imsg); } } + +__dead void +shell_exec(const char *shell, const char *shellcmd) +{ + const char *shellname, *ptr; + char *argv0; + + sigreset(); + + ptr = strrchr(shell, '/'); + if (ptr != NULL && *(ptr + 1) != '\0') + shellname = ptr + 1; + else + shellname = shell; + if (login_shell) + xasprintf(&argv0, "-%s", shellname); + else + xasprintf(&argv0, "%s", shellname); + setenv("SHELL", shell, 1); + + execl(shell, argv0, "-c", shellcmd, (char *) NULL); + fatal("execl failed"); +} @@ -1,4 +1,4 @@ -/* $Id: tmux.h,v 1.453 2009-09-23 15:00:09 tcunha Exp $ */ +/* $Id: tmux.h,v 1.454 2009-09-23 15:18:56 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -21,7 +21,7 @@ #include "config.h" -#define PROTOCOL_VERSION 4 +#define PROTOCOL_VERSION 5 #include <sys/param.h> #include <sys/time.h> @@ -128,6 +128,7 @@ enum key_code { /* Function keys. */ KEYC_F1, + KEYC_F2, KEYC_F3, KEYC_F4, @@ -306,7 +307,8 @@ enum msgtype { MSG_WAKEUP, MSG_ENVIRON, MSG_UNLOCK, - MSG_LOCK + MSG_LOCK, + MSG_SHELL }; /* @@ -346,6 +348,10 @@ struct msg_environ_data { char var[ENVIRON_LENGTH]; }; +struct msg_shell_data { + char shell[MAXPATHLEN]; +}; + /* Mode key commands. */ enum mode_key_cmd { MODEKEY_NONE, @@ -1,4 +1,4 @@ -/* $Id: tty.c,v 1.137 2009-09-23 15:08:21 tcunha Exp $ */ +/* $Id: tty.c,v 1.138 2009-09-23 15:18:56 tcunha Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -44,7 +44,6 @@ void tty_cell(struct tty *, void tty_init(struct tty *tty, int fd, char *term) { - int mode; char *path; memset(tty, 0, sizeof *tty); @@ -55,10 +54,6 @@ tty_init(struct tty *tty, int fd, char *term) else tty->termname = xstrdup(term); - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); tty->fd = fd; @@ -129,6 +124,7 @@ void tty_start_tty(struct tty *tty) { struct termios tio; + int mode; #ifdef TIOCFLUSH int what; #endif @@ -136,6 +132,11 @@ tty_start_tty(struct tty *tty) if (tty->fd == -1) return; + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + fatal("fcntl failed"); + if (fcntl(tty->fd, F_SETFL, mode|O_NONBLOCK) == -1) + fatal("fcntl failed"); + #if 0 tty_detect_utf8(tty); #endif @@ -187,6 +188,7 @@ void tty_stop_tty(struct tty *tty) { struct winsize ws; + int mode; if (!(tty->flags & TTY_STARTED)) return; @@ -197,6 +199,10 @@ tty_stop_tty(struct tty *tty) * because the fd is invalid. Things like ssh -t can easily leave us * with a dead tty. */ + if ((mode = fcntl(tty->fd, F_GETFL)) == -1) + return; + if (fcntl(tty->fd, F_SETFL, mode & ~O_NONBLOCK) == -1) + return; if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) return; if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) |