From b9c873cdaa3256f95a007d501fcab8375930bd94 Mon Sep 17 00:00:00 2001
From: Nicholas Marriott <nicm@openbsd.org>
Date: Sun, 11 Jul 2010 17:06:45 +0000
Subject: [PATCH] Return the command client return code with MSG_EXIT now that
 MSG_ERROR and MSG_PRINT are unused.

New clients should be compatible with old tmux servers but vice versa may print
an error.
---
 cmd-if-shell.c  |  5 ++++-
 cmd-run-shell.c |  5 ++++-
 server-client.c | 20 +++++++++++++-------
 tmux.c          | 14 ++++++++------
 tmux.h          |  5 +++++
 5 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/cmd-if-shell.c b/cmd-if-shell.c
index 1779486a..367bb691 100644
--- a/cmd-if-shell.c
+++ b/cmd-if-shell.c
@@ -104,10 +104,13 @@ cmd_if_shell_free(void *data)
 {
 	struct cmd_if_shell_data	*cdata = data;
 	struct cmd_ctx			*ctx = &cdata->ctx;
+	struct msg_exit_data		 exitdata;
 
 	if (ctx->cmdclient != NULL) {
 		ctx->cmdclient->references--;
-		server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
+		exitdata.retcode = ctx->cmdclient->retcode;
+		server_write_client(
+		    ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata);
 	}
 	if (ctx->curclient != NULL)
 		ctx->curclient->references--;
diff --git a/cmd-run-shell.c b/cmd-run-shell.c
index 3b6844eb..f9d1e237 100644
--- a/cmd-run-shell.c
+++ b/cmd-run-shell.c
@@ -131,10 +131,13 @@ cmd_run_shell_free(void *data)
 {
 	struct cmd_run_shell_data	*cdata = data;
 	struct cmd_ctx			*ctx = &cdata->ctx;
+	struct msg_exit_data		 exitdata;
 
 	if (ctx->cmdclient != NULL) {
 		ctx->cmdclient->references--;
-		server_write_client(ctx->cmdclient, MSG_EXIT, NULL, 0);
+		exitdata.retcode = ctx->cmdclient->retcode;
+		server_write_client(
+		    ctx->cmdclient, MSG_EXIT, &exitdata, sizeof exitdata);
 	}
 	if (ctx->curclient != NULL)
 		ctx->curclient->references--;
diff --git a/server-client.c b/server-client.c
index c7929fc1..6dc0fd3a 100644
--- a/server-client.c
+++ b/server-client.c
@@ -664,6 +664,8 @@ server_client_msg_error(struct cmd_ctx *ctx, const char *fmt, ...)
 
 	fputc('\n', ctx->cmdclient->stderr_file);
 	fflush(ctx->cmdclient->stderr_file);
+
+	ctx->cmdclient->retcode = 1;
 }
 
 /* Callback to send print message to client. */
@@ -701,10 +703,11 @@ server_client_msg_info(struct cmd_ctx *ctx, const char *fmt, ...)
 void
 server_client_msg_command(struct client *c, struct msg_command_data *data)
 {
-	struct cmd_ctx	 ctx;
-	struct cmd_list	*cmdlist = NULL;
-	int		 argc;
-	char	       **argv, *cause;
+	struct cmd_ctx	 	ctx;
+	struct cmd_list	       *cmdlist = NULL;
+	struct msg_exit_data	exitdata;
+	int			argc;
+	char		      **argv, *cause;
 
 	ctx.error = server_client_msg_error;
 	ctx.print = server_client_msg_print;
@@ -735,15 +738,18 @@ server_client_msg_command(struct client *c, struct msg_command_data *data)
 	}
 	cmd_free_argv(argc, argv);
 
-	if (cmd_list_exec(cmdlist, &ctx) != 1)
-		server_write_client(c, MSG_EXIT, NULL, 0);
+	if (cmd_list_exec(cmdlist, &ctx) != 1) {
+		exitdata.retcode = c->retcode;
+		server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
+	}
 	cmd_list_free(cmdlist);
 	return;
 
 error:
 	if (cmdlist != NULL)
 		cmd_list_free(cmdlist);
-	server_write_client(c, MSG_EXIT, NULL, 0);
+	exitdata.retcode = c->retcode;
+	server_write_client(c, MSG_EXIT, &exitdata, sizeof exitdata);
 }
 
 /* Handle identify message. */
diff --git a/tmux.c b/tmux.c
index 1c9d1cb5..e42e48d3 100644
--- a/tmux.c
+++ b/tmux.c
@@ -61,7 +61,6 @@ char 		*makesockpath(const char *);
 __dead void	 shell_exec(const char *, const char *);
 
 struct imsgbuf	*main_ibuf;
-int	         main_exitval;
 
 void		 main_signal(int, short, unused void *);
 void		 main_callback(int, short, void *);
@@ -548,7 +547,6 @@ main(int argc, char **argv)
 		events |= EV_WRITE;
 	event_once(main_ibuf->fd, events, main_callback, shellcmd, NULL);
 
-	main_exitval = 0;
 	event_dispatch();
 
 	clear_signals();
@@ -597,6 +595,7 @@ main_dispatch(const char *shellcmd)
 	struct imsg		imsg;
 	ssize_t			n, datalen;
 	struct msg_shell_data	shelldata;
+	struct msg_exit_data	exitdata;
 
 	if ((n = imsg_read(main_ibuf)) == -1 || n == 0)
 		fatalx("imsg_read failed");
@@ -611,10 +610,13 @@ main_dispatch(const char *shellcmd)
 		switch (imsg.hdr.type) {
 		case MSG_EXIT:
 		case MSG_SHUTDOWN:
-			if (datalen != 0)
-				fatalx("bad MSG_EXIT size");
-
-			exit(main_exitval);
+			if (datalen != sizeof exitdata) {
+				if (datalen != 0)
+					fatalx("bad MSG_EXIT size");
+				exit(0);
+			}
+			memcpy(&exitdata, imsg.data, sizeof exitdata);
+			exit(exitdata.retcode);
 		case MSG_READY:
 			if (datalen != 0)
 				fatalx("bad MSG_READY size");
diff --git a/tmux.h b/tmux.h
index a6d10a0b..c8e2c13d 100644
--- a/tmux.h
+++ b/tmux.h
@@ -413,6 +413,10 @@ struct msg_shell_data {
 	char		shell[MAXPATHLEN];
 };
 
+struct msg_exit_data {
+	int		retcode;
+};
+
 /* Mode key commands. */
 enum mode_key_cmd {
 	MODEKEY_NONE,
@@ -1081,6 +1085,7 @@ struct message_entry {
 struct client {
 	struct imsgbuf	 ibuf;
 	struct event	 event;
+	int		 retcode;
 
 	struct timeval	 creation_time;
 	struct timeval	 activity_time;