Rizin
unix-like reverse engineering framework and cli tools
subprocess.c File Reference
#include <rz_cons.h>
#include <rz_util.h>
#include <errno.h>
#include <sys/wait.h>

Go to the source code of this file.

Classes

struct  rz_subprocess_t
 

Macros

#define BUFFER_SIZE   0x500
 

Functions

static void subprocess_lock (void)
 
static void subprocess_unlock (void)
 
static void handle_sigchld (int sig)
 
static void * sigchld_th (void *th)
 
RZ_API bool rz_subprocess_init (void)
 
RZ_API void rz_subprocess_fini (void)
 
static char ** create_child_env (const char *envvars[], const char *envvals[], size_t env_size)
 
static void destroy_child_env (char **child_env)
 
RZ_API RzSubprocessrz_subprocess_start_opt (RzSubprocessOpt *opt)
 
static size_t read_to_strbuf (RzStrBuf *sb, int fd, bool *fd_eof, size_t n_bytes)
 
static RzSubprocessWaitReason subprocess_wait (RzSubprocess *proc, ut64 timeout_ms, int pipe_fd, size_t n_bytes)
 Wait for subprocess to do something, for a maximum of timeout_ms millisecond. More...
 
RZ_API RzSubprocessWaitReason rz_subprocess_wait (RzSubprocess *proc, ut64 timeout_ms)
 
RZ_API ssize_t rz_subprocess_stdin_write (RzSubprocess *proc, const ut8 *buf, size_t buf_size)
 
RZ_API RzStrBufrz_subprocess_stdout_read (RzSubprocess *proc, size_t n, ut64 timeout_ms)
 
RZ_API RzStrBufrz_subprocess_stdout_readline (RzSubprocess *proc, ut64 timeout_ms)
 
RZ_API void rz_subprocess_kill (RzSubprocess *proc)
 
RZ_API RzSubprocessOutputrz_subprocess_drain (RzSubprocess *proc)
 
RZ_API void rz_subprocess_free (RzSubprocess *proc)
 
RZ_API int rz_subprocess_ret (RzSubprocess *proc)
 
RZ_API ut8rz_subprocess_out (RzSubprocess *proc, int *length)
 
RZ_API ut8rz_subprocess_err (RzSubprocess *proc, int *length)
 
RZ_API void rz_subprocess_output_free (RzSubprocessOutput *out)
 
RZ_API RzSubprocessrz_subprocess_start (const char *file, const char *args[], size_t args_size, const char *envvars[], const char *envvals[], size_t env_size)
 

Variables

static RzPVector subprocs
 
static RzThreadLocksubprocs_mutex
 
static int sigchld_pipe [2]
 
static RzThreadsigchld_thread
 

Macro Definition Documentation

◆ BUFFER_SIZE

#define BUFFER_SIZE   0x500

Definition at line 8 of file subprocess.c.

Function Documentation

◆ create_child_env()

static char** create_child_env ( const char *  envvars[],
const char *  envvals[],
size_t  env_size 
)
static

Definition at line 826 of file subprocess.c.

826  {
827  char **ep;
828  size_t new_env_size = env_size, size = 0;
829  size_t *positions = RZ_NEWS(size_t, env_size);
830  if (!positions) {
831  return NULL;
832  }
833  for (size_t i = 0; i < env_size; i++) {
834  positions[i] = SIZE_MAX;
835  }
836 
837  char **environ = rz_sys_get_environ();
838  for (ep = environ; *ep; ep++, size++) {
839  size_t j;
840 
841  for (j = 0; j < env_size; j++) {
842  if (positions[j] != SIZE_MAX) {
843  continue;
844  }
845  size_t namelen = strlen(envvars[j]);
846  if (!strncmp(*ep, envvars[j], namelen) && (*ep)[namelen] == '=') {
847  positions[j] = size;
848  new_env_size--;
849  break;
850  }
851  }
852  }
853 
854  char **new_env = RZ_NEWS(char *, size + new_env_size + 1);
855  if (!new_env) {
856  free(positions);
857  return NULL;
858  }
859  for (size_t i = 0; i < size; i++) {
860  new_env[i] = strdup(environ[i]);
861  }
862  for (size_t i = 0; i <= new_env_size; i++) {
863  new_env[size + i] = NULL;
864  }
865 
866  for (size_t i = 0; i < env_size; i++) {
867  char *new_var = rz_str_newf("%s=%s", envvars[i], envvals[i]);
868  if (positions[i] == SIZE_MAX) {
869  // No env var exists with the same name, add it at the end
870  free(new_env[size]);
871  new_env[size++] = new_var;
872  } else {
873  // Replace the existing env var
874  free(new_env[positions[i]]);
875  new_env[positions[i]] = new_var;
876  }
877  }
878  free(positions);
879  return new_env;
880 }
lzma_index ** i
Definition: index.h:629
#define NULL
Definition: cris-opc.c:27
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char ** rz_sys_get_environ(void)
Definition: sys.c:1115
#define RZ_NEWS(x, y)
Definition: rz_types.h:283
#define SIZE_MAX
char ** environ

References environ, free(), i, NULL, RZ_NEWS, rz_str_newf(), rz_sys_get_environ(), SIZE_MAX, and strdup().

Referenced by rz_subprocess_start_opt().

◆ destroy_child_env()

static void destroy_child_env ( char **  child_env)
static

Definition at line 882 of file subprocess.c.

882  {
883  if (!child_env) {
884  return;
885  }
886  char **ep;
887  for (ep = child_env; *ep; ep++) {
888  free(*ep);
889  }
890  free(child_env);
891 }

References free().

Referenced by rz_subprocess_start_opt().

◆ handle_sigchld()

static void handle_sigchld ( int  sig)
static

Definition at line 732 of file subprocess.c.

732  {
733  ut8 b = 1;
734  rz_xwrite(sigchld_pipe[1], &b, 1);
735 }
uint8_t ut8
Definition: lh5801.h:11
#define rz_xwrite(fd, buf, count)
Definition: rz_types.h:642
#define b(i)
Definition: sha256.c:42
static int sigchld_pipe[2]
Definition: subprocess.c:721

References b, rz_xwrite, and sigchld_pipe.

Referenced by rz_subprocess_init().

◆ read_to_strbuf()

static size_t read_to_strbuf ( RzStrBuf sb,
int  fd,
bool fd_eof,
size_t  n_bytes 
)
static

Definition at line 1055 of file subprocess.c.

1055  {
1056  char buf[BUFFER_SIZE];
1057  size_t to_read = sizeof(buf);
1058  if (n_bytes && to_read > n_bytes) {
1059  to_read = n_bytes;
1060  }
1061  ssize_t sz = read(fd, buf, to_read);
1062  if (sz < 0) {
1063  perror("read");
1064  } else if (sz == 0) {
1065  *fd_eof = true;
1066  } else {
1067  rz_strbuf_append_n(sb, buf, (int)sz);
1068  }
1069  return sz;
1070 }
static SblHeader sb
Definition: bin_mbn.c:26
voidpf void * buf
Definition: ioapi.h:138
RZ_API bool rz_strbuf_append_n(RzStrBuf *sb, const char *s, size_t l)
Definition: strbuf.c:229
int ssize_t
Definition: sftypes.h:39
#define BUFFER_SIZE
Definition: subprocess.c:8
static const z80_opcode fd[]
Definition: z80_tab.h:997
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115

References BUFFER_SIZE, fd, read(), rz_strbuf_append_n(), and sb.

Referenced by subprocess_wait().

◆ rz_subprocess_drain()

RZ_API RzSubprocessOutput* rz_subprocess_drain ( RzSubprocess proc)

Definition at line 1260 of file subprocess.c.

1260  {
1261  subprocess_lock();
1263  if (out) {
1264  out->out = rz_subprocess_out(proc, &out->out_len);
1265  out->err = rz_subprocess_err(proc, &out->err_len);
1266  out->ret = proc->ret;
1267  out->timeout = false;
1268  }
1270  return out;
1271 }
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define RZ_NEW(x)
Definition: rz_types.h:285
RZ_API ut8 * rz_subprocess_out(RzSubprocess *proc, int *length)
Definition: subprocess.c:1301
RZ_API ut8 * rz_subprocess_err(RzSubprocess *proc, int *length)
Definition: subprocess.c:1312
static void subprocess_unlock(void)
Definition: subprocess.c:728
static void subprocess_lock(void)
Definition: subprocess.c:724
struct Proc * proc

References out, proc, RZ_NEW, rz_subprocess_err(), rz_subprocess_out(), subprocess_lock(), and subprocess_unlock().

Referenced by subprocess_runner().

◆ rz_subprocess_err()

RZ_API ut8* rz_subprocess_err ( RzSubprocess proc,
int length 
)

Definition at line 1312 of file subprocess.c.

1312  {
1313  int bin_len = 0;
1314  const ut8 *bin = rz_strbuf_getbin(&proc->err, &bin_len);
1315  ut8 *buf = (ut8 *)rz_str_newlen((const char *)bin, bin_len);
1316  if (length) {
1317  *length = bin_len;
1318  }
1319  rz_strbuf_fini(&proc->err);
1320  return buf;
1321 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void static offset struct stat static buf void long static basep static whence static length const void static len static semflg const void static shmflg const struct timespec struct timespec static rem const char static group const void length
Definition: sflib.h:133
RZ_API char RZ_API char * rz_str_newlen(const char *str, int len)
Definition: str.c:871
RZ_API void rz_strbuf_fini(RzStrBuf *sb)
Definition: strbuf.c:365
RZ_API ut8 * rz_strbuf_getbin(RzStrBuf *sb, int *len)
Definition: strbuf.c:326
Definition: malloc.c:26

References length, proc, rz_str_newlen(), rz_strbuf_fini(), and rz_strbuf_getbin().

Referenced by rz_subprocess_drain(), rz_sys_cmd_str_full(), and rz_test_run_asm_test().

◆ rz_subprocess_fini()

RZ_API void rz_subprocess_fini ( void  )

Definition at line 814 of file subprocess.c.

814  {
815  rz_sys_signal(SIGCHLD, SIG_IGN);
816  ut8 b = 0;
817  rz_xwrite(sigchld_pipe[1], &b, 1);
824 }
RZ_API void rz_th_free(RZ_NULLABLE RzThread *th)
Frees a RzThread structure.
Definition: thread.c:246
RZ_API bool rz_th_wait(RZ_NONNULL RzThread *th)
Awaits indefinetely for a thread to join.
Definition: thread.c:231
RZ_API int rz_sys_pipe_close(int fd)
Definition: sys.c:1462
RZ_API int rz_sys_signal(int sig, void(*handler)(int))
Definition: sys.c:178
RZ_API void rz_pvector_clear(RzPVector *vec)
Definition: vector.c:326
static RzThreadLock * subprocs_mutex
Definition: subprocess.c:720
static RzThread * sigchld_thread
Definition: subprocess.c:722
static RzPVector subprocs
Definition: subprocess.c:719
RZ_API void rz_th_lock_free(RZ_NULLABLE RzThreadLock *thl)
Frees a RzThreadLock structure.
Definition: thread_lock.c:89

References b, rz_pvector_clear(), rz_sys_pipe_close(), rz_sys_signal(), rz_th_free(), rz_th_lock_free(), rz_th_wait(), rz_xwrite, sigchld_pipe, sigchld_thread, subprocs, and subprocs_mutex.

Referenced by rz_sys_cmd_str_full(), rz_test_main(), system_exec(), and system_exec_stdin().

◆ rz_subprocess_free()

RZ_API void rz_subprocess_free ( RzSubprocess proc)

Definition at line 1273 of file subprocess.c.

1273  {
1274  if (!proc) {
1275  return;
1276  }
1277  subprocess_lock();
1280  rz_strbuf_fini(&proc->out);
1281  rz_strbuf_fini(&proc->err);
1282  rz_sys_pipe_close(proc->killpipe[0]);
1283  rz_sys_pipe_close(proc->killpipe[1]);
1284  if (proc->stdin_fd != -1) {
1285  rz_sys_pipe_close(proc->stdin_fd);
1286  }
1287  if (proc->stdout_fd != -1) {
1288  rz_sys_pipe_close(proc->stdout_fd);
1289  }
1290  if (proc->stderr_fd != -1 && proc->stderr_fd != proc->stdout_fd) {
1291  rz_sys_pipe_close(proc->stderr_fd);
1292  }
1293  free(proc);
1294 }
RZ_API void rz_pvector_remove_data(RzPVector *vec, void *x)
Definition: vector.c:362

References free(), proc, rz_pvector_remove_data(), rz_strbuf_fini(), rz_sys_pipe_close(), subprocess_lock(), subprocess_unlock(), and subprocs.

Referenced by rz_sys_cmd_str_full(), rz_test_check_jq_available(), rz_test_check_json_test(), rz_test_run_asm_test(), subprocess_runner(), system_exec(), and system_exec_stdin().

◆ rz_subprocess_init()

RZ_API bool rz_subprocess_init ( void  )

Definition at line 787 of file subprocess.c.

787  {
790  if (!subprocs_mutex) {
791  return false;
792  }
793  if (rz_sys_pipe(sigchld_pipe, true) == -1) {
794  perror("pipe");
796  return false;
797  }
799  if (!sigchld_thread) {
803  return false;
804  }
805  if (rz_sys_signal(SIGCHLD, handle_sigchld) < 0) {
809  return false;
810  }
811  return true;
812 }
RZ_API RZ_OWN RzThread * rz_th_new(RZ_NONNULL RzThreadFunction function, RZ_NULLABLE void *user)
Creates and starts a new thread.
Definition: thread.c:198
RZ_API int rz_sys_pipe(int pipefd[2], bool close_on_exec)
Definition: sys.c:1458
RZ_API void rz_pvector_init(RzPVector *vec, RzPVectorFree free)
Definition: vector.c:298
static void * sigchld_th(void *th)
Definition: subprocess.c:737
static void handle_sigchld(int sig)
Definition: subprocess.c:732
RZ_API RZ_OWN RzThreadLock * rz_th_lock_new(bool recursive)
Allocates and initialize a RzThreadLock structure.
Definition: thread_lock.c:14

References handle_sigchld(), NULL, rz_pvector_init(), rz_sys_pipe(), rz_sys_pipe_close(), rz_sys_signal(), rz_th_lock_free(), rz_th_lock_new(), rz_th_new(), sigchld_pipe, sigchld_th(), sigchld_thread, subprocs, and subprocs_mutex.

Referenced by rz_sys_cmd_str_full(), rz_test_main(), system_exec(), and system_exec_stdin().

◆ rz_subprocess_kill()

RZ_API void rz_subprocess_kill ( RzSubprocess proc)

Definition at line 1256 of file subprocess.c.

1256  {
1257  kill(proc->pid, SIGKILL);
1258 }
#define SIGKILL
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc kill
Definition: sflib.h:64

References kill, proc, and SIGKILL.

Referenced by rz_test_run_asm_test(), and subprocess_runner().

◆ rz_subprocess_out()

RZ_API ut8* rz_subprocess_out ( RzSubprocess proc,
int length 
)

Definition at line 1301 of file subprocess.c.

1301  {
1302  int bin_len = 0;
1303  const ut8 *bin = rz_strbuf_getbin(&proc->out, &bin_len);
1304  ut8 *buf = (ut8 *)rz_str_newlen((const char *)bin, bin_len);
1305  if (length) {
1306  *length = bin_len;
1307  }
1308  rz_strbuf_fini(&proc->out);
1309  return buf;
1310 }

References length, proc, rz_str_newlen(), rz_strbuf_fini(), and rz_strbuf_getbin().

Referenced by rz_subprocess_drain(), rz_sys_cmd_str_full(), rz_test_run_asm_test(), system_exec(), and system_exec_stdin().

◆ rz_subprocess_output_free()

RZ_API void rz_subprocess_output_free ( RzSubprocessOutput out)

Definition at line 1323 of file subprocess.c.

1323  {
1324  if (!out) {
1325  return;
1326  }
1327  free(out->out);
1328  free(out->err);
1329  free(out);
1330 }

References free(), and out.

Referenced by rz_test_test_result_info_free().

◆ rz_subprocess_ret()

RZ_API int rz_subprocess_ret ( RzSubprocess proc)

Definition at line 1297 of file subprocess.c.

1297  {
1298  return proc->ret;
1299 }

References proc.

Referenced by rz_test_check_jq_available(), rz_test_check_json_test(), rz_test_run_asm_test(), and system_exec().

◆ rz_subprocess_start()

RZ_API RzSubprocess* rz_subprocess_start ( const char *  file,
const char *  args[],
size_t  args_size,
const char *  envvars[],
const char *  envvals[],
size_t  env_size 
)

Start a program in a new child process with the specified parameters.

Parameters
fileName of the program to start. It is also evaluated against PATH
argsArray of arguments to pass to the new program. It does not include argv[0]
args_sizeNumber of arguments in the args array
envvarsName of environment variables that the newprocess has different from the parent
envvalsValues of environment variables that the newprocess has different from the parent. Elements are evaluated in parallel with envvars, so envvals[0] specifies the value of the environment variable named envvars[0] and so on.
env_sizeNumber of environment variables in arrays envvars and envvals

Definition at line 1345 of file subprocess.c.

1347  {
1348  RzSubprocessOpt opt = {
1349  .file = file,
1350  .args = args,
1351  .args_size = args_size,
1352  .envvars = envvars,
1353  .envvals = envvals,
1354  .env_size = env_size,
1355  .stdin_pipe = RZ_SUBPROCESS_PIPE_CREATE,
1356  .stdout_pipe = RZ_SUBPROCESS_PIPE_CREATE,
1357  .stderr_pipe = RZ_SUBPROCESS_PIPE_CREATE,
1358  };
1359  return rz_subprocess_start_opt(&opt);
1360 }
int args
Definition: mipsasm.c:18
@ RZ_SUBPROCESS_PIPE_CREATE
Re-use the same pipe as stdout. It can be used for stderr only.
Definition: rz_subprocess.h:18
const char * file
< Name of the executable to run. It is searched also in PATH
Definition: rz_subprocess.h:59
RZ_API RzSubprocess * rz_subprocess_start_opt(RzSubprocessOpt *opt)
Definition: subprocess.c:893
static int file
Definition: z80asm.c:58

References args, file, rz_subprocess_opt_t::file, RZ_SUBPROCESS_PIPE_CREATE, and rz_subprocess_start_opt().

Referenced by rz_test_check_jq_available(), rz_test_check_json_test(), rz_test_run_asm_test(), and subprocess_runner().

◆ rz_subprocess_start_opt()

RZ_API RzSubprocess* rz_subprocess_start_opt ( RzSubprocessOpt opt)

Definition at line 893 of file subprocess.c.

893  {
895  char **child_env = NULL;
896  char **argv = calloc(opt->args_size + 2, sizeof(char *));
897  if (!argv) {
898  return NULL;
899  }
900  argv[0] = (char *)opt->file;
901  if (opt->args_size) {
902  memcpy(argv + 1, opt->args, sizeof(char *) * opt->args_size);
903  }
904  // done by calloc: argv[args_size + 1] = NULL;
905  subprocess_lock();
907  if (!proc) {
908  goto error;
909  }
910  proc->killpipe[0] = proc->killpipe[1] = -1;
911  proc->ret = -1;
912  proc->stdin_fd = -1;
913  proc->stdout_fd = -1;
914  proc->stderr_fd = -1;
915  rz_strbuf_init(&proc->out);
916  rz_strbuf_init(&proc->err);
917 
918  if (rz_sys_pipe(proc->killpipe, true) == -1) {
919  perror("pipe");
920  goto error;
921  }
922  if (fcntl(proc->killpipe[1], F_SETFL, O_NONBLOCK) < 0) {
923  perror("fcntl");
924  goto error;
925  }
926 
927  int stdin_pipe[2] = { -1, -1 };
928  int stdout_pipe[2] = { -1, -1 };
929  int stderr_pipe[2] = { -1, -1 };
931  if (rz_sys_pipe(stdin_pipe, true) == -1) {
932  perror("pipe");
933  goto error;
934  }
935  proc->stdin_fd = stdin_pipe[1];
936  }
937 
939  if (rz_sys_pipe(stdout_pipe, true) == -1) {
940  perror("pipe");
941  goto error;
942  }
943  if (fcntl(stdout_pipe[0], F_SETFL, O_NONBLOCK) < 0) {
944  perror("fcntl");
945  goto error;
946  }
947  proc->stdout_fd = stdout_pipe[0];
948  }
949 
951  if (rz_sys_pipe(stderr_pipe, true) == -1) {
952  perror("pipe");
953  goto error;
954  }
955  if (fcntl(stderr_pipe[0], F_SETFL, O_NONBLOCK) < 0) {
956  perror("fcntl");
957  goto error;
958  }
959  proc->stderr_fd = stderr_pipe[0];
960  } else if (opt->stderr_pipe == RZ_SUBPROCESS_PIPE_STDOUT) {
961  stderr_pipe[0] = stdout_pipe[0];
962  stderr_pipe[1] = stdout_pipe[1];
963  proc->stderr_fd = proc->stdout_fd;
964  }
965 
966  // Let's create the environment for the child in the parent, with malloc,
967  // because we can't use functions that lock after fork
968  child_env = create_child_env(opt->envvars, opt->envvals, opt->env_size);
969 
970  proc->pid = rz_sys_fork();
971  if (proc->pid == -1) {
972  // fail
973  perror("fork");
974  goto error;
975  } else if (proc->pid == 0) {
976  // child
977  if (stderr_pipe[1] != -1) {
978  while ((dup2(stderr_pipe[1], STDERR_FILENO) == -1) && (errno == EINTR)) {
979  }
980  if (proc->stderr_fd != proc->stdout_fd) {
981  rz_sys_pipe_close(stderr_pipe[1]);
982  rz_sys_pipe_close(stderr_pipe[0]);
983  }
984  }
985  if (stdout_pipe[1] != -1) {
986  while ((dup2(stdout_pipe[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {
987  }
990  }
991  if (stdin_pipe[0] != -1) {
992  while ((dup2(stdin_pipe[0], STDIN_FILENO) == -1) && (errno == EINTR)) {
993  }
996  }
997 
998  // Use the previously created environment
999  rz_sys_set_environ(child_env);
1000 
1001  rz_sys_execvp(opt->file, argv);
1002  perror("exec");
1003  rz_sys_exit(-1, true);
1004  }
1005  destroy_child_env(child_env);
1006  free(argv);
1007 
1008  if (stdin_pipe[0] != -1) {
1010  }
1011  if (stdout_pipe[1] != -1) {
1013  }
1014  if (stderr_pipe[1] != -1 && proc->stderr_fd != proc->stdout_fd) {
1015  rz_sys_pipe_close(stderr_pipe[1]);
1016  }
1017 
1019 
1021 
1022  return proc;
1023 error:
1024  free(argv);
1025  if (proc && proc->killpipe[0] == -1) {
1026  rz_sys_pipe_close(proc->killpipe[0]);
1027  }
1028  if (proc && proc->killpipe[1] == -1) {
1029  rz_sys_pipe_close(proc->killpipe[1]);
1030  }
1031  free(proc);
1032  if (stderr_pipe[0] != -1 && stderr_pipe[0] != stdout_pipe[0]) {
1033  rz_sys_pipe_close(stderr_pipe[0]);
1034  }
1035  if (stderr_pipe[1] != -1 && stderr_pipe[1] != stdout_pipe[1]) {
1036  rz_sys_pipe_close(stderr_pipe[1]);
1037  }
1038  if (stdout_pipe[0] != -1) {
1040  }
1041  if (stdout_pipe[1] != -1) {
1043  }
1044  if (stdin_pipe[0] != -1) {
1046  }
1047  if (stdin_pipe[1] != -1) {
1049  }
1050  destroy_child_env(child_env);
1052  return NULL;
1053 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags fcntl
Definition: sflib.h:79
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
static static fork const void static count static fd const char const char static newpath char char argv
Definition: sflib.h:40
static static fork const void static count static fd const char static mode const char static pathname const char static path const char static dev const char static group static getpid static getuid void void static data static pause const char static mode static sync const char const char static newpath const char static pathname unsigned long static filedes void static end_data_segment static handler static getegid char static len static pgid const char static path dup2
Definition: sflib.h:94
RZ_API void rz_strbuf_init(RzStrBuf *sb)
Definition: strbuf.c:33
@ RZ_SUBPROCESS_PIPE_STDOUT
Definition: rz_subprocess.h:20
RZ_API void rz_sys_set_environ(char **e)
Definition: sys.c:1128
RZ_API void rz_sys_exit(int status, bool nocleanup)
Definition: sys.c:183
RZ_API int rz_sys_fork(void)
Definition: sys.c:1679
RZ_API int rz_sys_execvp(const char *file, char *const argv[])
Definition: sys.c:1525
#define RZ_NEW0(x)
Definition: rz_types.h:284
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
#define O_NONBLOCK
Definition: sftypes.h:494
#define EINTR
Definition: sftypes.h:114
#define F_SETFL
Definition: sftypes.h:507
size_t env_size
Specify how to deal with subprocess stdin.
Definition: rz_subprocess.h:69
RzSubprocessPipeCreate stderr_pipe
Definition: rz_subprocess.h:75
RzSubprocessPipeCreate stdout_pipe
Specify how to deal with subprocess stderr.
Definition: rz_subprocess.h:73
size_t args_size
Names of environment variables that subprocess should have differently from parent.
Definition: rz_subprocess.h:63
const char ** envvals
Number of elements contained in both envvars and envvals.
Definition: rz_subprocess.h:67
const char ** args
Number of arguments in args array.
Definition: rz_subprocess.h:61
RzSubprocessPipeCreate stdin_pipe
Specify how to deal with subprocess stdout.
Definition: rz_subprocess.h:71
const char ** envvars
Values of environment variables that subprocess should have differently from parent.
Definition: rz_subprocess.h:65
static char ** create_child_env(const char *envvars[], const char *envvals[], size_t env_size)
Definition: subprocess.c:826
static void destroy_child_env(char **child_env)
Definition: subprocess.c:882
uv_pipe_t stdin_pipe
Definition: main.c:15
uv_pipe_t stdout_pipe
Definition: main.c:16
#define STDOUT_FILENO
Definition: private.h:41
#define STDERR_FILENO
Definition: private.h:45
#define STDIN_FILENO
Definition: private.h:37
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4

References rz_subprocess_opt_t::args, rz_subprocess_opt_t::args_size, argv, calloc(), create_child_env(), destroy_child_env(), dup2, EINTR, rz_subprocess_opt_t::env_size, rz_subprocess_opt_t::envvals, rz_subprocess_opt_t::envvars, error(), F_SETFL, fcntl, rz_subprocess_opt_t::file, free(), if(), memcpy(), NULL, O_NONBLOCK, proc, RZ_NEW0, rz_pvector_push(), rz_strbuf_init(), RZ_SUBPROCESS_PIPE_CREATE, RZ_SUBPROCESS_PIPE_STDOUT, rz_sys_execvp(), rz_sys_exit(), rz_sys_fork(), rz_sys_pipe(), rz_sys_pipe_close(), rz_sys_set_environ(), STDERR_FILENO, rz_subprocess_opt_t::stderr_pipe, STDIN_FILENO, rz_subprocess_opt_t::stdin_pipe, stdin_pipe, STDOUT_FILENO, rz_subprocess_opt_t::stdout_pipe, stdout_pipe, subprocess_lock(), subprocess_unlock(), and subprocs.

Referenced by rz_subprocess_start(), rz_sys_cmd_str_full(), system_exec(), and system_exec_stdin().

◆ rz_subprocess_stdin_write()

RZ_API ssize_t rz_subprocess_stdin_write ( RzSubprocess proc,
const ut8 buf,
size_t  buf_size 
)

Sends some data to the stdin of the subprocess and returns the number of bytes sent.

Parameters
procSubprocess to communicate with
bufData that needs to be send to the subprocess stdin
buf_sizeNumber of bytes to send

Definition at line 1206 of file subprocess.c.

1206  {
1207  ssize_t written = -1;
1208  if (proc->stdin_fd == -1) {
1209  return written;
1210  }
1211  rz_sys_signal(SIGPIPE, SIG_IGN);
1212  written = write(proc->stdin_fd, buf, buf_size);
1213  rz_sys_signal(SIGPIPE, SIG_DFL);
1214  return written;
1215 }
static static fork write
Definition: sflib.h:33
static int buf_size
Definition: debug_qnx.c:35

References buf_size, proc, rz_sys_signal(), and write.

Referenced by rz_sys_cmd_str_full(), rz_test_check_jq_available(), rz_test_check_json_test(), and system_exec_stdin().

◆ rz_subprocess_stdout_read()

RZ_API RzStrBuf* rz_subprocess_stdout_read ( RzSubprocess proc,
size_t  n,
ut64  timeout_ms 
)

Read some data from the stdout of the subprocess and returns a RzStrBuf containing it. Callers must not free the returned pointer.

Parameters
procSubprocess to communicate with
nNumber of bytes to read from the subprocess' stdout
timeout_msWait for at most this amount of millisecond to read subprocess' stdout

Definition at line 1225 of file subprocess.c.

1225  {
1226  rz_strbuf_fini(&proc->out);
1227  rz_strbuf_init(&proc->out);
1228  if (proc->stdout_fd != -1) {
1229  subprocess_wait(proc, timeout_ms, RZ_SUBPROCESS_STDOUT, n);
1230  }
1231  return &proc->out;
1232 }
int n
Definition: mipsasm.c:19
#define RZ_SUBPROCESS_STDOUT
Definition: rz_subprocess.h:27
static RzSubprocessWaitReason subprocess_wait(RzSubprocess *proc, ut64 timeout_ms, int pipe_fd, size_t n_bytes)
Wait for subprocess to do something, for a maximum of timeout_ms millisecond.
Definition: subprocess.c:1085

References n, proc, rz_strbuf_fini(), rz_strbuf_init(), RZ_SUBPROCESS_STDOUT, and subprocess_wait().

◆ rz_subprocess_stdout_readline()

RZ_API RzStrBuf* rz_subprocess_stdout_readline ( RzSubprocess proc,
ut64  timeout_ms 
)

Read one line from the stdout of the subprocess and returns a RzStrBuf containing it. Callers must not free the returned pointer.

Parameters
procSubprocess to communicate with
timeout_msWait for at most this amount of millisecond to read subprocess' stdout

Definition at line 1241 of file subprocess.c.

1241  {
1242  rz_strbuf_fini(&proc->out);
1243  rz_strbuf_init(&proc->out);
1244  if (proc->stdout_fd != -1) {
1245  char c = '\0';
1246  RzSubprocessWaitReason reason;
1247  // FIXME: the timeout should also be checked globally here
1248  do {
1249  reason = subprocess_wait(proc, timeout_ms, RZ_SUBPROCESS_STDOUT, 1);
1250  c = rz_strbuf_get(&proc->out)[rz_strbuf_length(&proc->out) - 1];
1251  } while (c != '\n' && reason == RZ_SUBPROCESS_BYTESREAD);
1252  }
1253  return &proc->out;
1254 }
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
RZ_API int rz_strbuf_length(RzStrBuf *sb)
Definition: strbuf.c:28
@ RZ_SUBPROCESS_BYTESREAD
Definition: rz_subprocess.h:33
enum rz_process_wait_reason_t RzSubprocessWaitReason
#define c(i)
Definition: sha256.c:43

References c, proc, rz_strbuf_fini(), rz_strbuf_get(), rz_strbuf_init(), rz_strbuf_length(), RZ_SUBPROCESS_BYTESREAD, RZ_SUBPROCESS_STDOUT, and subprocess_wait().

◆ rz_subprocess_wait()

RZ_API RzSubprocessWaitReason rz_subprocess_wait ( RzSubprocess proc,
ut64  timeout_ms 
)

Wait until process dies or timeout expires and collect stdout + stderr. No more input can be sent after this call.

Parameters
procSubprocess to communicate with
timeout_msWait for at most this amount of millisecond

Definition at line 1185 of file subprocess.c.

1185  {
1186  if (proc->stdin_fd != -1) {
1187  // Close subprocess stdin to tell it that no more input will come from us
1188  rz_sys_pipe_close(proc->stdin_fd);
1189  proc->stdin_fd = -1;
1190  }
1191  // Empty buffers and read everything we can
1192  rz_strbuf_fini(&proc->out);
1193  rz_strbuf_init(&proc->out);
1194  rz_strbuf_fini(&proc->err);
1195  rz_strbuf_init(&proc->err);
1197 }
#define RZ_SUBPROCESS_STDERR
Definition: rz_subprocess.h:28

References proc, rz_strbuf_fini(), rz_strbuf_init(), RZ_SUBPROCESS_STDERR, RZ_SUBPROCESS_STDOUT, rz_sys_pipe_close(), and subprocess_wait().

Referenced by rz_sys_cmd_str_full(), rz_test_check_jq_available(), rz_test_check_json_test(), rz_test_run_asm_test(), subprocess_runner(), system_exec(), and system_exec_stdin().

◆ sigchld_th()

static void* sigchld_th ( void *  th)
static

Definition at line 737 of file subprocess.c.

737  {
738  while (true) {
739  ut8 b;
740  ssize_t rd = read(sigchld_pipe[0], &b, 1);
741  if (rd <= 0) {
742  if (rd < 0) {
743  if (errno == EINTR) {
744  continue;
745  }
746  perror("read");
747  }
748  break;
749  }
750  if (!b) {
751  break;
752  }
753  while (true) {
754  int wstat;
755  pid_t pid = waitpid(-1, &wstat, WNOHANG);
756  if (pid <= 0)
757  break;
758 
759  subprocess_lock();
760  void **it;
763  RzSubprocess *p = *it;
764  if (p->pid == pid) {
765  proc = p;
766  break;
767  }
768  }
769  if (!proc) {
771  continue;
772  }
773 
774  if (WIFEXITED(wstat)) {
775  proc->ret = WEXITSTATUS(wstat);
776  } else {
777  proc->ret = -1;
778  }
779  ut8 r = 0;
780  rz_xwrite(proc->killpipe[1], &r, 1);
782  }
783  }
784  return NULL;
785 }
#define rd()
#define r
Definition: crypto_rc6.c:12
void * p
Definition: libc.cpp:67
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
Definition: sflib.h:64
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
int pid_t
Definition: sftypes.h:38

References b, EINTR, NULL, p, pid, proc, r, rd, read(), rz_pvector_foreach, rz_xwrite, sigchld_pipe, subprocess_lock(), subprocess_unlock(), and subprocs.

Referenced by rz_subprocess_init().

◆ subprocess_lock()

static void subprocess_lock ( void  )
static

Definition at line 724 of file subprocess.c.

724  {
726 }
RZ_API void rz_th_lock_enter(RZ_NONNULL RzThreadLock *thl)
Acquires a RzThreadLock structure.
Definition: thread_lock.c:45

References rz_th_lock_enter(), and subprocs_mutex.

Referenced by rz_subprocess_drain(), rz_subprocess_free(), rz_subprocess_start_opt(), and sigchld_th().

◆ subprocess_unlock()

static void subprocess_unlock ( void  )
static

Definition at line 728 of file subprocess.c.

728  {
730 }
RZ_API void rz_th_lock_leave(RZ_NONNULL RzThreadLock *thl)
Releases a RzThreadLock structure.
Definition: thread_lock.c:75

References rz_th_lock_leave(), and subprocs_mutex.

Referenced by rz_subprocess_drain(), rz_subprocess_free(), rz_subprocess_start_opt(), and sigchld_th().

◆ subprocess_wait()

static RzSubprocessWaitReason subprocess_wait ( RzSubprocess proc,
ut64  timeout_ms,
int  pipe_fd,
size_t  n_bytes 
)
static

Wait for subprocess to do something, for a maximum of timeout_ms millisecond.

This function can be used to wait for some action from the subprocess, which includes terminating or sending output to stdout/stderr. If n_bytes is not 0, the function terminates as soon as n_bytes bytes have been read or the timeout expires.

Parameters
procSubprocess to interact with
timeout_msNumber of millisecond to wait before stopping the operation. If UT64_MAX no timeout is set
pipe_fdsOne of RZ_SUBPROCESS_STDOUT , RZ_SUBPROCESS_STDERR or a combination of them. Bytes are read only from those.
n_bytesNumber of bytes to read. If pipe_fds references multiple FDs, this indicates the number to read in either of them.

Definition at line 1085 of file subprocess.c.

1085  {
1086  ut64 timeout_abs = UT64_MAX;
1087  if (timeout_ms != UT64_MAX) {
1088  timeout_abs = rz_time_now_mono() + timeout_ms * RZ_USEC_PER_MSEC;
1089  }
1090 
1091  int r = 0;
1092  bool stdout_enabled = (pipe_fd & RZ_SUBPROCESS_STDOUT) && proc->stdout_fd != -1;
1093  bool stderr_enabled = (pipe_fd & RZ_SUBPROCESS_STDERR) && proc->stderr_fd != -1 && proc->stderr_fd != proc->stdout_fd;
1094  bool stdout_eof = false;
1095  bool stderr_eof = false;
1096  bool child_dead = false;
1097  bool timedout = true;
1098  bool bytes_enabled = n_bytes != 0;
1099  while ((!bytes_enabled || n_bytes) && ((stdout_enabled && !stdout_eof) || (stderr_enabled && !stderr_eof) || !child_dead)) {
1100  fd_set rfds;
1101  FD_ZERO(&rfds);
1102  int nfds = 0;
1103  if (stdout_enabled && !stdout_eof) {
1104  FD_SET(proc->stdout_fd, &rfds);
1105  if (proc->stdout_fd > nfds) {
1106  nfds = proc->stdout_fd;
1107  }
1108  }
1109  if (stderr_enabled && !stderr_eof) {
1110  FD_SET(proc->stderr_fd, &rfds);
1111  if (proc->stderr_fd > nfds) {
1112  nfds = proc->stderr_fd;
1113  }
1114  }
1115  if (!child_dead) {
1116  FD_SET(proc->killpipe[0], &rfds);
1117  if (proc->killpipe[0] > nfds) {
1118  nfds = proc->killpipe[0];
1119  }
1120  }
1121  nfds++;
1122 
1123  struct timeval timeout_s;
1124  struct timeval *timeout = NULL;
1125  if (timeout_ms != UT64_MAX) {
1126  ut64 now = rz_time_now_mono();
1127  if (now >= timeout_abs) {
1128  break;
1129  }
1130  ut64 usec_diff = timeout_abs - rz_time_now_mono();
1131  timeout_s.tv_sec = usec_diff / RZ_USEC_PER_SEC;
1132  timeout_s.tv_usec = usec_diff % RZ_USEC_PER_SEC;
1133  timeout = &timeout_s;
1134  }
1135  r = select(nfds, &rfds, NULL, NULL, timeout);
1136  if (r < 0) {
1137  if (errno == EINTR) {
1138  continue;
1139  }
1140  break;
1141  }
1142 
1143  timedout = true;
1144  if (stdout_enabled && FD_ISSET(proc->stdout_fd, &rfds)) {
1145  timedout = false;
1146  size_t r = read_to_strbuf(&proc->out, proc->stdout_fd, &stdout_eof, n_bytes);
1147  if (r > 0 && n_bytes) {
1148  n_bytes -= r;
1149  }
1150  }
1151  if (stderr_enabled && FD_ISSET(proc->stderr_fd, &rfds)) {
1152  timedout = false;
1153  size_t r = read_to_strbuf(&proc->err, proc->stderr_fd, &stderr_eof, n_bytes);
1154  if (r > 0 && n_bytes) {
1155  n_bytes -= r;
1156  }
1157  }
1158  if (FD_ISSET(proc->killpipe[0], &rfds)) {
1159  timedout = false;
1160  child_dead = true;
1161  }
1162  if (timedout) {
1163  break;
1164  }
1165  }
1166  if (r < 0) {
1167  perror("select");
1168  }
1169  if (child_dead) {
1170  return RZ_SUBPROCESS_DEAD;
1171  } else if (timedout) {
1172  return RZ_SUBPROCESS_TIMEDOUT;
1173  } else {
1174  return RZ_SUBPROCESS_BYTESREAD;
1175  }
1176 }
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz select
Definition: sflib.h:108
static const char struct stat static buf struct stat static buf static vhangup int struct rusage static rusage struct sysinfo static info unsigned static __unused struct utsname static buf const char static size const char static name static pid unsigned static persona static fsgid const void static flags const struct iovec static count static fd const void static len static munlockall struct sched_param static p static sched_yield static policy const struct timespec struct timespec static rem uid_t uid_t uid_t static suid struct pollfd unsigned nfds
Definition: sflib.h:196
@ RZ_SUBPROCESS_TIMEDOUT
Definition: rz_subprocess.h:32
@ RZ_SUBPROCESS_DEAD
Definition: rz_subprocess.h:31
#define RZ_USEC_PER_SEC
Definition: rz_time.h:9
#define RZ_USEC_PER_MSEC
Definition: rz_time.h:11
RZ_API ut64 rz_time_now_mono(void)
Returns the current time in microseconds, using the monotonic clock.
Definition: time.c:102
#define UT64_MAX
Definition: rz_types_base.h:86
#define FD_ZERO(set)
Definition: sftypes.h:204
#define FD_ISSET(d, set)
Definition: sftypes.h:214
#define FD_SET(d, set)
Definition: sftypes.h:212
static size_t read_to_strbuf(RzStrBuf *sb, int fd, bool *fd_eof, size_t n_bytes)
Definition: subprocess.c:1055
uv_timer_t timeout
Definition: main.c:9
ut64(WINAPI *w32_GetEnabledXStateFeatures)()

References EINTR, FD_ISSET, FD_SET, FD_ZERO, nfds, NULL, proc, r, read_to_strbuf(), RZ_SUBPROCESS_BYTESREAD, RZ_SUBPROCESS_DEAD, RZ_SUBPROCESS_STDERR, RZ_SUBPROCESS_STDOUT, RZ_SUBPROCESS_TIMEDOUT, rz_time_now_mono(), RZ_USEC_PER_MSEC, RZ_USEC_PER_SEC, select, timeout, timeval::tv_sec, timeval::tv_usec, ut64(), and UT64_MAX.

Referenced by rz_subprocess_stdout_read(), rz_subprocess_stdout_readline(), and rz_subprocess_wait().

Variable Documentation

◆ sigchld_pipe

int sigchld_pipe[2]
static

Definition at line 721 of file subprocess.c.

Referenced by handle_sigchld(), rz_subprocess_fini(), rz_subprocess_init(), and sigchld_th().

◆ sigchld_thread

RzThread* sigchld_thread
static

Definition at line 722 of file subprocess.c.

Referenced by rz_subprocess_fini(), and rz_subprocess_init().

◆ subprocs

◆ subprocs_mutex

RzThreadLock* subprocs_mutex
static