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