Coverage Report

Created: 2023-06-07 06:04

/src/tmux/cmd-if-shell.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
5
 * Copyright (c) 2009 Nicholas Marriott <nicm@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 <ctype.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "tmux.h"
28
29
/*
30
 * Executes a tmux command if a shell command returns true or false.
31
 */
32
33
static enum args_parse_type cmd_if_shell_args_parse(struct args *, u_int,
34
            char **);
35
static enum cmd_retval    cmd_if_shell_exec(struct cmd *,
36
            struct cmdq_item *);
37
38
static void cmd_if_shell_callback(struct job *);
39
static void cmd_if_shell_free(void *);
40
41
const struct cmd_entry cmd_if_shell_entry = {
42
  .name = "if-shell",
43
  .alias = "if",
44
45
  .args = { "bFt:", 2, 3, cmd_if_shell_args_parse },
46
  .usage = "[-bF] " CMD_TARGET_PANE_USAGE " shell-command command "
47
     "[command]",
48
49
  .target = { 't', CMD_FIND_PANE, CMD_FIND_CANFAIL },
50
51
  .flags = 0,
52
  .exec = cmd_if_shell_exec
53
};
54
55
struct cmd_if_shell_data {
56
  struct args_command_state *cmd_if;
57
  struct args_command_state *cmd_else;
58
59
  struct client     *client;
60
  struct cmdq_item    *item;
61
};
62
63
static enum args_parse_type
64
cmd_if_shell_args_parse(__unused struct args *args, u_int idx,
65
    __unused char **cause)
66
0
{
67
0
  if (idx == 1 || idx == 2)
68
0
    return (ARGS_PARSE_COMMANDS_OR_STRING);
69
0
  return (ARGS_PARSE_STRING);
70
0
}
71
72
static enum cmd_retval
73
cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
74
0
{
75
0
  struct args     *args = cmd_get_args(self);
76
0
  struct cmd_find_state   *target = cmdq_get_target(item);
77
0
  struct cmd_if_shell_data  *cdata;
78
0
  struct cmdq_item    *new_item;
79
0
  char        *shellcmd;
80
0
  struct client     *tc = cmdq_get_target_client(item);
81
0
  struct session      *s = target->s;
82
0
  struct cmd_list     *cmdlist;
83
0
  u_int        count = args_count(args);
84
0
  int        wait = !args_has(args, 'b');
85
86
0
  shellcmd = format_single_from_target(item, args_string(args, 0));
87
0
  if (args_has(args, 'F')) {
88
0
    if (*shellcmd != '0' && *shellcmd != '\0')
89
0
      cmdlist = args_make_commands_now(self, item, 1, 0);
90
0
    else if (count == 3)
91
0
      cmdlist = args_make_commands_now(self, item, 2, 0);
92
0
    else {
93
0
      free(shellcmd);
94
0
      return (CMD_RETURN_NORMAL);
95
0
    }
96
0
    free(shellcmd);
97
0
    if (cmdlist == NULL)
98
0
      return (CMD_RETURN_ERROR);
99
0
    new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
100
0
    cmdq_insert_after(item, new_item);
101
0
    return (CMD_RETURN_NORMAL);
102
0
  }
103
104
0
  cdata = xcalloc(1, sizeof *cdata);
105
106
0
  cdata->cmd_if = args_make_commands_prepare(self, item, 1, NULL, wait,
107
0
      0);
108
0
  if (count == 3) {
109
0
    cdata->cmd_else = args_make_commands_prepare(self, item, 2,
110
0
        NULL, wait, 0);
111
0
  }
112
113
0
  if (wait) {
114
0
    cdata->client = cmdq_get_client(item);
115
0
    cdata->item = item;
116
0
  } else
117
0
    cdata->client = tc;
118
0
  if (cdata->client != NULL)
119
0
    cdata->client->references++;
120
121
0
  if (job_run(shellcmd, 0, NULL, NULL, s,
122
0
      server_client_get_cwd(cmdq_get_client(item), s), NULL,
123
0
      cmd_if_shell_callback, cmd_if_shell_free, cdata, 0, -1,
124
0
      -1) == NULL) {
125
0
    cmdq_error(item, "failed to run command: %s", shellcmd);
126
0
    free(shellcmd);
127
0
    free(cdata);
128
0
    return (CMD_RETURN_ERROR);
129
0
  }
130
0
  free(shellcmd);
131
132
0
  if (!wait)
133
0
    return (CMD_RETURN_NORMAL);
134
0
  return (CMD_RETURN_WAIT);
135
0
}
136
137
static void
138
cmd_if_shell_callback(struct job *job)
139
0
{
140
0
  struct cmd_if_shell_data  *cdata = job_get_data(job);
141
0
  struct client     *c = cdata->client;
142
0
  struct cmdq_item    *item = cdata->item, *new_item;
143
0
  struct args_command_state *state;
144
0
  struct cmd_list     *cmdlist;
145
0
  char        *error;
146
0
  int        status;
147
148
0
  status = job_get_status(job);
149
0
  if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
150
0
    state = cdata->cmd_else;
151
0
  else
152
0
    state = cdata->cmd_if;
153
0
  if (state == NULL)
154
0
    goto out;
155
156
0
  cmdlist = args_make_commands(state, 0, NULL, &error);
157
0
  if (cmdlist == NULL) {
158
0
    if (cdata->item == NULL) {
159
0
      *error = toupper((u_char)*error);
160
0
      status_message_set(c, -1, 1, 0, "%s", error);
161
0
    } else
162
0
      cmdq_error(cdata->item, "%s", error);
163
0
    free(error);
164
0
  } else if (item == NULL) {
165
0
    new_item = cmdq_get_command(cmdlist, NULL);
166
0
    cmdq_append(c, new_item);
167
0
  } else {
168
0
    new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
169
0
    cmdq_insert_after(item, new_item);
170
0
  }
171
172
0
out:
173
0
  if (cdata->item != NULL)
174
0
    cmdq_continue(cdata->item);
175
0
}
176
177
static void
178
cmd_if_shell_free(void *data)
179
0
{
180
0
  struct cmd_if_shell_data  *cdata = data;
181
182
0
  if (cdata->client != NULL)
183
0
    server_client_unref(cdata->client);
184
185
0
  if (cdata->cmd_else != NULL)
186
0
    args_make_commands_free(cdata->cmd_else);
187
0
  args_make_commands_free(cdata->cmd_if);
188
189
0
  free(cdata);
190
0
}