1 /* $OpenBSD$ */
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 * Runs a command without a window.
30 */
31
32 enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmd_q *);
33
34 void cmd_run_shell_callback(struct job *);
35 void cmd_run_shell_free(void *);
36 void cmd_run_shell_print(struct job *, const char *);
37
38 const struct cmd_entry cmd_run_shell_entry = {
39 .name = "run-shell",
40 .alias = "run",
41
42 .args = { "bt:", 1, 1 },
43 .usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
44
45 .tflag = CMD_PANE_CANFAIL,
46
47 .flags = 0,
48 .exec = cmd_run_shell_exec
49 };
50
51 struct cmd_run_shell_data {
52 char *cmd;
53 struct cmd_q *cmdq;
54 int bflag;
55 int wp_id;
56 };
57
58 void
cmd_run_shell_print(struct job * job,const char * msg)59 cmd_run_shell_print(struct job *job, const char *msg)
60 {
61 struct cmd_run_shell_data *cdata = job->data;
62 struct window_pane *wp = NULL;
63
64 if (cdata->wp_id != -1)
65 wp = window_pane_find_by_id(cdata->wp_id);
66 if (wp == NULL) {
67 cmdq_print(cdata->cmdq, "%s", msg);
68 return;
69 }
70
71 if (window_pane_set_mode(wp, &window_copy_mode) == 0)
72 window_copy_init_for_output(wp);
73 if (wp->mode == &window_copy_mode)
74 window_copy_add(wp, "%s", msg);
75 }
76
77 enum cmd_retval
cmd_run_shell_exec(struct cmd * self,struct cmd_q * cmdq)78 cmd_run_shell_exec(struct cmd *self, struct cmd_q *cmdq)
79 {
80 struct args *args = self->args;
81 struct cmd_run_shell_data *cdata;
82 char *shellcmd;
83 struct session *s = cmdq->state.tflag.s;
84 struct winlink *wl = cmdq->state.tflag.wl;
85 struct window_pane *wp = cmdq->state.tflag.wp;
86 struct format_tree *ft;
87 const char *cwd;
88
89 if (cmdq->client != NULL && cmdq->client->session == NULL)
90 cwd = cmdq->client->cwd;
91 else if (s != NULL)
92 cwd = s->cwd;
93 else
94 cwd = NULL;
95 ft = format_create(cmdq, 0);
96 format_defaults(ft, cmdq->state.c, s, wl, wp);
97 shellcmd = format_expand(ft, args->argv[0]);
98 format_free(ft);
99
100 cdata = xmalloc(sizeof *cdata);
101 cdata->cmd = shellcmd;
102 cdata->bflag = args_has(args, 'b');
103 cdata->wp_id = wp != NULL ? (int) wp->id : -1;
104
105 cdata->cmdq = cmdq;
106 cmdq->references++;
107
108 job_run(shellcmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
109 cdata);
110
111 if (cdata->bflag)
112 return (CMD_RETURN_NORMAL);
113 return (CMD_RETURN_WAIT);
114 }
115
116 void
cmd_run_shell_callback(struct job * job)117 cmd_run_shell_callback(struct job *job)
118 {
119 struct cmd_run_shell_data *cdata = job->data;
120 struct cmd_q *cmdq = cdata->cmdq;
121 char *cmd, *msg, *line;
122 size_t size;
123 int retcode;
124 u_int lines;
125
126 if (cmdq->flags & CMD_Q_DEAD)
127 return;
128 cmd = cdata->cmd;
129
130 lines = 0;
131 do {
132 if ((line = evbuffer_readline(job->event->input)) != NULL) {
133 cmd_run_shell_print(job, line);
134 free(line);
135 lines++;
136 }
137 } while (line != NULL);
138
139 size = EVBUFFER_LENGTH(job->event->input);
140 if (size != 0) {
141 line = xmalloc(size + 1);
142 memcpy(line, EVBUFFER_DATA(job->event->input), size);
143 line[size] = '\0';
144
145 cmd_run_shell_print(job, line);
146 lines++;
147
148 free(line);
149 }
150
151 msg = NULL;
152 if (WIFEXITED(job->status)) {
153 if ((retcode = WEXITSTATUS(job->status)) != 0)
154 xasprintf(&msg, "'%s' returned %d", cmd, retcode);
155 } else if (WIFSIGNALED(job->status)) {
156 retcode = WTERMSIG(job->status);
157 xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
158 }
159 if (msg != NULL)
160 cmd_run_shell_print(job, msg);
161 free(msg);
162 }
163
164 void
cmd_run_shell_free(void * data)165 cmd_run_shell_free(void *data)
166 {
167 struct cmd_run_shell_data *cdata = data;
168 struct cmd_q *cmdq = cdata->cmdq;
169
170 if (!cmdq_free(cmdq) && !cdata->bflag)
171 cmdq_continue(cmdq);
172
173 free(cdata->cmd);
174 free(cdata);
175 }
176