Coverage Report

Created: 2026-10-17 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/cmd-confirm-before.c
Line
Count
Source
1
/* $OpenBSD: cmd-confirm-before.c,v 1.62 2026/10/09 13:12:14 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <ctype.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "tmux.h"
26
27
/*
28
 * Asks for confirmation before executing a command.
29
 */
30
31
static enum args_parse_type cmd_confirm_before_args_parse(struct args *,
32
            u_int, char **);
33
static enum cmd_retval    cmd_confirm_before_exec(struct cmd *,
34
            struct cmdq_item *);
35
36
static enum prompt_result cmd_confirm_before_callback(struct client *, void *,
37
        const char *, enum prompt_key_result);
38
static void cmd_confirm_before_free(void *);
39
40
const struct cmd_entry cmd_confirm_before_entry = {
41
  .name = "confirm-before",
42
  .description = "Ask for confirmation before a command.",
43
  .alias = "confirm",
44
45
  .args = { "bc:p:t:y", 1, 1, cmd_confirm_before_args_parse },
46
  .usage = "[-by] [-c confirm-key] [-p prompt] " CMD_TARGET_CLIENT_USAGE
47
     " command",
48
49
  .flags = CMD_CLIENT_TFLAG,
50
  .exec = cmd_confirm_before_exec
51
};
52
53
struct cmd_confirm_before_data {
54
  struct cmdq_item  *item;
55
  struct cmd_list   *cmdlist;
56
  u_char       confirm_key;
57
  int      default_yes;
58
};
59
60
static enum args_parse_type
61
cmd_confirm_before_args_parse(__unused struct args *args, __unused u_int idx,
62
    __unused char **cause)
63
0
{
64
0
  return (ARGS_PARSE_COMMANDS_OR_STRING);
65
0
}
66
67
static enum cmd_retval
68
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
69
0
{
70
0
  struct args     *args = cmd_get_args(self);
71
0
  struct cmd_confirm_before_data  *cdata;
72
0
  struct client     *tc = cmdq_get_target_client(item);
73
0
  struct cmd_find_state   *target = cmdq_get_target(item);
74
0
  char        *new_prompt;
75
0
  const char      *confirm_key, *prompt, *cmd;
76
0
  int        wait = !args_has(args, 'b');
77
78
0
  cdata = xcalloc(1, sizeof *cdata);
79
0
  cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
80
0
  if (cdata->cmdlist == NULL) {
81
0
    free(cdata);
82
0
    return (CMD_RETURN_ERROR);
83
0
  }
84
85
0
  if (wait)
86
0
    cdata->item = item;
87
88
0
  cdata->default_yes = args_has(args, 'y');
89
0
  if ((confirm_key = args_get(args, 'c')) != NULL) {
90
0
    if (confirm_key[1] == '\0' &&
91
0
        confirm_key[0] > 31 &&
92
0
        confirm_key[0] < 127)
93
0
      cdata->confirm_key = confirm_key[0];
94
0
    else {
95
0
      cmdq_error(item, "invalid confirm key");
96
0
      cmd_list_free(cdata->cmdlist);
97
0
      free(cdata);
98
0
      return (CMD_RETURN_ERROR);
99
0
    }
100
0
  }
101
0
  else
102
0
    cdata->confirm_key = 'y';
103
104
0
  if ((prompt = args_get(args, 'p')) != NULL)
105
0
    xasprintf(&new_prompt, "%s ", prompt);
106
0
  else {
107
0
    cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name;
108
0
    xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd,
109
0
        cdata->confirm_key);
110
0
  }
111
112
0
  status_prompt_set(tc, target, new_prompt, NULL,
113
0
      cmd_confirm_before_callback, cmd_confirm_before_free, cdata,
114
0
      PROMPT_SINGLE, PROMPT_TYPE_COMMAND);
115
0
  free(new_prompt);
116
117
0
  if (!wait)
118
0
    return (CMD_RETURN_NORMAL);
119
0
  return (CMD_RETURN_WAIT);
120
0
}
121
122
static enum prompt_result
123
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
124
    __unused enum prompt_key_result key)
125
0
{
126
0
  struct cmd_confirm_before_data  *cdata = data;
127
0
  struct cmdq_item    *item = cdata->item, *new_item;
128
0
  int        retcode = 1;
129
130
0
  if (c->flags & CLIENT_DEAD)
131
0
    goto out;
132
133
0
  if (s == NULL)
134
0
    goto out;
135
0
  if (s[0] != cdata->confirm_key && (s[0] != '\r' || !cdata->default_yes))
136
0
    goto out;
137
0
  retcode = 0;
138
139
0
  if (item == NULL) {
140
0
    new_item = cmdq_get_command(cdata->cmdlist, NULL);
141
0
    cmdq_append(c, new_item);
142
0
  } else {
143
0
    new_item = cmdq_get_command(cdata->cmdlist,
144
0
        cmdq_get_state(item));
145
0
    cmdq_insert_after(item, new_item);
146
0
  }
147
148
0
out:
149
0
  if (item != NULL) {
150
0
    if (cmdq_get_client(item) != NULL &&
151
0
        cmdq_get_client(item)->session == NULL)
152
0
      cmdq_get_client(item)->retval = retcode;
153
0
    cmdq_continue(item);
154
0
  }
155
0
  return (PROMPT_CLOSE);
156
0
}
157
158
static void
159
cmd_confirm_before_free(void *data)
160
0
{
161
0
  struct cmd_confirm_before_data  *cdata = data;
162
163
0
  cmd_list_free(cdata->cmdlist);
164
0
  free(cdata);
165
0
}