Home | History | Annotate | Line # | Download | only in dist
cmd-run-shell.c revision 1.1.1.8.4.1
      1      1.1.1.5  christos /* $OpenBSD$ */
      2          1.1      jmmv 
      3          1.1      jmmv /*
      4          1.1      jmmv  * Copyright (c) 2009 Tiago Cunha <me (at) tiagocunha.org>
      5          1.1      jmmv  * Copyright (c) 2009 Nicholas Marriott <nicm (at) openbsd.org>
      6          1.1      jmmv  *
      7          1.1      jmmv  * Permission to use, copy, modify, and distribute this software for any
      8          1.1      jmmv  * purpose with or without fee is hereby granted, provided that the above
      9          1.1      jmmv  * copyright notice and this permission notice appear in all copies.
     10          1.1      jmmv  *
     11          1.1      jmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     12          1.1      jmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     13          1.1      jmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     14          1.1      jmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     15          1.1      jmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
     16          1.1      jmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     17          1.1      jmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     18          1.1      jmmv  */
     19          1.1      jmmv 
     20          1.1      jmmv #include <sys/types.h>
     21          1.1      jmmv #include <sys/wait.h>
     22          1.1      jmmv 
     23      1.1.1.3  christos #include <stdlib.h>
     24          1.1      jmmv #include <string.h>
     25          1.1      jmmv 
     26          1.1      jmmv #include "tmux.h"
     27          1.1      jmmv 
     28          1.1      jmmv /*
     29          1.1      jmmv  * Runs a command without a window.
     30          1.1      jmmv  */
     31          1.1      jmmv 
     32      1.1.1.7  christos static enum cmd_retval	cmd_run_shell_exec(struct cmd *, struct cmdq_item *);
     33          1.1      jmmv 
     34      1.1.1.7  christos static void	cmd_run_shell_callback(struct job *);
     35      1.1.1.7  christos static void	cmd_run_shell_free(void *);
     36      1.1.1.7  christos static void	cmd_run_shell_print(struct job *, const char *);
     37          1.1      jmmv 
     38          1.1      jmmv const struct cmd_entry cmd_run_shell_entry = {
     39      1.1.1.6  christos 	.name = "run-shell",
     40      1.1.1.6  christos 	.alias = "run",
     41      1.1.1.6  christos 
     42      1.1.1.6  christos 	.args = { "bt:", 1, 1 },
     43      1.1.1.6  christos 	.usage = "[-b] " CMD_TARGET_PANE_USAGE " shell-command",
     44      1.1.1.6  christos 
     45      1.1.1.8  christos 	.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
     46      1.1.1.6  christos 
     47      1.1.1.6  christos 	.flags = 0,
     48      1.1.1.6  christos 	.exec = cmd_run_shell_exec
     49          1.1      jmmv };
     50          1.1      jmmv 
     51          1.1      jmmv struct cmd_run_shell_data {
     52      1.1.1.7  christos 	char			*cmd;
     53      1.1.1.7  christos 	struct cmdq_item	*item;
     54      1.1.1.7  christos 	int			 wp_id;
     55          1.1      jmmv };
     56          1.1      jmmv 
     57      1.1.1.7  christos static void
     58      1.1.1.3  christos cmd_run_shell_print(struct job *job, const char *msg)
     59          1.1      jmmv {
     60      1.1.1.3  christos 	struct cmd_run_shell_data	*cdata = job->data;
     61      1.1.1.3  christos 	struct window_pane		*wp = NULL;
     62      1.1.1.7  christos 	struct cmd_find_state		 fs;
     63          1.1      jmmv 
     64      1.1.1.3  christos 	if (cdata->wp_id != -1)
     65      1.1.1.3  christos 		wp = window_pane_find_by_id(cdata->wp_id);
     66      1.1.1.3  christos 	if (wp == NULL) {
     67      1.1.1.7  christos 		if (cdata->item != NULL) {
     68      1.1.1.7  christos 			cmdq_print(cdata->item, "%s", msg);
     69      1.1.1.7  christos 			return;
     70      1.1.1.7  christos 		}
     71      1.1.1.8  christos 		if (cmd_find_from_nothing(&fs, 0) != 0)
     72      1.1.1.7  christos 			return;
     73      1.1.1.7  christos 		wp = fs.wp;
     74      1.1.1.7  christos 		if (wp == NULL)
     75      1.1.1.7  christos 			return;
     76      1.1.1.3  christos 	}
     77          1.1      jmmv 
     78      1.1.1.8  christos 	if (window_pane_set_mode(wp, &window_copy_mode, NULL, NULL) == 0)
     79      1.1.1.3  christos 		window_copy_init_for_output(wp);
     80      1.1.1.3  christos 	if (wp->mode == &window_copy_mode)
     81      1.1.1.3  christos 		window_copy_add(wp, "%s", msg);
     82      1.1.1.3  christos }
     83          1.1      jmmv 
     84      1.1.1.7  christos static enum cmd_retval
     85      1.1.1.7  christos cmd_run_shell_exec(struct cmd *self, struct cmdq_item *item)
     86      1.1.1.3  christos {
     87      1.1.1.3  christos 	struct args			*args = self->args;
     88      1.1.1.3  christos 	struct cmd_run_shell_data	*cdata;
     89      1.1.1.8  christos 	struct client			*c = cmd_find_client(item, NULL, 1);
     90      1.1.1.8  christos 	struct session			*s = item->target.s;
     91      1.1.1.8  christos 	struct winlink			*wl = item->target.wl;
     92      1.1.1.8  christos 	struct window_pane		*wp = item->target.wp;
     93      1.1.1.3  christos 
     94      1.1.1.7  christos 	cdata = xcalloc(1, sizeof *cdata);
     95      1.1.1.7  christos 	cdata->cmd = format_single(item, args->argv[0], c, s, wl, wp);
     96      1.1.1.7  christos 
     97      1.1.1.7  christos 	if (args_has(args, 't') && wp != NULL)
     98      1.1.1.7  christos 		cdata->wp_id = wp->id;
     99      1.1.1.7  christos 	else
    100      1.1.1.7  christos 		cdata->wp_id = -1;
    101      1.1.1.7  christos 
    102      1.1.1.7  christos 	if (!args_has(args, 'b'))
    103      1.1.1.7  christos 		cdata->item = item;
    104      1.1.1.3  christos 
    105  1.1.1.8.4.1  christos 	job_run(cdata->cmd, s, server_client_get_cwd(item->client, s), NULL,
    106  1.1.1.8.4.1  christos 	    cmd_run_shell_callback, cmd_run_shell_free, cdata, 0);
    107      1.1.1.3  christos 
    108      1.1.1.7  christos 	if (args_has(args, 'b'))
    109      1.1.1.3  christos 		return (CMD_RETURN_NORMAL);
    110      1.1.1.3  christos 	return (CMD_RETURN_WAIT);
    111          1.1      jmmv }
    112          1.1      jmmv 
    113      1.1.1.7  christos static void
    114          1.1      jmmv cmd_run_shell_callback(struct job *job)
    115          1.1      jmmv {
    116          1.1      jmmv 	struct cmd_run_shell_data	*cdata = job->data;
    117      1.1.1.7  christos 	char				*cmd = cdata->cmd, *msg, *line;
    118          1.1      jmmv 	size_t				 size;
    119          1.1      jmmv 	int				 retcode;
    120          1.1      jmmv 
    121          1.1      jmmv 	do {
    122          1.1      jmmv 		if ((line = evbuffer_readline(job->event->input)) != NULL) {
    123      1.1.1.3  christos 			cmd_run_shell_print(job, line);
    124      1.1.1.3  christos 			free(line);
    125          1.1      jmmv 		}
    126          1.1      jmmv 	} while (line != NULL);
    127          1.1      jmmv 
    128          1.1      jmmv 	size = EVBUFFER_LENGTH(job->event->input);
    129          1.1      jmmv 	if (size != 0) {
    130          1.1      jmmv 		line = xmalloc(size + 1);
    131          1.1      jmmv 		memcpy(line, EVBUFFER_DATA(job->event->input), size);
    132          1.1      jmmv 		line[size] = '\0';
    133          1.1      jmmv 
    134      1.1.1.3  christos 		cmd_run_shell_print(job, line);
    135          1.1      jmmv 
    136      1.1.1.3  christos 		free(line);
    137          1.1      jmmv 	}
    138          1.1      jmmv 
    139          1.1      jmmv 	msg = NULL;
    140          1.1      jmmv 	if (WIFEXITED(job->status)) {
    141          1.1      jmmv 		if ((retcode = WEXITSTATUS(job->status)) != 0)
    142          1.1      jmmv 			xasprintf(&msg, "'%s' returned %d", cmd, retcode);
    143          1.1      jmmv 	} else if (WIFSIGNALED(job->status)) {
    144          1.1      jmmv 		retcode = WTERMSIG(job->status);
    145          1.1      jmmv 		xasprintf(&msg, "'%s' terminated by signal %d", cmd, retcode);
    146          1.1      jmmv 	}
    147      1.1.1.5  christos 	if (msg != NULL)
    148      1.1.1.5  christos 		cmd_run_shell_print(job, msg);
    149      1.1.1.5  christos 	free(msg);
    150      1.1.1.7  christos 
    151      1.1.1.7  christos 	if (cdata->item != NULL)
    152      1.1.1.7  christos 		cdata->item->flags &= ~CMDQ_WAITING;
    153          1.1      jmmv }
    154          1.1      jmmv 
    155      1.1.1.7  christos static void
    156          1.1      jmmv cmd_run_shell_free(void *data)
    157          1.1      jmmv {
    158          1.1      jmmv 	struct cmd_run_shell_data	*cdata = data;
    159          1.1      jmmv 
    160      1.1.1.3  christos 	free(cdata->cmd);
    161      1.1.1.3  christos 	free(cdata);
    162          1.1      jmmv }
    163