rizin/librz/socket/rzpipe.c
Riccardo Schirone 53bf5c497f SPDX Copyright text for all files based on history
- Add LICENSES directory
- Download additional licenses used
- Add .reuse directory
- Add doc about SPDX/reuse

Co-authored-by: Florian Märkl <info@florianmaerkl.de>
2021-03-05 19:39:15 +08:00

354 lines
7.5 KiB
C

// SPDX-FileCopyrightText: 2015-2020 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
/*
Usage Example:
#include <rz_core.h>
int main() {
RzCoreBind rcb;
RzCore *core = rz_core_new ();
rz_core_bind (core, &rcb);
rzpipe_open_corebind (&rcb);
char *clippy = rzpipe_cmd ("?E hello");
eprintf ("%s\n", clippy);
free (clippy);
rzpipe_close (rzpipe);
rz_core_free (core);
}
*/
#include <rz_util.h>
#include <rz_lib.h>
#include <rz_socket.h>
#define RZP_PID(x) (((RzPipe *)(x)->data)->pid)
#define RZP_INPUT(x) (((RzPipe *)(x)->data)->input[0])
#define RZP_OUTPUT(x) (((RzPipe *)(x)->data)->output[1])
#if !__WINDOWS__
static void env(const char *s, int f) {
char *a = rz_str_newf("%d", f);
rz_sys_setenv(s, a);
free(a);
}
#endif
RZ_API int rzpipe_write(RzPipe *rzpipe, const char *str) {
char *cmd;
int ret, len;
if (!rzpipe || !str) {
return -1;
}
len = strlen(str) + 2; /* include \n\x00 */
cmd = malloc(len + 2);
if (!cmd) {
return 0;
}
memcpy(cmd, str, len - 1);
strcpy(cmd + len - 2, "\n");
#if __WINDOWS__
DWORD dwWritten = -1;
WriteFile(rzpipe->pipe, cmd, len, &dwWritten, NULL);
ret = (dwWritten == len);
#else
ret = (write(rzpipe->input[1], cmd, len) == len);
#endif
free(cmd);
return ret;
}
/* TODO: add timeout here ? */
RZ_API char *rzpipe_read(RzPipe *rzpipe) {
int bufsz = 0;
char *buf = NULL;
if (!rzpipe) {
return NULL;
}
bufsz = 4096;
buf = calloc(1, bufsz);
if (!buf) {
return NULL;
}
#if __WINDOWS__
BOOL bSuccess = FALSE;
DWORD dwRead = 0;
// TODO: handle > 4096 buffers here
bSuccess = ReadFile(rzpipe->pipe, buf, bufsz, &dwRead, NULL);
if (!bSuccess || !buf[0]) {
return NULL;
}
if (dwRead > 0) {
buf[dwRead] = 0;
}
buf[bufsz - 1] = 0;
#else
char *newbuf;
int i, rv;
for (i = 0; i < bufsz; i++) {
rv = read(rzpipe->output[0], buf + i, 1);
if (i + 2 >= bufsz) {
bufsz += 4096;
newbuf = realloc(buf, bufsz);
if (!newbuf) {
RZ_FREE(buf);
break;
}
buf = newbuf;
}
if (rv != 1 || !buf[i]) {
break;
}
}
if (buf) {
int zpos = (i < bufsz) ? i : i - 1;
buf[zpos] = 0;
}
#endif
return buf;
}
RZ_API int rzpipe_close(RzPipe *rzpipe) {
if (!rzpipe) {
return 0;
}
/*
if (rzpipe->coreb.core && !rzpipe->coreb.puts) {
void (*rfre)(void *c) = rz_lib_dl_sym (librz, "rz_core_free");
if (rfre) {
rfre (rzpipe->coreb.core);
}
}
*/
#if __WINDOWS__
if (rzpipe->pipe) {
CloseHandle(rzpipe->pipe);
rzpipe->pipe = NULL;
}
#else
if (rzpipe->input[0] != -1) {
rz_sys_pipe_close(rzpipe->input[0]);
rzpipe->input[0] = -1;
}
if (rzpipe->input[1] != -1) {
rz_sys_pipe_close(rzpipe->input[1]);
rzpipe->input[1] = -1;
}
if (rzpipe->output[0] != -1) {
rz_sys_pipe_close(rzpipe->output[0]);
rzpipe->output[0] = -1;
}
if (rzpipe->output[1] != -1) {
rz_sys_pipe_close(rzpipe->output[1]);
rzpipe->output[1] = -1;
}
if (rzpipe->child != -1) {
kill(rzpipe->child, SIGTERM);
waitpid(rzpipe->child, NULL, 0);
rzpipe->child = -1;
}
#endif
free(rzpipe);
return 0;
}
#if __WINDOWS__
static int w32_createPipe(RzPipe *rzpipe, const char *cmd) {
CHAR buf[1024];
rzpipe->pipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\RZ_PIPE_IN"),
PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
sizeof(buf), sizeof(buf), 0, NULL);
if (rz_sys_create_child_proc_w32(cmd, NULL, NULL, NULL)) {
if (ConnectNamedPipe(rzpipe->pipe, NULL)) {
return true;
}
}
return false;
}
#endif
static RzPipe *rzp_open_spawn(RzPipe *rzp, const char *cmd) {
rz_return_val_if_fail(rzp, NULL);
#if __UNIX__ || defined(__CYGWIN__)
char *out = rz_sys_getenv("RZ_PIPE_IN");
char *in = rz_sys_getenv("RZ_PIPE_OUT");
int done = false;
if (in && out) {
int i_in = atoi(in);
int i_out = atoi(out);
if (i_in >= 0 && i_out >= 0) {
rzp->input[0] = rzp->input[1] = i_in;
rzp->output[0] = rzp->output[1] = i_out;
done = true;
}
}
if (!done) {
eprintf("Cannot find RZ_PIPE_IN or RZ_PIPE_OUT environment\n");
RZ_FREE(rzp);
}
free(in);
free(out);
return rzp;
#else
eprintf("rzpipe_open(NULL) not supported on windows\n");
return NULL;
#endif
}
static RzPipe *rzpipe_new(void) {
RzPipe *rzpipe = RZ_NEW0(RzPipe);
if (rzpipe) {
#if __UNIX__
rzpipe->input[0] = rzpipe->input[1] = -1;
rzpipe->output[0] = rzpipe->output[1] = -1;
#endif
rzpipe->child = -1;
}
return rzpipe;
}
RZ_API RzPipe *rzpipe_open_corebind(RzCoreBind *coreb) {
RzPipe *rzpipe = rzpipe_new();
if (rzpipe) {
memcpy(&rzpipe->coreb, coreb, sizeof(RzCoreBind));
}
return rzpipe;
}
RZ_API RzPipe *rzpipe_open_dl(const char *libr_path) {
void *librz = rz_lib_dl_open(libr_path);
void *(*rnew)() = rz_lib_dl_sym(librz, "rz_core_new");
char *(*rcmd)(void *c, const char *cmd) = rz_lib_dl_sym(librz, "rz_core_cmd_str");
if (rnew && rcmd) {
RzPipe *rzpipe = rzpipe_new();
if (rzpipe) {
rzpipe->coreb.core = rnew();
rzpipe->coreb.cmdstr = rcmd;
// rzpipe->coreb.free = rfre;
}
return rzpipe;
}
eprintf("Cannot resolve rz_core_cmd, rz_core_cmd_str, rz_core_free\n");
return NULL;
}
RZ_API RzPipe *rzpipe_open(const char *cmd) {
RzPipe *rzp = rzpipe_new();
if (!rzp) {
return NULL;
}
if (RZ_STR_ISEMPTY(cmd)) {
rzp->child = -1;
return rzp_open_spawn(rzp, cmd);
}
#if __WINDOWS__
w32_createPipe(rzp, cmd);
rzp->child = (int)(rzp->pipe);
#else
int r = rz_sys_pipe(rzp->input, false);
if (r != 0) {
eprintf("pipe failed on input\n");
rzpipe_close(rzp);
return NULL;
}
r = rz_sys_pipe(rzp->output, false);
if (r != 0) {
eprintf("pipe failed on output\n");
rzpipe_close(rzp);
return NULL;
}
rzp->child = rz_sys_fork();
if (rzp->child == -1) {
rzpipe_close(rzp);
return NULL;
}
env("RZ_PIPE_IN", rzp->input[0]);
env("RZ_PIPE_OUT", rzp->output[1]);
if (rzp->child) {
signed char ch = -1;
// eprintf ("[+] rzpipeipe child is %d\n", rzpipe->child);
if (read(rzp->output[0], &ch, 1) != 1) {
eprintf("Failed to read 1 byte\n");
rzpipe_close(rzp);
return NULL;
}
if (ch == -1) {
eprintf("[+] rzpipe link error.\n");
rzpipe_close(rzp);
return NULL;
}
// Close parent's end of pipes
rz_sys_pipe_close(rzp->input[0]);
rz_sys_pipe_close(rzp->output[1]);
rzp->input[0] = -1;
rzp->output[1] = -1;
} else {
int rc = 0;
if (cmd && *cmd) {
close(0);
close(1);
dup2(rzp->input[0], 0);
dup2(rzp->output[1], 1);
rz_sys_pipe_close(rzp->input[1]);
rz_sys_pipe_close(rzp->output[0]);
rzp->input[1] = -1;
rzp->output[0] = -1;
rc = rz_sys_system(cmd);
if (rc != 0) {
eprintf("return code %d for %s\n", rc, cmd);
}
// trigger the blocking read
rz_xwrite(1, "\xff", 1);
rz_sys_pipe_close(rzp->output[1]);
close(0);
close(1);
}
rzp->child = -1;
rzpipe_close(rzp);
exit(rc);
return NULL;
}
#endif
return rzp;
}
RZ_API char *rzpipe_cmd(RzPipe *rzp, const char *str) {
rz_return_val_if_fail(rzp && str, NULL);
if (!*str || !rzpipe_write(rzp, str)) {
perror("rzpipe_write");
return NULL;
}
return rzpipe_read(rzp);
}
RZ_API char *rzpipe_cmdf(RzPipe *rzp, const char *fmt, ...) {
int ret, ret2;
char *p, string[1024];
va_list ap, ap2;
va_start(ap, fmt);
va_start(ap2, fmt);
ret = vsnprintf(string, sizeof(string) - 1, fmt, ap);
if (ret < 1 || ret >= sizeof(string)) {
p = malloc(ret + 2);
if (!p) {
va_end(ap2);
va_end(ap);
return NULL;
}
ret2 = vsnprintf(p, ret + 1, fmt, ap2);
if (ret2 < 1 || ret2 > ret + 1) {
free(p);
va_end(ap2);
va_end(ap);
return NULL;
}
fmt = rzpipe_cmd(rzp, p);
free(p);
} else {
fmt = rzpipe_cmd(rzp, string);
}
va_end(ap2);
va_end(ap);
return (char *)fmt;
}