diff options
author | Nicholas Marriott <nicm@openbsd.org> | 2009-09-23 12:03:30 +0000 |
---|---|---|
committer | Nicholas Marriott <nicm@openbsd.org> | 2009-09-23 12:03:30 +0000 |
commit | 9200a0be7a515cd04c1a05d120002c73932cbf98 (patch) | |
tree | 6e82962815963a9962c1029d7d97898fb0dae98b /tmux.c | |
parent | 18ea820cb0f1e7d9936c89abf15130e40efc956b (diff) | |
download | rtmux-9200a0be7a515cd04c1a05d120002c73932cbf98.tar.gz rtmux-9200a0be7a515cd04c1a05d120002c73932cbf98.tar.bz2 rtmux-9200a0be7a515cd04c1a05d120002c73932cbf98.zip |
Support -c like sh(1) to execute a command, useful when tmux is a login
shell. Suggested by halex@.
This includes another protocol version increase (the last for now) so again
restart the tmux server before upgrading.
Diffstat (limited to 'tmux.c')
-rw-r--r-- | tmux.c | 66 |
1 files changed, 56 insertions, 10 deletions
@@ -57,13 +57,14 @@ 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 *); __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); @@ -275,17 +276,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; @@ -295,6 +296,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; @@ -332,6 +338,9 @@ main(int argc, char **argv) argc -= optind; argv += optind; + if (shellcmd != NULL && argc != 0) + usage(); + log_open_tty(debug_level); siginit(); @@ -477,10 +486,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 { /* @@ -529,7 +544,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; } @@ -546,11 +561,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"); @@ -594,6 +610,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"); } @@ -601,3 +624,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"); +} |