Home | History | Annotate | Line # | Download | only in dist
cmd-run-shell.c revision 1.1.1.7
      1 /* $OpenBSD$ */
      2 
      3 /*
      4  * Copyright (c) 2009 Tiago Cunha <me (at) tiagocunha.org>
      5  * Copyright (c) 2009 Nicholas Marriott <nicm (at) 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 static enum cmd_retval	cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
     33 
     34 static void	cmd_run_shell_callback(struct job *);
     35 static void	cmd_run_shell_free(void *);
     36 static 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 cmdq_item	*item;
     54 	int			 wp_id;
     55 };
     56 
     57 static void
     58 cmd_run_shell_print(struct job *job, const char *msg)
     59 {
     60 	struct cmd_run_shell_data	*cdata = job->data;
     61 	struct window_pane		*wp = NULL;
     62 	struct cmd_find_state		 fs;
     63 
     64 	if (cdata->wp_id != -1)
     65 		wp = window_pane_find_by_id(cdata->wp_id);
     66 	if (wp == NULL) {
     67 		if (cdata->item != NULL) {
     68 			cmdq_print(cdata->item, "%s", msg);
     69 			return;
     70 		}
     71 		if (cmd_find_current (&fs, NULL, CMD_FIND_QUIET) != 0)
     72 			return;
     73 		wp = fs.wp;
     74 		if (wp == NULL)
     75 			return;
     76 	}
     77 
     78 	if (window_pane_set_mode(wp, &window_copy_mode) == 0)
     79 		window_copy_init_for_output(wp);
     80 	if (wp->mode == &window_copy_mode)
     81 		window_copy_add(wp, "%s", msg);
     82 }
     83 
     84 static enum cmd_retval
     85 cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
     86 {
     87 	struct args			*args = self->args;
     88 	struct cmd_run_shell_data	*cdata;
     89 	struct client			*c = item->state.c;
     90 	struct session			*s = item->state.tflag.s;
     91 	struct winlink			*wl = item->state.tflag.wl;
     92 	struct window_pane		*wp = item->state.tflag.wp;
     93 	const char			*cwd;
     94 
     95 	if (item->client != NULL && item->client->session == NULL)
     96 		cwd = item->client->cwd;
     97 	else if (s != NULL)
     98 		cwd = s->cwd;
     99 	else
    100 		cwd = NULL;
    101 
    102 	cdata = xcalloc(1, sizeof *cdata);
    103 	cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
    104 
    105 	if (args_has(args, 't') && wp != NULL)
    106 		cdata->wp_id = wp->id;
    107 	else
    108 		cdata->wp_id = -1;
    109 
    110 	if (!args_has(args, 'b'))
    111 		cdata->item = item;
    112 
    113 	job_run(cdata->cmd, s, cwd, cmd_run_shell_callback, cmd_run_shell_free,
    114 	    cdata);
    115 
    116 	if (args_has(args, 'b'))
    117 		return (CMD_RETURN_NORMAL);
    118 	return (CMD_RETURN_WAIT);
    119 }
    120 
    121 static void
    122 cmd_run_shell_callback(struct job *job)
    123 {
    124 	struct cmd_run_shell_data	*cdata = job->data;
    125 	char				*cmd = cdata->cmd, *msg, *line;
    126 	size_t				 size;
    127 	int				 retcode;
    128 
    129 	do {
    130 		if ((line = evbuffer_readline(job->event->input)) != NULL) {
    131 			cmd_run_shell_print(job, line);
    132 			free(line);
    133 		}
    134 	} while (line != NULL);
    135 
    136 	size = EVBUFFER_LENGTH(job->event->input);
    137 	if (size != 0) {
    138 		line = xmalloc(size + 1);
    139 		memcpy(line, EVBUFFER_DATA(job->event->input), size);
    140 		line[size] = '\0';
    141 
    142 		cmd_run_shell_print(job, line);
    143 
    144 		free(line);
    145 	}
    146 
    147 	msg = NULL;
    148 	if (WIFEXITED(job->status)) {
    149 		if ((retcode = WEXITSTATUS(job->status)) != 0)
    150 			xasprintf(&msg, "'%s' returned %d", cmd, retcode);
    151 	} else if (WIFSIGNALED(job->status)) {
    152 		retcode = WTERMSIG(job->status);
    153 		xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
    154 	}
    155 	if (msg != NULL)
    156 		cmd_run_shell_print(job, msg);
    157 	free(msg);
    158 
    159 	if (cdata->item != NULL)
    160 		cdata->item->flags &= ~CMDQ_WAITING;
    161 }
    162 
    163 static void
    164 cmd_run_shell_free(void *data)
    165 {
    166 	struct cmd_run_shell_data	*cdata = data;
    167 
    168 	free(cdata->cmd);
    169 	free(cdata);
    170 }
    171