Home | History | Annotate | Line # | Download | only in dist
cmd-run-shell.c revision 1.1.1.8.4.1
      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 	.target = { 't', CMD_FIND_PANE, CMD_FIND_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_from_nothing(&fs, 0) != 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, NULL, NULL) == 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 = cmd_find_client(item, NULL, 1);
     90 	struct session			*s = item->target.s;
     91 	struct winlink			*wl = item->target.wl;
     92 	struct window_pane		*wp = item->target.wp;
     93 
     94 	cdata = xcalloc(1, sizeof *cdata);
     95 	cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
     96 
     97 	if (args_has(args, 't') && wp != NULL)
     98 		cdata->wp_id = wp->id;
     99 	else
    100 		cdata->wp_id = -1;
    101 
    102 	if (!args_has(args, 'b'))
    103 		cdata->item = item;
    104 
    105 	job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
    106 	    cmd_run_shell_callback, cmd_run_shell_free, cdata, 0);
    107 
    108 	if (args_has(args, 'b'))
    109 		return (CMD_RETURN_NORMAL);
    110 	return (CMD_RETURN_WAIT);
    111 }
    112 
    113 static void
    114 cmd_run_shell_callback(struct job *job)
    115 {
    116 	struct cmd_run_shell_data	*cdata = job->data;
    117 	char				*cmd = cdata->cmd, *msg, *line;
    118 	size_t				 size;
    119 	int				 retcode;
    120 
    121 	do {
    122 		if ((line = evbuffer_readline(job->event->input)) != NULL) {
    123 			cmd_run_shell_print(job, line);
    124 			free(line);
    125 		}
    126 	} while (line != NULL);
    127 
    128 	size = EVBUFFER_LENGTH(job->event->input);
    129 	if (size != 0) {
    130 		line = xmalloc(size + 1);
    131 		memcpy(line, EVBUFFER_DATA(job->event->input), size);
    132 		line[size] = '\0';
    133 
    134 		cmd_run_shell_print(job, line);
    135 
    136 		free(line);
    137 	}
    138 
    139 	msg = NULL;
    140 	if (WIFEXITED(job->status)) {
    141 		if ((retcode = WEXITSTATUS(job->status)) != 0)
    142 			xasprintf(&msg, "'%s' returned %d", cmd, retcode);
    143 	} else if (WIFSIGNALED(job->status)) {
    144 		retcode = WTERMSIG(job->status);
    145 		xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
    146 	}
    147 	if (msg != NULL)
    148 		cmd_run_shell_print(job, msg);
    149 	free(msg);
    150 
    151 	if (cdata->item != NULL)
    152 		cdata->item->flags &= ~CMDQ_WAITING;
    153 }
    154 
    155 static void
    156 cmd_run_shell_free(void *data)
    157 {
    158 	struct cmd_run_shell_data	*cdata = data;
    159 
    160 	free(cdata->cmd);
    161 	free(cdata);
    162 }
    163