1*03a1f8ddSnicm /* $OpenBSD: cmd-if-shell.c,v 1.84 2021/10/11 10:55:30 nicm Exp $ */
24983507eSnicm
34983507eSnicm /*
44983507eSnicm * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
5cd21dd5dSnicm * Copyright (c) 2009 Nicholas Marriott <nicm@openbsd.org>
64983507eSnicm *
74983507eSnicm * Permission to use, copy, modify, and distribute this software for any
84983507eSnicm * purpose with or without fee is hereby granted, provided that the above
94983507eSnicm * copyright notice and this permission notice appear in all copies.
104983507eSnicm *
114983507eSnicm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
124983507eSnicm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
134983507eSnicm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
144983507eSnicm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
154983507eSnicm * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
164983507eSnicm * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
174983507eSnicm * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
184983507eSnicm */
194983507eSnicm
204983507eSnicm #include <sys/types.h>
21cd21dd5dSnicm #include <sys/wait.h>
224983507eSnicm
2367a3a2b6Snicm #include <ctype.h>
247d053cf9Snicm #include <stdlib.h>
254983507eSnicm #include <string.h>
264983507eSnicm
274983507eSnicm #include "tmux.h"
284983507eSnicm
294983507eSnicm /*
3012828c2bSnicm * Executes a tmux command if a shell command returns true or false.
314983507eSnicm */
324983507eSnicm
33e4c0b811Snicm static enum args_parse_type cmd_if_shell_args_parse(struct args *, u_int,
34e4c0b811Snicm char **);
35e4c0b811Snicm static enum cmd_retval cmd_if_shell_exec(struct cmd *,
36e4c0b811Snicm struct cmdq_item *);
374983507eSnicm
38dc1f0f5fSnicm static void cmd_if_shell_callback(struct job *);
39dc1f0f5fSnicm static void cmd_if_shell_free(void *);
404983507eSnicm
414983507eSnicm const struct cmd_entry cmd_if_shell_entry = {
42c057646bSnicm .name = "if-shell",
43c057646bSnicm .alias = "if",
44c057646bSnicm
45e4c0b811Snicm .args = { "bFt:", 2, 3, cmd_if_shell_args_parse },
46c057646bSnicm .usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
47c057646bSnicm "[command]",
48c057646bSnicm
49bf0d297eSnicm .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
508d471e80Snicm
518d471e80Snicm .flags = 0,
52c057646bSnicm .exec = cmd_if_shell_exec
534983507eSnicm };
544983507eSnicm
55cd21dd5dSnicm struct cmd_if_shell_data {
5667a3a2b6Snicm struct args_command_state *cmd_if;
5767a3a2b6Snicm struct args_command_state *cmd_else;
58ea090d8cSnicm
59765b9a58Snicm struct client *client;
6068e0a7f2Snicm struct cmdq_item *item;
61cd21dd5dSnicm };
624983507eSnicm
63e4c0b811Snicm static enum args_parse_type
cmd_if_shell_args_parse(__unused struct args * args,u_int idx,__unused char ** cause)64e4c0b811Snicm cmd_if_shell_args_parse(__unused struct args *args, u_int idx,
65e4c0b811Snicm __unused char **cause)
66e4c0b811Snicm {
67e4c0b811Snicm if (idx == 1 || idx == 2)
68e4c0b811Snicm return (ARGS_PARSE_COMMANDS_OR_STRING);
69e4c0b811Snicm return (ARGS_PARSE_STRING);
70e4c0b811Snicm }
71e4c0b811Snicm
72dc1f0f5fSnicm static enum cmd_retval
cmd_if_shell_exec(struct cmd * self,struct cmdq_item * item)7368e0a7f2Snicm cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
744983507eSnicm {
7590d7ba38Snicm struct args *args = cmd_get_args(self);
76040343aeSnicm struct cmd_find_state *target = cmdq_get_target(item);
77cd21dd5dSnicm struct cmd_if_shell_data *cdata;
782db6a388Snicm struct cmdq_item *new_item;
792db6a388Snicm char *shellcmd;
80035dc73dSnicm struct client *tc = cmdq_get_target_client(item);
81040343aeSnicm struct session *s = target->s;
8267a3a2b6Snicm struct cmd_list *cmdlist;
831693b10bSnicm u_int count = args_count(args);
8467a3a2b6Snicm int wait = !args_has(args, 'b');
851549639cSnicm
861693b10bSnicm shellcmd = format_single_from_target(item, args_string(args, 0));
87e3ea15f3Snicm if (args_has(args, 'F')) {
88e3ea15f3Snicm if (*shellcmd != '0' && *shellcmd != '\0')
890b5b9347Snicm cmdlist = args_make_commands_now(self, item, 1, 0);
901693b10bSnicm else if (count == 3)
910b5b9347Snicm cmdlist = args_make_commands_now(self, item, 2, 0);
922db6a388Snicm else {
9359fc359aSnicm free(shellcmd);
94e3ea15f3Snicm return (CMD_RETURN_NORMAL);
95df6ab229Snicm }
962db6a388Snicm free(shellcmd);
972db6a388Snicm if (cmdlist == NULL)
982db6a388Snicm return (CMD_RETURN_ERROR);
992db6a388Snicm new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
1002db6a388Snicm cmdq_insert_after(item, new_item);
101e3ea15f3Snicm return (CMD_RETURN_NORMAL);
102e3ea15f3Snicm }
103e3ea15f3Snicm
10410c3dabaSnicm cdata = xcalloc(1, sizeof *cdata);
105ea090d8cSnicm
10667a3a2b6Snicm cdata->cmd_if = args_make_commands_prepare(self, item, 1, NULL, wait,
10767a3a2b6Snicm 0);
1082db6a388Snicm if (count == 3) {
10967a3a2b6Snicm cdata->cmd_else = args_make_commands_prepare(self, item, 2,
11067a3a2b6Snicm NULL, wait, 0);
1112db6a388Snicm }
112ea090d8cSnicm
11367a3a2b6Snicm if (wait) {
114040343aeSnicm cdata->client = cmdq_get_client(item);
11567a3a2b6Snicm cdata->item = item;
11667a3a2b6Snicm } else
117035dc73dSnicm cdata->client = tc;
118cb1db415Snicm if (cdata->client != NULL)
119765b9a58Snicm cdata->client->references++;
120cd21dd5dSnicm
121*03a1f8ddSnicm if (job_run(shellcmd, 0, NULL, NULL, s,
122040343aeSnicm server_client_get_cwd(cmdq_get_client(item), s), NULL,
123a6396ca2Snicm cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
124a6396ca2Snicm -1) == NULL) {
12504131cdaSnicm cmdq_error(item, "failed to run command: %s", shellcmd);
12604131cdaSnicm free(shellcmd);
12704131cdaSnicm free(cdata);
12804131cdaSnicm return (CMD_RETURN_ERROR);
12904131cdaSnicm }
1300a0dfdd8Snicm free(shellcmd);
131cd21dd5dSnicm
13267a3a2b6Snicm if (!wait)
133175d36ccSnicm return (CMD_RETURN_NORMAL);
134175d36ccSnicm return (CMD_RETURN_WAIT);
135cd21dd5dSnicm }
136cd21dd5dSnicm
137dc1f0f5fSnicm static void
cmd_if_shell_callback(struct job * job)138cd21dd5dSnicm cmd_if_shell_callback(struct job *job)
139cd21dd5dSnicm {
1409430fe9eSnicm struct cmd_if_shell_data *cdata = job_get_data(job);
141765b9a58Snicm struct client *c = cdata->client;
1422db6a388Snicm struct cmdq_item *item = cdata->item, *new_item;
14367a3a2b6Snicm struct args_command_state *state;
1442db6a388Snicm struct cmd_list *cmdlist;
14567a3a2b6Snicm char *error;
1469430fe9eSnicm int status;
147175d36ccSnicm
1489430fe9eSnicm status = job_get_status(job);
1499430fe9eSnicm if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
15067a3a2b6Snicm state = cdata->cmd_else;
151175d36ccSnicm else
15267a3a2b6Snicm state = cdata->cmd_if;
15367a3a2b6Snicm if (state == NULL)
154765b9a58Snicm goto out;
155175d36ccSnicm
15667a3a2b6Snicm cmdlist = args_make_commands(state, 0, NULL, &error);
15767a3a2b6Snicm if (cmdlist == NULL) {
15867a3a2b6Snicm if (cdata->item == NULL) {
15967a3a2b6Snicm *error = toupper((u_char)*error);
16067a3a2b6Snicm status_message_set(c, -1, 1, 0, "%s", error);
16167a3a2b6Snicm } else
16267a3a2b6Snicm cmdq_error(cdata->item, "%s", error);
16367a3a2b6Snicm free(error);
16467a3a2b6Snicm } else if (item == NULL) {
1652db6a388Snicm new_item = cmdq_get_command(cmdlist, NULL);
16668e0a7f2Snicm cmdq_append(c, new_item);
1672db6a388Snicm } else {
1682db6a388Snicm new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
1692db6a388Snicm cmdq_insert_after(item, new_item);
170765b9a58Snicm }
171175d36ccSnicm
172765b9a58Snicm out:
17368e0a7f2Snicm if (cdata->item != NULL)
174780ca620Snicm cmdq_continue(cdata->item);
175175d36ccSnicm }
176175d36ccSnicm
177dc1f0f5fSnicm static void
cmd_if_shell_free(void * data)178cd21dd5dSnicm cmd_if_shell_free(void *data)
1794983507eSnicm {
180cd21dd5dSnicm struct cmd_if_shell_data *cdata = data;
1814983507eSnicm
182cb1db415Snicm if (cdata->client != NULL)
183765b9a58Snicm server_client_unref(cdata->client);
1844983507eSnicm
1852db6a388Snicm if (cdata->cmd_else != NULL)
18667a3a2b6Snicm args_make_commands_free(cdata->cmd_else);
18767a3a2b6Snicm args_make_commands_free(cdata->cmd_if);
188df6ab229Snicm
1897d053cf9Snicm free(cdata);
1904983507eSnicm }
191