tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

cmd-run-shell.c
Go to the documentation of this file.
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 <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "tmux.h"
28 
29 /*
30  * Runs a command without a window.
31  */
32 
33 static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
34 
35 static void cmd_run_shell_timer(int, short, void *);
36 static void cmd_run_shell_callback(struct job *);
37 static void cmd_run_shell_free(void *);
38 static void cmd_run_shell_print(struct job *, const char *);
39 
40 const struct cmd_entry cmd_run_shell_entry = {
41  .name = "run-shell",
42  .alias = "run",
43 
44  .args = { "bd:Ct:", 0, 1 },
45  .usage = "[-bC] [-d delay] " CMD_TARGET_PANE_USAGE " [shell-command]",
46 
47  .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
48 
49  .flags = 0,
50  .exec = cmd_run_shell_exec
51 };
52 
54  struct client *client;
55  char *cmd;
56  int shell;
57  char *cwd;
58  struct cmdq_item *item;
59  struct session *s;
60  int wp_id;
61  struct event timer;
62  int flags;
63  struct cmd_parse_input pi;
64 };
65 
66 static void
67 cmd_run_shell_print(struct job *job, const char *msg)
68 {
69  struct cmd_run_shell_data *cdata = job_get_data(job);
70  struct window_pane *wp = NULL;
71  struct cmd_find_state fs;
72  struct window_mode_entry *wme;
73 
74  if (cdata->wp_id != -1)
76  if (wp == NULL) {
77  if (cdata->item != NULL) {
78  cmdq_print(cdata->item, "%s", msg);
79  return;
80  }
81  if (cmd_find_from_nothing(&fs, 0) != 0)
82  return;
83  wp = fs.wp;
84  if (wp == NULL)
85  return;
86  }
87 
88  wme = TAILQ_FIRST(&wp->modes);
89  if (wme == NULL || wme->mode != &window_view_mode)
90  window_pane_set_mode(wp, NULL, &window_view_mode, NULL, NULL);
91  window_copy_add(wp, "%s", msg);
92 }
93 
94 static enum cmd_retval
95 cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
96 {
97  struct args *args = cmd_get_args(self);
98  struct cmd_find_state *target = cmdq_get_target(item);
99  struct cmd_run_shell_data *cdata;
100  struct client *tc = cmdq_get_target_client(item);
101  struct session *s = target->s;
102  struct window_pane *wp = target->wp;
103  const char *delay;
104  double d;
105  struct timeval tv;
106  char *end;
107  int wait = !args_has(args, 'b');
108 
109  if ((delay = args_get(args, 'd')) != NULL) {
110  d = strtod(delay, &end);
111  if (*end != '\0') {
112  cmdq_error(item, "invalid delay time: %s", delay);
113  return (CMD_RETURN_ERROR);
114  }
115  } else if (args->argc == 0)
116  return (CMD_RETURN_NORMAL);
117 
118  cdata = xcalloc(1, sizeof *cdata);
119  if (args->argc != 0)
120  cdata->cmd = format_single_from_target(item, args->argv[0]);
121 
122  cdata->shell = !args_has(args, 'C');
123  if (!cdata->shell) {
124  memset(&cdata->pi, 0, sizeof cdata->pi);
125  cmd_get_source(self, &cdata->pi.file, &cdata->pi.line);
126  if (wait)
127  cdata->pi.item = item;
128  cdata->pi.c = tc;
129  cmd_find_copy_state(&cdata->pi.fs, target);
130  }
131 
132  if (args_has(args, 't') && wp != NULL)
133  cdata->wp_id = wp->id;
134  else
135  cdata->wp_id = -1;
136 
137  if (wait) {
138  cdata->client = cmdq_get_client(item);
139  cdata->item = item;
140  } else {
141  cdata->client = tc;
142  cdata->flags |= JOB_NOWAIT;
143  }
144  if (cdata->client != NULL)
145  cdata->client->references++;
146 
147  cdata->cwd = xstrdup(server_client_get_cwd(cmdq_get_client(item), s));
148 
149  cdata->s = s;
150  if (s != NULL)
151  session_add_ref(s, __func__);
152 
153  evtimer_set(&cdata->timer, cmd_run_shell_timer, cdata);
154  if (delay != NULL) {
155  timerclear(&tv);
156  tv.tv_sec = (time_t)d;
157  tv.tv_usec = (d - (double)tv.tv_sec) * 1000000U;
158  evtimer_add(&cdata->timer, &tv);
159  } else
160  event_active(&cdata->timer, EV_TIMEOUT, 1);
161 
162  if (!wait)
163  return (CMD_RETURN_NORMAL);
164  return (CMD_RETURN_WAIT);
165 }
166 
167 static void
168 cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
169 {
170  struct cmd_run_shell_data *cdata = arg;
171  struct client *c = cdata->client;
172  const char *cmd = cdata->cmd;
173  char *error;
174  struct cmdq_item *item = cdata->item;
175  enum cmd_parse_status status;
176 
177  if (cmd != NULL && cdata->shell) {
178  if (job_run(cmd, 0, NULL, cdata->s, cdata->cwd, NULL,
180  cdata->flags, -1, -1) == NULL)
181  cmd_run_shell_free(cdata);
182  return;
183  }
184 
185  if (cmd != NULL) {
186  if (item != NULL) {
187  status = cmd_parse_and_insert(cmd, &cdata->pi, item,
188  cmdq_get_state(item), &error);
189  } else {
190  status = cmd_parse_and_append(cmd, &cdata->pi, c, NULL,
191  &error);
192  }
193  if (status == CMD_PARSE_ERROR) {
194  if (cdata->item == NULL) {
195  *error = toupper((u_char)*error);
196  status_message_set(c, -1, 1, 0, "%s", error);
197  } else
198  cmdq_error(cdata->item, "%s", error);
199  free(error);
200  }
201  }
202 
203  if (cdata->item != NULL)
204  cmdq_continue(cdata->item);
205  cmd_run_shell_free(cdata);
206 }
207 
208 static void
210 {
211  struct cmd_run_shell_data *cdata = job_get_data(job);
212  struct bufferevent *event = job_get_event(job);
213  struct cmdq_item *item = cdata->item;
214  char *cmd = cdata->cmd, *msg = NULL, *line;
215  size_t size;
216  int retcode, status;
217 
218  do {
219  if ((line = evbuffer_readline(event->input)) != NULL) {
220  cmd_run_shell_print(job, line);
221  free(line);
222  }
223  } while (line != NULL);
224 
225  size = EVBUFFER_LENGTH(event->input);
226  if (size != 0) {
227  line = xmalloc(size + 1);
228  memcpy(line, EVBUFFER_DATA(event->input), size);
229  line[size] = '\0';
230 
231  cmd_run_shell_print(job, line);
232 
233  free(line);
234  }
235 
236  status = job_get_status(job);
237  if (WIFEXITED(status)) {
238  if ((retcode = WEXITSTATUS(status)) != 0)
239  xasprintf(&msg, "'%s' returned %d", cmd, retcode);
240  } else if (WIFSIGNALED(status)) {
241  retcode = WTERMSIG(status);
242  xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
243  retcode += 128;
244  } else
245  retcode = 0;
246  if (msg != NULL)
247  cmd_run_shell_print(job, msg);
248  free(msg);
249 
250  if (item != NULL) {
251  if (cmdq_get_client(item) != NULL &&
252  cmdq_get_client(item)->session == NULL)
253  cmdq_get_client(item)->retval = retcode;
254  cmdq_continue(item);
255  }
256 }
257 
258 static void
260 {
261  struct cmd_run_shell_data *cdata = data;
262 
263  evtimer_del(&cdata->timer);
264  if (cdata->s != NULL)
265  session_remove_ref(cdata->s, __func__);
266  if (cdata->client != NULL)
267  server_client_unref(cdata->client);
268  free(cdata->cwd);
269  free(cdata->cmd);
270  free(cdata);
271 }
int args_has(struct args *args, u_char flag)
Definition: arguments.c:259
const char * args_get(struct args *args, u_char flag)
Definition: arguments.c:295
int cmd_find_from_nothing(struct cmd_find_state *fs, int flags)
Definition: cmd-find.c:819
void cmd_find_copy_state(struct cmd_find_state *dst, struct cmd_find_state *src)
Definition: cmd-find.c:689
enum cmd_parse_status cmd_parse_and_insert(const char *s, struct cmd_parse_input *pi, struct cmdq_item *after, struct cmdq_state *state, char **error)
Definition: cmd-parse.c:615
enum cmd_parse_status cmd_parse_and_append(const char *s, struct cmd_parse_input *pi, struct client *c, struct cmdq_state *state, char **error)
Definition: cmd-parse.c:641
void cmdq_print(struct cmdq_item *item, const char *fmt,...)
Definition: cmd-queue.c:792
struct client * cmdq_get_target_client(struct cmdq_item *item)
Definition: cmd-queue.c:157
struct cmdq_state * cmdq_get_state(struct cmdq_item *item)
Definition: cmd-queue.c:164
struct client * cmdq_get_client(struct cmdq_item *item)
Definition: cmd-queue.c:150
struct cmd_find_state * cmdq_get_target(struct cmdq_item *item)
Definition: cmd-queue.c:171
void cmdq_continue(struct cmdq_item *item)
Definition: cmd-queue.c:434
void cmdq_error(struct cmdq_item *item, const char *fmt,...)
Definition: cmd-queue.c:833
const struct cmd_entry cmd_run_shell_entry
Definition: cmd-run-shell.c:40
static void cmd_run_shell_callback(struct job *)
static void cmd_run_shell_free(void *)
static void cmd_run_shell_timer(int, short, void *)
static enum cmd_retval cmd_run_shell_exec(struct cmd *, struct cmdq_item *)
Definition: cmd-run-shell.c:95
static void cmd_run_shell_print(struct job *, const char *)
Definition: cmd-run-shell.c:67
struct args * cmd_get_args(struct cmd *cmd)
Definition: cmd.c:393
void cmd_get_source(struct cmd *cmd, const char **file, u_int *line)
Definition: cmd.c:407
#define __unused
Definition: compat.h:60
char * format_single_from_target(struct cmdq_item *item, const char *fmt)
Definition: format.c:4643
void * job_get_data(struct job *job)
Definition: job.c:332
int job_get_status(struct job *job)
Definition: job.c:325
struct bufferevent * job_get_event(struct job *job)
Definition: job.c:339
void server_client_unref(struct client *c)
const char * server_client_get_cwd(struct client *c, struct session *s)
void session_add_ref(struct session *s, const char *from)
Definition: session.c:165
void session_remove_ref(struct session *s, const char *from)
Definition: session.c:173
void status_message_set(struct client *c, int delay, int ignore_styles, int ignore_keys, const char *fmt,...)
Definition: status.c:428
Definition: tmux.h:1435
int argc
Definition: tmux.h:1437
char ** argv
Definition: tmux.h:1438
Definition: tmux.h:1608
int retval
Definition: tmux.h:1622
int references
Definition: tmux.h:1746
Definition: tmux.h:1525
const char * name
Definition: tmux.h:1526
struct window_pane * wp
Definition: tmux.h:1454
struct session * s
Definition: tmux.h:1451
struct cmdq_item * item
Definition: tmux.h:1504
u_int line
Definition: tmux.h:1502
struct cmd_find_state fs
Definition: tmux.h:1506
struct client * c
Definition: tmux.h:1505
const char * file
Definition: tmux.h:1501
struct session * s
Definition: cmd-run-shell.c:59
struct cmdq_item * item
Definition: cmd-run-shell.c:58
struct client * client
Definition: cmd-run-shell.c:54
struct cmd_parse_input pi
Definition: cmd-run-shell.c:63
struct event timer
Definition: cmd-run-shell.c:61
Definition: cmd.c:212
void * data
Definition: cmd-queue.c:63
Definition: job.c:42
Definition: tmux.h:1179
Definition: tmux.h:927
const struct window_mode * mode
Definition: tmux.h:931
struct window_pane * wp
Definition: tmux.h:928
u_int id
Definition: tmux.h:959
struct job * job_run(const char *, int, char **, struct session *, const char *, job_update_cb, job_complete_cb, job_free_cb, void *, int, int, int)
#define CMD_FIND_CANFAIL
Definition: tmux.h:1465
void window_copy_add(struct window_pane *, const char *,...)
Definition: window-copy.c:503
cmd_retval
Definition: tmux.h:1475
@ CMD_RETURN_NORMAL
Definition: tmux.h:1477
@ CMD_RETURN_ERROR
Definition: tmux.h:1476
@ CMD_RETURN_WAIT
Definition: tmux.h:1478
struct window_pane * window_pane_find_by_id(u_int)
Definition: window.c:841
cmd_parse_status
Definition: tmux.h:1483
@ CMD_PARSE_ERROR
Definition: tmux.h:1485
int window_pane_set_mode(struct window_pane *, struct window_pane *, const struct window_mode *, struct cmd_find_state *, struct args *)
Definition: window.c:1068
#define CMD_TARGET_PANE_USAGE
Definition: tmux.h:1858
const struct window_mode window_view_mode
Definition: window-copy.c:157
#define JOB_NOWAIT
Definition: tmux.h:2099
@ CMD_FIND_PANE
Definition: tmux.h:1443
void * xmalloc(size_t size)
Definition: xmalloc.c:27
int xasprintf(char **ret, const char *fmt,...)
Definition: xmalloc.c:109
void * xcalloc(size_t nmemb, size_t size)
Definition: xmalloc.c:41
char * xstrdup(const char *str)
Definition: xmalloc.c:89