xref: /minix3/external/bsd/tmux/dist/cmd-run-shell.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /* Id */
2eda6f593SDavid van Moolenbroek 
3eda6f593SDavid van Moolenbroek /*
4eda6f593SDavid van Moolenbroek  * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
5eda6f593SDavid van Moolenbroek  * Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
6eda6f593SDavid van Moolenbroek  *
7eda6f593SDavid van Moolenbroek  * Permission to use, copy, modify, and distribute this software for any
8eda6f593SDavid van Moolenbroek  * purpose with or without fee is hereby granted, provided that the above
9eda6f593SDavid van Moolenbroek  * copyright notice and this permission notice appear in all copies.
10eda6f593SDavid van Moolenbroek  *
11eda6f593SDavid van Moolenbroek  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12eda6f593SDavid van Moolenbroek  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13eda6f593SDavid van Moolenbroek  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14eda6f593SDavid van Moolenbroek  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15eda6f593SDavid van Moolenbroek  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16eda6f593SDavid van Moolenbroek  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17eda6f593SDavid van Moolenbroek  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18eda6f593SDavid van Moolenbroek  */
19eda6f593SDavid van Moolenbroek 
20eda6f593SDavid van Moolenbroek #include <sys/types.h>
21eda6f593SDavid van Moolenbroek #include <sys/wait.h>
22eda6f593SDavid van Moolenbroek 
23*0a6a1f1dSLionel Sambuc #include <stdlib.h>
24eda6f593SDavid van Moolenbroek #include <string.h>
25eda6f593SDavid van Moolenbroek 
26eda6f593SDavid van Moolenbroek #include "tmux.h"
27eda6f593SDavid van Moolenbroek 
28eda6f593SDavid van Moolenbroek /*
29eda6f593SDavid van Moolenbroek  * Runs a command without a window.
30eda6f593SDavid van Moolenbroek  */
31eda6f593SDavid van Moolenbroek 
32*0a6a1f1dSLionel Sambuc enum cmd_retval	 cmd_run_shell_exec(struct cmd *, struct cmd_q *);
33eda6f593SDavid van Moolenbroek 
34eda6f593SDavid van Moolenbroek void	cmd_run_shell_callback(struct job *);
35eda6f593SDavid van Moolenbroek void	cmd_run_shell_free(void *);
36*0a6a1f1dSLionel Sambuc void	cmd_run_shell_print(struct job *, const char *);
37eda6f593SDavid van Moolenbroek 
38eda6f593SDavid van Moolenbroek const struct cmd_entry cmd_run_shell_entry = {
39eda6f593SDavid van Moolenbroek 	"run-shell", "run",
40*0a6a1f1dSLionel Sambuc 	"bt:", 1, 1,
41*0a6a1f1dSLionel Sambuc 	"[-b] " CMD_TARGET_PANE_USAGE " shell-command",
42eda6f593SDavid van Moolenbroek 	0,
43eda6f593SDavid van Moolenbroek 	NULL,
44eda6f593SDavid van Moolenbroek 	cmd_run_shell_exec
45eda6f593SDavid van Moolenbroek };
46eda6f593SDavid van Moolenbroek 
47eda6f593SDavid van Moolenbroek struct cmd_run_shell_data {
48eda6f593SDavid van Moolenbroek 	char		*cmd;
49*0a6a1f1dSLionel Sambuc 	struct cmd_q	*cmdq;
50*0a6a1f1dSLionel Sambuc 	int		 bflag;
51*0a6a1f1dSLionel Sambuc 	int		 wp_id;
52eda6f593SDavid van Moolenbroek };
53eda6f593SDavid van Moolenbroek 
54*0a6a1f1dSLionel Sambuc void
cmd_run_shell_print(struct job * job,const char * msg)55*0a6a1f1dSLionel Sambuc cmd_run_shell_print(struct job *job, const char *msg)
56*0a6a1f1dSLionel Sambuc {
57*0a6a1f1dSLionel Sambuc 	struct cmd_run_shell_data	*cdata = job->data;
58*0a6a1f1dSLionel Sambuc 	struct window_pane		*wp = NULL;
59*0a6a1f1dSLionel Sambuc 
60*0a6a1f1dSLionel Sambuc 	if (cdata->wp_id != -1)
61*0a6a1f1dSLionel Sambuc 		wp = window_pane_find_by_id(cdata->wp_id);
62*0a6a1f1dSLionel Sambuc 	if (wp == NULL) {
63*0a6a1f1dSLionel Sambuc 		cmdq_print(cdata->cmdq, "%s", msg);
64*0a6a1f1dSLionel Sambuc 		return;
65*0a6a1f1dSLionel Sambuc 	}
66*0a6a1f1dSLionel Sambuc 
67*0a6a1f1dSLionel Sambuc 	if (window_pane_set_mode(wp, &window_copy_mode) == 0)
68*0a6a1f1dSLionel Sambuc 		window_copy_init_for_output(wp);
69*0a6a1f1dSLionel Sambuc 	if (wp->mode == &window_copy_mode)
70*0a6a1f1dSLionel Sambuc 		window_copy_add(wp, "%s", msg);
71*0a6a1f1dSLionel Sambuc }
72*0a6a1f1dSLionel Sambuc 
73*0a6a1f1dSLionel Sambuc enum cmd_retval
cmd_run_shell_exec(struct cmd * self,struct cmd_q * cmdq)74*0a6a1f1dSLionel Sambuc cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
75eda6f593SDavid van Moolenbroek {
76eda6f593SDavid van Moolenbroek 	struct args			*args = self->args;
77eda6f593SDavid van Moolenbroek 	struct cmd_run_shell_data	*cdata;
78*0a6a1f1dSLionel Sambuc 	char				*shellcmd;
79*0a6a1f1dSLionel Sambuc 	struct client			*c;
80*0a6a1f1dSLionel Sambuc 	struct session			*s = NULL;
81*0a6a1f1dSLionel Sambuc 	struct winlink			*wl = NULL;
82*0a6a1f1dSLionel Sambuc 	struct window_pane		*wp = NULL;
83*0a6a1f1dSLionel Sambuc 	struct format_tree		*ft;
84*0a6a1f1dSLionel Sambuc 
85*0a6a1f1dSLionel Sambuc 	if (args_has(args, 't'))
86*0a6a1f1dSLionel Sambuc 		wl = cmd_find_pane(cmdq, args_get(args, 't'), &s, &wp);
87*0a6a1f1dSLionel Sambuc 	else {
88*0a6a1f1dSLionel Sambuc 		c = cmd_find_client(cmdq, NULL, 1);
89*0a6a1f1dSLionel Sambuc 		if (c != NULL && c->session != NULL) {
90*0a6a1f1dSLionel Sambuc 			s = c->session;
91*0a6a1f1dSLionel Sambuc 			wl = s->curw;
92*0a6a1f1dSLionel Sambuc 			wp = wl->window->active;
93*0a6a1f1dSLionel Sambuc 		}
94*0a6a1f1dSLionel Sambuc 	}
95*0a6a1f1dSLionel Sambuc 
96*0a6a1f1dSLionel Sambuc 	ft = format_create();
97*0a6a1f1dSLionel Sambuc 	if (s != NULL)
98*0a6a1f1dSLionel Sambuc 		format_session(ft, s);
99*0a6a1f1dSLionel Sambuc 	if (s != NULL && wl != NULL)
100*0a6a1f1dSLionel Sambuc 		format_winlink(ft, s, wl);
101*0a6a1f1dSLionel Sambuc 	if (wp != NULL)
102*0a6a1f1dSLionel Sambuc 		format_window_pane(ft, wp);
103*0a6a1f1dSLionel Sambuc 	shellcmd = format_expand(ft, args->argv[0]);
104*0a6a1f1dSLionel Sambuc 	format_free(ft);
105eda6f593SDavid van Moolenbroek 
106eda6f593SDavid van Moolenbroek 	cdata = xmalloc(sizeof *cdata);
107*0a6a1f1dSLionel Sambuc 	cdata->cmd = shellcmd;
108*0a6a1f1dSLionel Sambuc 	cdata->bflag = args_has(args, 'b');
109*0a6a1f1dSLionel Sambuc 	cdata->wp_id = wp != NULL ? (int) wp->id : -1;
110eda6f593SDavid van Moolenbroek 
111*0a6a1f1dSLionel Sambuc 	cdata->cmdq = cmdq;
112*0a6a1f1dSLionel Sambuc 	cmdq->references++;
113eda6f593SDavid van Moolenbroek 
114*0a6a1f1dSLionel Sambuc 	job_run(shellcmd, s, cmd_run_shell_callback, cmd_run_shell_free, cdata);
115eda6f593SDavid van Moolenbroek 
116*0a6a1f1dSLionel Sambuc 	if (cdata->bflag)
117*0a6a1f1dSLionel Sambuc 		return (CMD_RETURN_NORMAL);
118*0a6a1f1dSLionel Sambuc 	return (CMD_RETURN_WAIT);
119eda6f593SDavid van Moolenbroek }
120eda6f593SDavid van Moolenbroek 
121eda6f593SDavid van Moolenbroek void
cmd_run_shell_callback(struct job * job)122eda6f593SDavid van Moolenbroek cmd_run_shell_callback(struct job *job)
123eda6f593SDavid van Moolenbroek {
124eda6f593SDavid van Moolenbroek 	struct cmd_run_shell_data	*cdata = job->data;
125*0a6a1f1dSLionel Sambuc 	struct cmd_q			*cmdq = cdata->cmdq;
126eda6f593SDavid van Moolenbroek 	char				*cmd, *msg, *line;
127eda6f593SDavid van Moolenbroek 	size_t				 size;
128eda6f593SDavid van Moolenbroek 	int				 retcode;
129eda6f593SDavid van Moolenbroek 	u_int				 lines;
130eda6f593SDavid van Moolenbroek 
131*0a6a1f1dSLionel Sambuc 	if (cmdq->dead)
132eda6f593SDavid van Moolenbroek 		return;
133*0a6a1f1dSLionel Sambuc 	cmd = cdata->cmd;
134eda6f593SDavid van Moolenbroek 
135eda6f593SDavid van Moolenbroek 	lines = 0;
136eda6f593SDavid van Moolenbroek 	do {
137eda6f593SDavid van Moolenbroek 		if ((line = evbuffer_readline(job->event->input)) != NULL) {
138*0a6a1f1dSLionel Sambuc 			cmd_run_shell_print(job, line);
139*0a6a1f1dSLionel Sambuc 			free(line);
140eda6f593SDavid van Moolenbroek 			lines++;
141eda6f593SDavid van Moolenbroek 		}
142eda6f593SDavid van Moolenbroek 	} while (line != NULL);
143eda6f593SDavid van Moolenbroek 
144eda6f593SDavid van Moolenbroek 	size = EVBUFFER_LENGTH(job->event->input);
145eda6f593SDavid van Moolenbroek 	if (size != 0) {
146eda6f593SDavid van Moolenbroek 		line = xmalloc(size + 1);
147eda6f593SDavid van Moolenbroek 		memcpy(line, EVBUFFER_DATA(job->event->input), size);
148eda6f593SDavid van Moolenbroek 		line[size] = '\0';
149eda6f593SDavid van Moolenbroek 
150*0a6a1f1dSLionel Sambuc 		cmd_run_shell_print(job, line);
151eda6f593SDavid van Moolenbroek 		lines++;
152eda6f593SDavid van Moolenbroek 
153*0a6a1f1dSLionel Sambuc 		free(line);
154eda6f593SDavid van Moolenbroek 	}
155eda6f593SDavid van Moolenbroek 
156eda6f593SDavid van Moolenbroek 	msg = NULL;
157eda6f593SDavid van Moolenbroek 	if (WIFEXITED(job->status)) {
158eda6f593SDavid van Moolenbroek 		if ((retcode = WEXITSTATUS(job->status)) != 0)
159eda6f593SDavid van Moolenbroek 			xasprintf(&msg, "'%s' returned %d", cmd, retcode);
160eda6f593SDavid van Moolenbroek 	} else if (WIFSIGNALED(job->status)) {
161eda6f593SDavid van Moolenbroek 		retcode = WTERMSIG(job->status);
162eda6f593SDavid van Moolenbroek 		xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
163eda6f593SDavid van Moolenbroek 	}
164eda6f593SDavid van Moolenbroek 	if (msg != NULL) {
165*0a6a1f1dSLionel Sambuc 		if (lines == 0)
166*0a6a1f1dSLionel Sambuc 			cmdq_info(cmdq, "%s", msg);
167eda6f593SDavid van Moolenbroek 		else
168*0a6a1f1dSLionel Sambuc 			cmd_run_shell_print(job, msg);
169*0a6a1f1dSLionel Sambuc 		free(msg);
170eda6f593SDavid van Moolenbroek 	}
171eda6f593SDavid van Moolenbroek }
172eda6f593SDavid van Moolenbroek 
173eda6f593SDavid van Moolenbroek void
cmd_run_shell_free(void * data)174eda6f593SDavid van Moolenbroek cmd_run_shell_free(void *data)
175eda6f593SDavid van Moolenbroek {
176eda6f593SDavid van Moolenbroek 	struct cmd_run_shell_data	*cdata = data;
177*0a6a1f1dSLionel Sambuc 	struct cmd_q			*cmdq = cdata->cmdq;
178eda6f593SDavid van Moolenbroek 
179*0a6a1f1dSLionel Sambuc 	if (!cmdq_free(cmdq) && !cdata->bflag)
180*0a6a1f1dSLionel Sambuc 		cmdq_continue(cmdq);
181eda6f593SDavid van Moolenbroek 
182*0a6a1f1dSLionel Sambuc 	free(cdata->cmd);
183*0a6a1f1dSLionel Sambuc 	free(cdata);
184eda6f593SDavid van Moolenbroek }
185