xref: /openbsd-src/usr.bin/tmux/cmd-if-shell.c (revision ac9b4aacc1da35008afea06a5d23c2f2dea9b93e)
1 /* $OpenBSD: cmd-if-shell.c,v 1.17 2012/08/11 07:32:16 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
5  * Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "tmux.h"
27 
28 /*
29  * Executes a tmux command if a shell command returns true or false.
30  */
31 
32 enum cmd_retval	 cmd_if_shell_exec(struct cmd *, struct cmd_ctx *);
33 
34 void	cmd_if_shell_callback(struct job *);
35 void	cmd_if_shell_free(void *);
36 
37 const struct cmd_entry cmd_if_shell_entry = {
38 	"if-shell", "if",
39 	"", 2, 3,
40 	"shell-command command [command]",
41 	0,
42 	NULL,
43 	NULL,
44 	cmd_if_shell_exec
45 };
46 
47 struct cmd_if_shell_data {
48 	char		*cmd_if;
49 	char		*cmd_else;
50 	struct cmd_ctx	 ctx;
51 };
52 
53 enum cmd_retval
54 cmd_if_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
55 {
56 	struct args			*args = self->args;
57 	struct cmd_if_shell_data	*cdata;
58 	const char			*shellcmd = args->argv[0];
59 
60 	cdata = xmalloc(sizeof *cdata);
61 	cdata->cmd_if = xstrdup(args->argv[1]);
62 	if (args->argc == 3)
63 		cdata->cmd_else = xstrdup(args->argv[2]);
64 	else
65 		cdata->cmd_else = NULL;
66 	memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
67 
68 	if (ctx->cmdclient != NULL)
69 		ctx->cmdclient->references++;
70 	if (ctx->curclient != NULL)
71 		ctx->curclient->references++;
72 
73 	job_run(shellcmd, cmd_if_shell_callback, cmd_if_shell_free, cdata);
74 
75 	return (CMD_RETURN_YIELD);	/* don't let client exit */
76 }
77 
78 void
79 cmd_if_shell_callback(struct job *job)
80 {
81 	struct cmd_if_shell_data	*cdata = job->data;
82 	struct cmd_ctx			*ctx = &cdata->ctx;
83 	struct cmd_list			*cmdlist;
84 	char				*cause, *cmd;
85 
86 	if (!WIFEXITED(job->status) || WEXITSTATUS(job->status) != 0) {
87 		cmd = cdata->cmd_else;
88 		if (cmd == NULL)
89 			return;
90 	} else
91 		cmd = cdata->cmd_if;
92 	if (cmd_string_parse(cmd, &cmdlist, &cause) != 0) {
93 		if (cause != NULL) {
94 			ctx->error(ctx, "%s", cause);
95 			free(cause);
96 		}
97 		return;
98 	}
99 
100 	cmd_list_exec(cmdlist, ctx);
101 	cmd_list_free(cmdlist);
102 }
103 
104 void
105 cmd_if_shell_free(void *data)
106 {
107 	struct cmd_if_shell_data	*cdata = data;
108 	struct cmd_ctx			*ctx = &cdata->ctx;
109 
110 	if (ctx->cmdclient != NULL) {
111 		ctx->cmdclient->references--;
112 		ctx->cmdclient->flags |= CLIENT_EXIT;
113 	}
114 	if (ctx->curclient != NULL)
115 		ctx->curclient->references--;
116 
117 	free(cdata->cmd_else);
118 	free(cdata->cmd_if);
119 	free(cdata);
120 }
121