Sync OpenBSD patchset 350:

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.
This commit is contained in:
Tiago Cunha
2009-09-23 15:18:56 +00:00
parent 4dd332c95e
commit 5be3fb86b9
6 changed files with 118 additions and 23 deletions

68
tmux.c
View File

@ -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");
}