From a5297b57c242ff7fbe36d8b065ee0276783d5599 Mon Sep 17 00:00:00 2001 From: Ahmed_Hany Date: Thu, 15 Feb 2024 19:54:12 +0200 Subject: [PATCH] Add help and colors for `rz-run -h` (#4225) (#4237) * `-l` flag for listing profile options * `-d` for ouputing a base profile template. * Updated relevant manpage. --- binrz/man/rz-run.1 | 24 ++++--- librz/include/rz_socket.h | 1 - librz/main/rz-run.c | 145 +++++++++++++++++++++++++++++++++++++- librz/socket/run.c | 48 ------------- 4 files changed, 157 insertions(+), 61 deletions(-) diff --git a/binrz/man/rz-run.1 b/binrz/man/rz-run.1 index f827ff11968..03d6069f216 100644 --- a/binrz/man/rz-run.1 +++ b/binrz/man/rz-run.1 @@ -13,7 +13,13 @@ This command is part of the Rizin project. .Pp This program is used as a launcher for running programs with different environment, arguments, permissions, directories and overridden default filedescriptors. .Pp -rz-run -t will show the terminal name and wait for a connection from another process. try rz-run stdio= program=/bin/sh +rz-run -l lists all the supported profile options. +.Pp +.Pp +rz-run -t outputs a base template profile. Try rz-run -d > profile.rz +.Pp +.Pp +rz-run -w shows the terminal name and wait for a connection from another process. Try rz-run stdio= program=/bin/sh .Pp The program just accepts a single argument which is the filename of the configuration file to run the program. .Pp @@ -22,7 +28,7 @@ It is useful when you have to run a program using long arguments or pass long da .Pp The rrz (rz-run) configuration file accepts the following directives, described as key=value entries and comments defined as lines starting with '#'. .Bl -tag -width Fl -.It Ar arg[0-N] +.It Ar arg[0-511] Set value for argument N passed to the program .It Ar aslr Enable or disable ASLR @@ -32,8 +38,6 @@ Set 32 or 64 bit (if the architecture supports it) Change directory before executing the program .It Ar chroot Run the program in chroot. requires some previous setup -.It Ar clearenv -Unset the whole environment .It Ar core Set no limit the core file size .It Ar connect @@ -68,16 +72,12 @@ Path to program to be executed Set to true to print the PID of the process to stderr .It Ar pidfile Print the PID of the process to the specified file -.It Ar execve -Use execve instead of posix_spawn (osx tricks) .It Ar runlib Path to the library to be executed .It Ar runlib.fcn Function name to call from runlib library .It Ar rzpreload Preload with librz, kill -USR1 to get an rizin shell or -USRZ to spawn a webserver in a thread -.It Ar rzpreweb -Run the webserver in a thread just at starting the rzpreload .It Ar setenv Set value for given environment variable .It Ar setegid @@ -90,10 +90,16 @@ Set process group id Set process uid .It Ar sleep Sleep for the given amount of seconds +.It Ar stdio=value +Set io streams (stdin, stdout, stderr) to a value +.It Ar stdio=!cmd +Redirect input/output to the process created by the specified command .It Ar stdin -Select file to read data from stdin +Set stdin, stdout, and stderr streams to the specified value .It Ar stdout Select file to replace stdout file descriptor +.It Ar stderr +Select file to replace stderr file descriptor .It Ar system Execute the given command .It Ar timeout diff --git a/librz/include/rz_socket.h b/librz/include/rz_socket.h index 4439ff3bebc..1f77f22b7ac 100644 --- a/librz/include/rz_socket.h +++ b/librz/include/rz_socket.h @@ -275,7 +275,6 @@ RZ_API RzRunProfile *rz_run_new(const char *str); RZ_API bool rz_run_parse(RzRunProfile *pf, const char *profile); RZ_API void rz_run_free(RzRunProfile *r); RZ_API bool rz_run_parseline(RzRunProfile *p, const char *b); -RZ_API const char *rz_run_help(void); RZ_API int rz_run_config_env(RzRunProfile *p); RZ_API int rz_run_start(RzRunProfile *p); RZ_API void rz_run_reset(RzRunProfile *p); diff --git a/librz/main/rz-run.c b/librz/main/rz-run.c index 0b7af55a51a..908e4baf415 100644 --- a/librz/main/rz-run.c +++ b/librz/main/rz-run.c @@ -4,6 +4,7 @@ #include #include #include +#include #if __UNIX__ static void fwd(int sig) { @@ -22,19 +23,157 @@ static void rz_run_tty(void) { } #endif +static void rz_run_help(int v) { + if (v == 0) { + printf(Color_CYAN "Usage: "); + printf(Color_RESET "[directives] [script.rz] [--] [program] [args]\n"); + const char *options[] = { + // clang-format off + "-h", "", "Show this help", + "-l", "", "Show profile options", + "-t", "", "Output template profile", + "-v", "", "Show version information", + "-w", "", "Wait for incoming terminal process", + "--", "[program] [args]", "Run commands", + // clang-format on + }; + size_t maxOptionAndArgLength = 0; + for (int i = 0; i < sizeof(options) / sizeof(options[0]); i += 3) { + size_t optionLength = strlen(options[i]); + size_t argLength = strlen(options[i + 1]); + size_t totalLength = optionLength + argLength; + if (totalLength > maxOptionAndArgLength) { + maxOptionAndArgLength = totalLength; + } + } + for (int i = 0; i < sizeof(options) / sizeof(options[0]); i += 3) { + if (i + 1 < sizeof(options) / sizeof(options[0])) { + rz_print_colored_help_option(options[i], options[i + 1], options[i + 2], maxOptionAndArgLength); + } + } + } + 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 options:\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 + } +} + + RZ_API int rz_main_rz_run(int argc, const char **argv) { RzRunProfile *p; int i, ret; if (argc == 1 || !strcmp(argv[1], "-h")) { - printf("Usage: rz-run -v|-t|script.rz [directive ..]\n"); - printf("%s", rz_run_help()); + rz_run_help(0); return 1; } if (!strcmp(argv[1], "-v")) { return rz_main_version_print("rz-run"); } + if (!strcmp(argv[1], "-t")) { + rz_run_help(1); + return 0; + } + if (!strcmp(argv[1], "-l")) { + rz_run_help(2); + return 0; + } const char *file = argv[1]; - if (!strcmp(file, "-t")) { + if (!strcmp(file, "-w")) { #if __UNIX__ rz_run_tty(); return 0; diff --git a/librz/socket/run.c b/librz/socket/run.c index 083d858aa0d..2d5a7c22e2e 100644 --- a/librz/socket/run.c +++ b/librz/socket/run.c @@ -655,54 +655,6 @@ RZ_API bool rz_run_parseline(RzRunProfile *p, const char *b) { return true; } -RZ_API const char *rz_run_help(void) { - return "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"; -} - #if HAVE_OPENPTY && HAVE_FORKPTY && HAVE_LOGIN_TTY static int fd_forward(int in_fd, int out_fd, char **buff) { int size = 0;