rizin/librz/main/rz-run.c
Giovanni 70fdd67278
Allow rizin tools to run as standalone binaries (#6011)
* Implement TOOL/ENVS/EXIT_STATUS for rz-test

* update readme
2026-03-11 16:24:23 +00:00

231 lines
6.9 KiB
C

// SPDX-FileCopyrightText: 2011-2020 pancake <pancake@nopcode.org>
// SPDX-License-Identifier: LGPL-3.0-only
#include <rz_util.h>
#include <rz_main.h>
#include <rz_socket.h>
#include <rz_util/rz_print.h>
#if __UNIX__
static void fwd(int sig) {
/* do nothing? send kill signal to remote process */
}
static void rz_run_tty(void) {
/* TODO: Implement in native code */
rz_sys_xsystem("tty");
close(1);
dup2(2, 1);
rz_sys_signal(SIGINT, fwd);
for (;;) {
sleep(1);
}
}
#endif
static void rz_run_help(int v) {
if (v == 0) {
printf(Color_CYAN "Usage: ");
printf(Color_RESET "rz-run [directives | script.rz] [-- program [args]]\n");
const char *options[] = {
// clang-format off
"-h", "", "Show this help",
"-l", "", "Show profile directives",
"-t", "", "Output template profile",
"-v", "", "Show version information",
"-w", "", "Wait for incoming terminal process",
"--", "program [args]", "Run program",
// clang-format on
};
rz_print_colored_help(options, RZ_ARRAY_SIZE(options), false);
}
if (v == 1) {
// clang-format off
printf(
"program=/bin/ls\n"
"arg1=/bin\n"
"# arg2=hello\n"
"# arg3=\"hello\\nworld\"\n"
"# arg4=:048490184058104849\n"
"# arg5=:!rz-gg -p n50 -d 10:0x8048123\n"
"# arg6=@arg.txt\n"
"# arg7=@300@ABCD # 300 chars filled with ABCD pattern\n"
"# system=rizin -\n"
"# daemon=false\n"
"# aslr=no\n"
"setenv=FOO=BAR\n"
"# unsetenv=FOO\n"
"# clearenv=true\n"
"# envfile=environ.txt\n"
"timeout=3\n"
"# timeoutsig=SIGTERM # or 15\n"
"# connect=localhost:8080\n"
"# listen=8080\n"
"# pty=false\n"
"# fork=true\n"
"# bits=32\n"
"# pid=0\n"
"# pidfile=/tmp/foo.pid\n"
"# #sleep=0\n"
"# #maxfd=0\n"
"# #execve=false\n"
"# #maxproc=0\n"
"# #maxstack=0\n"
"# #core=false\n"
"# #stdio=blah.txt\n"
"# #stderr=foo.txt\n"
"# stdout=foo.txt\n"
"# stdin=input.txt # or !program to redirect input from another program\n"
"# input=input.txt\n"
"# chdir=/\n"
"# chroot=/mnt/chroot\n"
"# libpath=$PWD:/tmp/lib\n"
"# rzpreload=yes\n"
"# preload=/lib/libfoo.so\n"
"# setuid=2000\n"
"# seteuid=2000\n"
"# setgid=2001\n"
"# setegid=2001\n"
"# nice=5\n"
""
);
// clang-format on
}
if (v == 2) {
// clang-format off
printf(Color_CYAN "Supported RzRun profile directives:\n"
Color_RESET
"arg[0-511] Set value for argument N passed to the program\n"
"aslr Enable or disable ASLR\n"
"bits Set 32 or 64 bit (if the architecture supports it)\n"
"chdir Change directory before executing the program\n"
"chroot Run the program in chroot. requires some previous setup\n"
"connect Connect stdin/stdout/stderr to a socket\n"
"core Set no limit the core file size\n"
"daemon Set to false by default, otherwise it will run the program in background, detached from the terminal\n"
"envfile Set a file with lines like `var=value` to be used as env\n"
"fork Used with the listen option, allow to spawn a different process for each connection. Ignored when debugging.\n"
"input Set string to be passed to the program via stdin\n"
"libpath Override path where the dynamic loader will look for shared libraries\n"
"listen Bound stdin/stdout/stderr to a listening socket\n"
"maxfd Set the maximum number of file descriptors\n"
"maxproc Set the maximum number of processes\n"
"maxstack Set the maximum size for the stack\n"
"nice Set the niceness level of the process\n"
"pid Set to true to print the PID of the process to stderr\n"
"pidfile Print the PID of the process to the specified file\n"
"preload Preload a library (not supported on Windows, only linux,osx,bsd)\n"
"program Path to program to be executed\n"
"pty Use a pty for connection over socket (with connect/listen)\n"
"runlib Path to the library to be executed\n"
"runlib.fcn Function name to call from runlib library\n"
"rzpreload Preload with librz, kill -USR1 to get an rizin shell or -USRZ to spawn a webserver in a thread\n"
"setegid Set effective process group id\n"
"setenv Set value for given environment variable (setenv=FOO=BAR)\n"
"seteuid Set effective process uid\n"
"setgid Set process group id\n"
"setuid Set process uid\n"
"sleep Sleep for the given amount of seconds\n"
"sterr Select file to replace stderr file descriptor\n"
"stdin Select file to read data from stdin\n"
"stdio Select io stream to redirect data from/to\n"
" Redirect input/output to the process created by the specified command prefixed by '!' (stdio=!cmd)\n"
"stdout Select file to replace stdout file descriptor\n"
"system Execute the given command\n"
"timeout Set a timeout\n"
"timeoutsig Signal to use when killing the child because the timeout happens\n"
"unsetenv Unset one environment variable\n"
"");
// clang-format off
}
}
static RzRunProfile *rz_run_new_from_cmdline(int start, int argc, const char **argv) {
bool no_more_directives = false;
int directive_index = 0;
RzRunProfile *p = rz_run_new(NULL);
if (!p) {
RZ_LOG_ERROR("Failed to create new RzRunProfile\n");
return NULL;
}
for (int i = start; i < argc; i++) {
if (!strcmp(argv[i], "--")) {
no_more_directives = true;
continue;
}
if (no_more_directives) {
const char *word = argv[i];
char *line = directive_index
? rz_str_newf("arg%d=%s", directive_index, word)
: rz_str_newf("program=%s", word);
rz_run_parseline(p, line);
directive_index++;
free(line);
} else if (!rz_run_parseline(p, argv[i])) {
goto fail;
}
}
return p;
fail:
rz_run_free(p);
return NULL;
}
RZ_API int rz_main_rz_run(int argc, const char **argv) {
int ret = 0;
RzRunProfile *p = NULL;
if (argc == 1 || !strcmp(argv[1], "-h")) {
rz_run_help(0);
ret = 1;
goto finish;
}
if (!strcmp(argv[1], "-v")) {
RzPath *sys_path = rz_path_new();
if(!sys_path){
ret = 1;
goto finish;
}
ret = rz_main_version_print(sys_path, "rz-run");
rz_path_free(sys_path);
goto finish;
}
if (!strcmp(argv[1], "-t")) {
rz_run_help(1);
ret = 0;
goto finish;
}
if (!strcmp(argv[1], "-l")) {
rz_run_help(2);
ret = 0;
goto finish;
}
const char *file = argc > 1 ? argv[1] : "";
if (RZ_STR_ISNOTEMPTY(file) && !strcmp(file, "-w")) {
#if __UNIX__
rz_run_tty();
return 0;
#else
RZ_LOG_ERROR("Not supported\n");
return 1;
#endif
}
if (RZ_STR_ISNOTEMPTY(file) && !strchr(file, '=')) {
p = rz_run_new(file);
} else {
p = rz_run_new_from_cmdline(*file ? 1 : 2, argc, argv);
}
if (!p) {
return 1;
}
ret = rz_run_config_env(p);
if (ret) {
printf("error while configuring the environment.\n");
rz_run_free(p);
return 1;
}
ret = rz_run_start(p);
finish:
rz_run_free(p);
return ret;
}