Home | History | Annotate | Line # | Download | only in dist
cmd-if-shell.c revision 1.10
      1   1.4  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.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.3  christos  * Executes a tmux command if a shell command returns true or false.
     30   1.1      jmmv  */
     31   1.1      jmmv 
     32   1.6  christos static enum cmd_retval	cmd_if_shell_exec(struct cmd *, struct cmdq_item *);
     33   1.1      jmmv 
     34   1.6  christos static void		cmd_if_shell_callback(struct job *);
     35   1.6  christos static void		cmd_if_shell_free(void *);
     36   1.1      jmmv 
     37   1.1      jmmv const struct cmd_entry cmd_if_shell_entry = {
     38   1.5  christos 	.name = "if-shell",
     39   1.5  christos 	.alias = "if",
     40   1.5  christos 
     41   1.5  christos 	.args = { "bFt:", 2, 3 },
     42   1.5  christos 	.usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
     43   1.5  christos 		 "[command]",
     44   1.5  christos 
     45   1.7  christos 	.target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
     46   1.5  christos 
     47   1.5  christos 	.flags = 0,
     48   1.5  christos 	.exec = cmd_if_shell_exec
     49   1.1      jmmv };
     50   1.1      jmmv 
     51   1.1      jmmv struct cmd_if_shell_data {
     52  1.10  christos 	struct cmd_parse_input	 input;
     53   1.6  christos 
     54   1.4  christos 	char			*cmd_if;
     55   1.4  christos 	char			*cmd_else;
     56   1.4  christos 
     57   1.6  christos 	struct client		*client;
     58   1.6  christos 	struct cmdq_item	*item;
     59   1.4  christos 	struct mouse_event	 mouse;
     60   1.1      jmmv };
     61   1.1      jmmv 
     62   1.6  christos static enum cmd_retval
     63   1.6  christos cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
     64   1.1      jmmv {
     65   1.2  christos 	struct args			*args = self->args;
     66  1.10  christos 	struct mouse_event		*m = &item->shared->mouse;
     67   1.1      jmmv 	struct cmd_if_shell_data	*cdata;
     68  1.10  christos 	char				*shellcmd, *cmd;
     69   1.6  christos 	struct cmdq_item		*new_item;
     70  1.10  christos 	struct cmd_find_state		*fs = &item->target;
     71   1.7  christos 	struct client			*c = cmd_find_client(item, NULL, 1);
     72  1.10  christos 	struct session			*s = fs->s;
     73  1.10  christos 	struct winlink			*wl = fs->wl;
     74  1.10  christos 	struct window_pane		*wp = fs->wp;
     75  1.10  christos 	struct cmd_parse_input		 pi;
     76  1.10  christos 	struct cmd_parse_result		*pr;
     77   1.3  christos 
     78   1.6  christos 	shellcmd = format_single(item, args->argv[0], c, s, wl, wp);
     79   1.4  christos 	if (args_has(args, 'F')) {
     80   1.4  christos 		if (*shellcmd != '0' && *shellcmd != '\0')
     81   1.4  christos 			cmd = args->argv[1];
     82   1.4  christos 		else if (args->argc == 3)
     83   1.4  christos 			cmd = args->argv[2];
     84  1.10  christos 		else
     85  1.10  christos 			cmd = NULL;
     86   1.5  christos 		free(shellcmd);
     87   1.4  christos 		if (cmd == NULL)
     88   1.4  christos 			return (CMD_RETURN_NORMAL);
     89  1.10  christos 
     90  1.10  christos 		memset(&pi, 0, sizeof pi);
     91  1.10  christos 		if (self->file != NULL)
     92  1.10  christos 			pi.file = self->file;
     93  1.10  christos 		pi.line = self->line;
     94  1.10  christos 		pi.item = item;
     95  1.10  christos 		pi.c = c;
     96  1.10  christos 		cmd_find_copy_state(&pi.fs, fs);
     97  1.10  christos 
     98  1.10  christos 		pr = cmd_parse_from_string(cmd, &pi);
     99  1.10  christos 		switch (pr->status) {
    100  1.10  christos 		case CMD_PARSE_EMPTY:
    101  1.10  christos 			break;
    102  1.10  christos 		case CMD_PARSE_ERROR:
    103  1.10  christos 			cmdq_error(item, "%s", pr->error);
    104  1.10  christos 			free(pr->error);
    105   1.4  christos 			return (CMD_RETURN_ERROR);
    106  1.10  christos 		case CMD_PARSE_SUCCESS:
    107  1.10  christos 			new_item = cmdq_get_command(pr->cmdlist, fs, m, 0);
    108  1.10  christos 			cmdq_insert_after(item, new_item);
    109  1.10  christos 			cmd_list_free(pr->cmdlist);
    110  1.10  christos 			break;
    111   1.4  christos 		}
    112   1.4  christos 		return (CMD_RETURN_NORMAL);
    113   1.4  christos 	}
    114   1.4  christos 
    115   1.6  christos 	cdata = xcalloc(1, sizeof *cdata);
    116   1.4  christos 
    117   1.3  christos 	cdata->cmd_if = xstrdup(args->argv[1]);
    118   1.3  christos 	if (args->argc == 3)
    119   1.3  christos 		cdata->cmd_else = xstrdup(args->argv[2]);
    120   1.3  christos 	else
    121   1.3  christos 		cdata->cmd_else = NULL;
    122  1.10  christos 	memcpy(&cdata->mouse, m, sizeof cdata->mouse);
    123   1.4  christos 
    124  1.10  christos 	if (!args_has(args, 'b'))
    125  1.10  christos 		cdata->client = item->client;
    126  1.10  christos 	else
    127  1.10  christos 		cdata->client = c;
    128   1.7  christos 	if (cdata->client != NULL)
    129   1.7  christos 		cdata->client->references++;
    130   1.3  christos 
    131   1.6  christos 	if (!args_has(args, 'b'))
    132   1.6  christos 		cdata->item = item;
    133   1.6  christos 	else
    134   1.6  christos 		cdata->item = NULL;
    135  1.10  christos 
    136  1.10  christos 	memset(&cdata->input, 0, sizeof cdata->input);
    137  1.10  christos 	if (self->file != NULL)
    138  1.10  christos 		cdata->input.file = xstrdup(self->file);
    139  1.10  christos 	cdata->input.line = self->line;
    140  1.10  christos 	cdata->input.item = cdata->item;
    141  1.10  christos 	cdata->input.c = c;
    142  1.10  christos 	if (cdata->input.c != NULL)
    143  1.10  christos 		cdata->input.c->references++;
    144  1.10  christos 	cmd_find_copy_state(&cdata->input.fs, fs);
    145   1.3  christos 
    146   1.9  christos 	if (job_run(shellcmd, s, server_client_get_cwd(item->client, s), NULL,
    147   1.9  christos 	    cmd_if_shell_callback, cmd_if_shell_free, cdata, 0) == NULL) {
    148   1.9  christos 		cmdq_error(item, "failed to run command: %s", shellcmd);
    149   1.9  christos 		free(shellcmd);
    150   1.9  christos 		free(cdata);
    151   1.9  christos 		return (CMD_RETURN_ERROR);
    152   1.9  christos 	}
    153   1.3  christos 	free(shellcmd);
    154   1.3  christos 
    155   1.6  christos 	if (args_has(args, 'b'))
    156   1.3  christos 		return (CMD_RETURN_NORMAL);
    157   1.3  christos 	return (CMD_RETURN_WAIT);
    158   1.1      jmmv }
    159   1.1      jmmv 
    160   1.6  christos static void
    161   1.1      jmmv cmd_if_shell_callback(struct job *job)
    162   1.1      jmmv {
    163   1.9  christos 	struct cmd_if_shell_data	*cdata = job_get_data(job);
    164   1.6  christos 	struct client			*c = cdata->client;
    165  1.10  christos 	struct mouse_event		*m = &cdata->mouse;
    166  1.10  christos 	struct cmdq_item		*new_item = NULL;
    167  1.10  christos 	char				*cmd;
    168   1.9  christos 	int				 status;
    169  1.10  christos 	struct cmd_parse_result		*pr;
    170   1.1      jmmv 
    171   1.9  christos 	status = job_get_status(job);
    172   1.9  christos 	if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
    173   1.3  christos 		cmd = cdata->cmd_else;
    174   1.3  christos 	else
    175   1.3  christos 		cmd = cdata->cmd_if;
    176   1.3  christos 	if (cmd == NULL)
    177   1.6  christos 		goto out;
    178   1.1      jmmv 
    179  1.10  christos 	pr = cmd_parse_from_string(cmd, &cdata->input);
    180  1.10  christos 	switch (pr->status) {
    181  1.10  christos 	case CMD_PARSE_EMPTY:
    182  1.10  christos 		break;
    183  1.10  christos 	case CMD_PARSE_ERROR:
    184  1.10  christos 		if (cdata->item != NULL)
    185  1.10  christos 		       cmdq_error(cdata->item, "%s", pr->error);
    186  1.10  christos 		free(pr->error);
    187  1.10  christos 		break;
    188  1.10  christos 	case CMD_PARSE_SUCCESS:
    189  1.10  christos 		new_item = cmdq_get_command(pr->cmdlist, NULL, m, 0);
    190  1.10  christos 		cmd_list_free(pr->cmdlist);
    191  1.10  christos 		break;
    192   1.1      jmmv 	}
    193   1.6  christos 	if (new_item != NULL) {
    194   1.6  christos 		if (cdata->item == NULL)
    195   1.6  christos 			cmdq_append(c, new_item);
    196   1.6  christos 		else
    197   1.6  christos 			cmdq_insert_after(cdata->item, new_item);
    198   1.6  christos 	}
    199   1.3  christos 
    200   1.6  christos out:
    201   1.6  christos 	if (cdata->item != NULL)
    202  1.10  christos 		cmdq_continue(cdata->item);
    203   1.3  christos }
    204   1.3  christos 
    205   1.6  christos static void
    206   1.1      jmmv cmd_if_shell_free(void *data)
    207   1.1      jmmv {
    208   1.1      jmmv 	struct cmd_if_shell_data	*cdata = data;
    209   1.3  christos 
    210   1.7  christos 	if (cdata->client != NULL)
    211   1.7  christos 		server_client_unref(cdata->client);
    212   1.1      jmmv 
    213   1.3  christos 	free(cdata->cmd_else);
    214   1.3  christos 	free(cdata->cmd_if);
    215   1.6  christos 
    216  1.10  christos 	if (cdata->input.c != NULL)
    217  1.10  christos 		server_client_unref(cdata->input.c);
    218  1.10  christos 	free(__UNCONST(cdata->input.file));
    219  1.10  christos 
    220   1.3  christos 	free(cdata);
    221   1.1      jmmv }
    222