Skip to content

Commit

Permalink
Fix #22588 - Support multiple redirections in the same line ##shell
Browse files Browse the repository at this point in the history
* allowed: x > a 2> b
* forbidden: x > a > b
* broken: x>a
* todo: add tests and support nesting and multiple redirects
  • Loading branch information
trufae authored Feb 13, 2024
1 parent e394274 commit be75b2d
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 50 deletions.
11 changes: 5 additions & 6 deletions libr/cons/cons.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* radare2 - LGPL - Copyright 2008-2023 - pancake, Jody Frankowski */
/* radare2 - LGPL - Copyright 2008-2024 - pancake, Jody Frankowski */

#include <r_cons.h>
#include <r_util.h>
Expand All @@ -15,7 +15,7 @@ static R_TH_LOCAL RCons *r_cons_instance = NULL;
static R_TH_LOCAL ut64 prev = 0LL; //r_time_now_mono ();
static R_TH_LOCAL RStrBuf *echodata = NULL; // TODO: move into RConsInstance? maybe nope
#define I (r_cons_instance)
#define C (getctx())
#define C (getctx ())

static inline void cons_input_state_init(InputState *state) {
state->readbuffer = NULL;
Expand Down Expand Up @@ -692,8 +692,7 @@ R_API RCons *r_cons_new(void) {
I->teefile = NULL;
I->fix_columns = 0;
I->fix_rows = 0;
I->backup_fd = -1;
I->backup_fdn = -1;
RVecFdPairs_init (&I->fds);
I->mouse_event = 0;
I->force_rows = 0;
I->force_columns = 0;
Expand Down Expand Up @@ -771,12 +770,12 @@ R_API RCons *r_cons_free(void) {
R_FREE (C->lastOutput);
C->lastLength = 0;
R_FREE (I->pager);
RVecFdPairs_fini (&I->fds);
return NULL;
}

#define MOAR (4096 * 8)
static bool palloc(int moar) {
void *temp;
if (moar <= 0) {
return false;
}
Expand All @@ -785,7 +784,7 @@ static bool palloc(int moar) {
return false;
}
size_t new_sz = moar + MOAR;
temp = calloc (1, new_sz);
void *temp = calloc (1, new_sz);
if (temp) {
C->buffer_sz = new_sz;
C->buffer = temp;
Expand Down
129 changes: 104 additions & 25 deletions libr/cons/cpipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,68 +7,147 @@
#define O_BINARY 0
#endif

#define I (r_cons_singleton ())
#define HONOR_LAST_REDIRECT 0
#define USE_HACK 0

static bool __dupDescriptor(int fd, int fdn) {
#if 0
static bool mydup(const int fd, const int fdn) {
if (fd == fdn) {
return false;
}
#if __wasi__
return false;
#elif R2__WINDOWS__
I->backup_fd = 2002 - (fd - 2); // windows xp has 2048 as limit fd
return _dup2 (fdn, I->backup_fd) != -1;
#else
I->backup_fd = sysconf (_SC_OPEN_MAX) - (fd - 2); // portable getdtablesize()
if (I->backup_fd < 2) {
I->backup_fd = 2002 - (fd - 2); // fallback
# if R2__WINDOWS__
int newfd = -1;
# else
int newfd = sysconf (_SC_OPEN_MAX) - (fd - 2); // portable getdtablesize()
# endif
if (newfd < 2) {
newfd = 2002 - (fd - 2); // fallback
}
return dup2 (fdn, I->backup_fd) != -1;
return dup2 (fd, newfd) != -1;
#endif
}
#endif

R_API int r_cons_pipe_open(const char *file, int fdn, int append) {
R_API int r_cons_pipe_open(const char *file, int fd_src, int append) {
#if __wasi__
return -1;
#else
if (fdn < 1) {
if (fd_src < 1) {
return -1;
}
RCons *ci = r_cons_singleton ();
RConsFdPair *pair;
#if !HONOR_LAST_REDIRECT
// prevent redirecting the same fd twice in the same line
R_VEC_FOREACH (&ci->fds, pair) {
if (fd_src == pair->fd_src) {
R_LOG_WARN ("cannot redirect the same fd twice");
// do not permit redirecting output to more than one file
return -1;
}
}
#endif
char *targetFile = (r_str_startswith (file, "~/") || r_str_startswith (file, "~\\"))
? r_file_home (file + 2): strdup (file);
const int fd_flags = O_BINARY | O_RDWR | O_CREAT | (append? O_APPEND: O_TRUNC);
int fd = r_sandbox_open (targetFile, fd_flags, 0644);
if (fd == -1) {
int fd_new = r_sandbox_open (targetFile, fd_flags, 0644);
if (fd_new < 0) {
R_LOG_ERROR ("ConsPipe cannot open file '%s'", file);
free (targetFile);
return -1;
}
if (I->backup_fd != -1) {
close (I->backup_fd);
// already set in __dupDescriptor // backup_fd = -1;
R_LOG_DEBUG ("open (%s) = %d", targetFile, fd_new);
int fd_bak = fd_src + 32; // XXX wrong assumptions
bool is_dual = false;
#if HONOR_LAST_REDIRECT
R_VEC_FOREACH (&ci->fds, pair) {
if (fd_src == pair->fd_src) {
// do not permit redirecting output to more than one file
#if USE_HACK
int fd_new2 = pair->fd_new + 64;
dup2 (pair->fd_bak, fd_new2);
#else
int fd_new2 = dup (pair->fd_bak);
#endif
fd_bak = fd_new2;
break;
}
}
I->backup_fdn = fdn;
if (!__dupDescriptor (fd, fdn)) {
#endif
// int res = dup2 (fdn, rfd);
int res;
if (!is_dual) {
#if USE_HACK
res = dup2 (fd_src, fd_bak);
#else
res = fd_bak = dup (fd_src);
#endif
R_LOG_DEBUG ("dup2 %d %d = %d", fd_src, fd_bak, res);
close (fd_src);
res = dup2 (fd_new, fd_src);
}
R_LOG_DEBUG ("dup2 %d %d = %d", fd_new, fd_src, res);
RConsFdPair newPair = {
.fd_src = fd_src, // original source file descriptor
.fd_new = fd_new, // new file descriptor created to write into the file
.fd_bak = fd_bak, // restored file descriptor to be used to recover the original fd into fdn
};
// eprintf (" %d -> %d\n", fd_src, fd_new);
RVecFdPairs_push_back (&ci->fds, &newPair);
#if 0
if (!mydup (fd, fdn)) {
R_LOG_ERROR ("Cannot dup stdout to %d", fdn);
free (targetFile);
return -1;
}
close (fdn);
dup2 (fd, fdn);
#endif
// close (fdn);
// res = dup2 (fd, fdn);
// eprintf ("dup2 %d %d = %d\n", fd, fdn, res);
free (targetFile);
return fd;
return fd_new;
#endif
}

R_API void r_cons_pipe_close(int fd) {
#if !__wasi__
r_cons_pipe_close_all ();
#if 0
if (fd != -1) {
close (fd);
if (I->backup_fd != -1) {
dup2 (I->backup_fd, I->backup_fdn);
close (I->backup_fd);
I->backup_fd = -1;
RCons *ci = r_cons_singleton ();
if (ci->backup_fdn[fd] != -1) {
dup2 (ci->backup_fd, ci->backup_fdn[fd]);
close (ci->backup_fd);
ci->backup_fd = -1;
ci->backup_fdn[fd] = -1;
}
}
#endif
#endif
}

R_API void r_cons_pipe_close_all(void) {
#if !__wasi__
RCons *ci = r_cons_singleton ();
RConsFdPair *pair;
int res;
R_VEC_FOREACH_PREV (&ci->fds, pair) {
res = dup2 (pair->fd_bak, pair->fd_src);
R_LOG_DEBUG ("dup2 %d -> %d = %d", pair->fd_bak, pair->fd_src, res);
res = close (pair->fd_bak);
R_LOG_DEBUG ("close (%d)=%d", pair->fd_bak, res);
#if 0
res = dup2 (pair->fd_new, pair->fd_src);
eprintf ("dup %d -> %d\n", pair->fd_new, pair->fd_src);
#endif
res = close (pair->fd_new);
R_LOG_DEBUG ("close (%d)=%d", pair->fd_new, res);
}
RVecFdPairs_fini (&ci->fds);
RVecFdPairs_init (&ci->fds);
#endif
}
73 changes: 56 additions & 17 deletions libr/core/cmd.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* radare - LGPL - Copyright 2009-2023 - nibble, pancake */
/* radare - LGPL - Copyright 2009-2024 - nibble, pancake */

#define INTERACTIVE_MAX_REP 1024

Expand Down Expand Up @@ -875,7 +875,7 @@ static int cmd_alias(void *data, const char *input) {
free (n);
}
} else if (*def == '$') {
char *s = strdup (def+1);
char *s = strdup (def + 1);
int l = r_str_unescape (s);
r_cmd_alias_set_raw (core->rcmd, buf, (ut8 *)s, l);
free (s);
Expand Down Expand Up @@ -4331,6 +4331,8 @@ static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek
ptr = NULL;
}
}
int fdn = 1;
char *next_redirect = NULL;
if (ptr) {
if (ptr > cmd) {
char *ch = ptr - 1;
Expand All @@ -4344,21 +4346,27 @@ static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek
r_list_free (tmpenvs);
return true;
}
int fdn = 1;
bool pipecolor = r_config_get_b (core->config, "scr.color.pipe");
int use_editor = false;
bool use_editor = false;
int ocolor = r_config_get_i (core->config, "scr.color");
*ptr = '\0';
r_cons_set_interactive (false);
repeat:;
str = ptr + 1 + (ptr[1] == '>');
r_str_trim (str);
if (!*str) {
R_LOG_ERROR ("No output?");
goto next2;
}
fdn = 1;
/* r_cons_flush() handles interactive output (to the terminal)
* differently (e.g. asking about too long output). This conflicts
* with piping to a file. Disable it while piping. */
if (ptr > (cmd + 1) && IS_WHITECHAR (ptr[-2])) {
// note that 'x>a' is not working .. but 'x > a' or 'x >a' is valid
bool redirect_check = (ptr > cmd && (!ptr[-1] || !ptr[-2] || IS_WHITECHAR (ptr[-2])));
if (redirect_check) { // R2R db/cmd/cmd_macros
R_LOG_DEBUG ("FD FROM (%s)", ptr - 1 );
// eprintf ("COMPUTE FD (%s) (ptr=%s)\n", ptr -1, ptr-1);
char *fdnum = ptr - 1;
if (*fdnum == 'H') { // "H>"
scr_html = r_cons_context ()->is_html;
Expand All @@ -4372,19 +4380,42 @@ static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek
*fdnum = 0;
}
}
r_cons_set_interactive (false);
R_LOG_DEBUG ("FD %d", fdn);
if (!strcmp (str, "-")) {
use_editor = true;
str = r_file_temp ("dumpedit");
r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
}

char *nextgt = strchr (r_str_trim_head_ro (ptr + 1), '>');
if (nextgt) {
R_LOG_DEBUG ("CHUM!");
char *back = ptr + 1;
while (nextgt > back) {
if (!isdigit (*nextgt) && *nextgt != 'H') {
break;
}
nextgt--;
}
next_redirect = nextgt;
while (nextgt > back) {
if (*nextgt == ' ') {
*nextgt = 0;
break;
}
nextgt--;
}
} else {
next_redirect = NULL;
}
// eprintf ("---> (%s)\n", ptr + 1);
// eprintf ("next (%s)\n", next_redirect);
const bool appendResult = (ptr[1] == '>');
if (*str == '$' && !str[1]) {
R_LOG_ERROR ("No alias name given");
} else if (*str == '$') {
// pipe to alias variable
// register output of command as an alias

r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
RBuffer *cmd_out = r_core_cmd_tobuf (core, cmd);
int alias_len;
Expand All @@ -4406,22 +4437,28 @@ static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek
} else if (fdn > 0) {
// pipe to file (or append)
pipefd = r_cons_pipe_open (str, fdn, appendResult);
if (pipefd != -1) {
if (!pipecolor) {
r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
}
ret = r_core_cmd_subst (core, cmd);
r_cons_flush ();
r_cons_pipe_close (pipefd);
if (pipefd == -1) {
// R_LOG_ERROR ("Cannot open pipe with fd %d", fdn);
// goto errorout;
}
if (next_redirect) {
ptr = next_redirect;
*next_redirect = ' ';
next_redirect = NULL;
goto repeat;
}
if (!pipecolor) {
r_config_set_i (core->config, "scr.color", COLOR_MODE_DISABLED);
}
ret = r_core_cmd_subst (core, cmd);
r_cons_flush ();
}
r_cons_set_last_interactive ();
if (!pipecolor) {
r_config_set_i (core->config, "scr.color", ocolor);
}
if (use_editor) {
const char *editor = r_config_get (core->config, "cfg.editor");
if (editor && *editor) {
if (R_STR_ISNOTEMPTY (editor)) {
r_sys_cmdf ("%s '%s'", editor, str);
r_file_rm (str);
} else {
Expand All @@ -4438,6 +4475,8 @@ static int r_core_cmd_subst_i(RCore *core, char *cmd, char *colon, bool *tmpseek
}
core->cons->context->use_tts = false;
r_list_free (tmpenvs);
r_cons_pipe_close_all ();
r_cons_set_last_interactive ();
return ret;
}
escape_redir:
Expand Down Expand Up @@ -6280,7 +6319,7 @@ R_API char *r_core_cmd_str_pipe(RCore *core, const char *cmd) {
r_cons_reset ();
r_sandbox_disable (true);
if (r_file_mkstemp ("cmd", &tmp) != -1) {
int pipefd = r_cons_pipe_open (tmp, 1, 0);
int pipefd = r_cons_pipe_open (tmp, 1, false);
if (pipefd == -1) {
r_file_rm (tmp);
r_sandbox_disable (false);
Expand Down
Loading

0 comments on commit be75b2d

Please sign in to comment.