1/* $Id: cmd-run-shell.c,v 1.1.1.2 2011/08/17 18:40:04 jmmv 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 <string.h>
24
25#include "tmux.h"
26
27/*
28 * Runs a command without a window.
29 */
30
31int	cmd_run_shell_exec(struct cmd *, struct cmd_ctx *);
32
33void	cmd_run_shell_callback(struct job *);
34void	cmd_run_shell_free(void *);
35
36const struct cmd_entry cmd_run_shell_entry = {
37	"run-shell", "run",
38	"", 1, 1,
39	"command",
40	0,
41	NULL,
42	NULL,
43	cmd_run_shell_exec
44};
45
46struct cmd_run_shell_data {
47	char		*cmd;
48	struct cmd_ctx	 ctx;
49};
50
51int
52cmd_run_shell_exec(struct cmd *self, struct cmd_ctx *ctx)
53{
54	struct args			*args = self->args;
55	struct cmd_run_shell_data	*cdata;
56	const char			*shellcmd = args->argv[0];
57
58	cdata = xmalloc(sizeof *cdata);
59	cdata->cmd = xstrdup(args->argv[0]);
60	memcpy(&cdata->ctx, ctx, sizeof cdata->ctx);
61
62	if (ctx->cmdclient != NULL)
63		ctx->cmdclient->references++;
64	if (ctx->curclient != NULL)
65		ctx->curclient->references++;
66
67	job_run(shellcmd, cmd_run_shell_callback, cmd_run_shell_free, cdata);
68
69	return (1);	/* don't let client exit */
70}
71
72void
73cmd_run_shell_callback(struct job *job)
74{
75	struct cmd_run_shell_data	*cdata = job->data;
76	struct cmd_ctx			*ctx = &cdata->ctx;
77	char				*cmd, *msg, *line;
78	size_t				 size;
79	int				 retcode;
80	u_int				 lines;
81
82	if (ctx->cmdclient != NULL && ctx->cmdclient->flags & CLIENT_DEAD)
83		return;
84	if (ctx->curclient != NULL && ctx->curclient->flags & CLIENT_DEAD)
85		return;
86
87	lines = 0;
88	do {
89		if ((line = evbuffer_readline(job->event->input)) != NULL) {
90			ctx->print(ctx, "%s", line);
91			lines++;
92		}
93	} while (line != NULL);
94
95	size = EVBUFFER_LENGTH(job->event->input);
96	if (size != 0) {
97		line = xmalloc(size + 1);
98		memcpy(line, EVBUFFER_DATA(job->event->input), size);
99		line[size] = '\0';
100
101		ctx->print(ctx, "%s", line);
102		lines++;
103
104		xfree(line);
105	}
106
107	cmd = cdata->cmd;
108
109	msg = NULL;
110	if (WIFEXITED(job->status)) {
111		if ((retcode = WEXITSTATUS(job->status)) != 0)
112			xasprintf(&msg, "'%s' returned %d", cmd, retcode);
113	} else if (WIFSIGNALED(job->status)) {
114		retcode = WTERMSIG(job->status);
115		xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
116	}
117	if (msg != NULL) {
118		if (lines != 0)
119			ctx->print(ctx, "%s", msg);
120		else
121			ctx->info(ctx, "%s", msg);
122		xfree(msg);
123	}
124}
125
126void
127cmd_run_shell_free(void *data)
128{
129	struct cmd_run_shell_data	*cdata = data;
130	struct cmd_ctx			*ctx = &cdata->ctx;
131
132	if (ctx->cmdclient != NULL) {
133		ctx->cmdclient->references--;
134		ctx->cmdclient->flags |= CLIENT_EXIT;
135	}
136	if (ctx->curclient != NULL)
137		ctx->curclient->references--;
138
139	xfree(cdata->cmd);
140	xfree(cdata);
141}
142