Rizin
unix-like reverse engineering framework and cli tools
subprocess.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2020 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2021 ret2libc <sirmy15@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_cons.h>
6 #include <rz_util.h>
7 
8 #define BUFFER_SIZE 0x500
9 
10 #if __WINDOWS__
11 #include <rz_windows.h>
12 
13 #if NTDDI_VERSION >= NTDDI_VISTA
14 typedef _Success_(return != FALSE) BOOL(WINAPI *InitializeProcThreadAttributeList_t)(
15  _Out_writes_bytes_to_opt_(*lpSize, *lpSize) LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
16  _In_ DWORD dwAttributeCount,
17  _Reserved_ DWORD dwFlags,
18  _When_(lpAttributeList == nullptr, _Out_) _When_(lpAttributeList != nullptr, _Inout_) PSIZE_T lpSize);
19 
20 typedef BOOL(WINAPI *UpdateProcThreadAttribute_t)(
21  _Inout_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList,
22  _In_ DWORD dwFlags,
23  _In_ DWORD_PTR Attribute,
24  _In_reads_bytes_opt_(cbSize) PVOID lpValue,
25  _In_ SIZE_T cbSize,
26  _Out_writes_bytes_opt_(cbSize) PVOID lpPreviousValue,
27  _In_opt_ PSIZE_T lpReturnSize);
28 
29 typedef VOID(WINAPI *DeleteProcThreadAttributeList_t)(
30  _Inout_ LPPROC_THREAD_ATTRIBUTE_LIST lpAttributeList);
31 
32 static InitializeProcThreadAttributeList_t lpInitializeProcThreadAttributeList = NULL;
33 static UpdateProcThreadAttribute_t lpUpdateProcThreadAttribute = NULL;
34 static DeleteProcThreadAttributeList_t lpDeleteProcThreadAttributeList = NULL;
35 #endif
36 
37 struct rz_subprocess_t {
38  HANDLE stdin_write;
39  HANDLE stdout_read;
40  HANDLE stderr_read;
41  HANDLE proc;
42  int ret;
43  RzStrBuf out;
44  RzStrBuf err;
45 };
46 
47 #define INVALID_POINTER_VALUE ((void *)PTRDIFF_MAX)
48 
49 static RzThreadLock *subproc_mutex = NULL;
50 static long refcount = 0;
51 static bool has_procthreadattr = false;
52 static volatile long pipe_id = 0;
53 static DWORD mode_stdin;
54 static DWORD mode_stdout;
55 static DWORD mode_stderr;
56 
57 static bool create_pipe_overlap(HANDLE *pipe_read, HANDLE *pipe_write, LPSECURITY_ATTRIBUTES attrs, DWORD sz, DWORD read_mode, DWORD write_mode) {
58  // see https://stackoverflow.com/a/419736
59  if (!sz) {
60  sz = 4096;
61  }
62  WCHAR name[MAX_PATH];
63  _snwprintf_s(name, _countof(name), sizeof(name), L"\\\\.\\pipe\\rz-pipe-subproc.%d.%ld", (int)GetCurrentProcessId(), (long)InterlockedIncrement(&pipe_id));
64  *pipe_read = CreateNamedPipeW(name, PIPE_ACCESS_INBOUND | read_mode, PIPE_TYPE_BYTE | PIPE_WAIT, 1, sz, sz, 120 * 1000, attrs);
65  if (!*pipe_read) {
66  return FALSE;
67  }
68  *pipe_write = CreateFileW(name, GENERIC_WRITE, 0, attrs, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | write_mode, NULL);
69  if (*pipe_write == INVALID_HANDLE_VALUE) {
70  CloseHandle(*pipe_read);
71  return FALSE;
72  }
73 
74  SetEnvironmentVariableW(L"RZ_PIPE_PATH", name);
75  return true;
76 }
77 
78 static RzThreadLock *get_subprocess_lock(void) {
80  do {
81  lock = InterlockedCompareExchangePointer(&subproc_mutex, INVALID_POINTER_VALUE, INVALID_POINTER_VALUE);
82  } while (!lock);
83  return lock;
84 }
85 
86 RZ_API bool rz_subprocess_init(void) {
87  long ref = InterlockedIncrement(&refcount);
89  if (ref == 1) {
90  lock = rz_th_lock_new(false);
91  if (!lock) {
92  InterlockedExchangePointer(&subproc_mutex, INVALID_POINTER_VALUE);
93  InterlockedDecrement(&refcount);
94  return false;
95  }
96  // Enter lock before making it available, so we are the first to run
98  InterlockedExchangePointer(&subproc_mutex, lock);
99  } else {
100  // Spin until theres a lock available or lock initialization failed
101  lock = get_subprocess_lock();
102  if (lock == INVALID_POINTER_VALUE) {
103  InterlockedDecrement(&refcount);
104  return false;
105  }
107  }
108 
109  if (ref > 1) {
110  // This is not the first call to this function, just leave
111  goto leave;
112  }
113 
114  // Save current console mode
115  GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode_stdin);
116  GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &mode_stdout);
117  GetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), &mode_stderr);
118 
119 #if NTDDI_VERSION >= NTDDI_VISTA
120  if (!has_procthreadattr && IsWindowsVistaOrGreater()) {
121  HMODULE kernel32 = LoadLibraryW(L"kernel32");
122  if (!kernel32) {
123  rz_sys_perror("LoadLibraryW(L\"kernel32\")");
124  goto leave;
125  }
126  lpInitializeProcThreadAttributeList = (InitializeProcThreadAttributeList_t)GetProcAddress(kernel32, "InitializeProcThreadAttributeList");
127  lpUpdateProcThreadAttribute = (UpdateProcThreadAttribute_t)GetProcAddress(kernel32, "UpdateProcThreadAttribute");
128  lpDeleteProcThreadAttributeList = (DeleteProcThreadAttributeList_t)GetProcAddress(kernel32, "DeleteProcThreadAttributeList");
129  if (lpInitializeProcThreadAttributeList && lpUpdateProcThreadAttribute && lpDeleteProcThreadAttributeList) {
130  has_procthreadattr = true;
131  }
132  FreeLibrary(kernel32);
133  }
134 #endif
135 leave:
137  return true;
138 }
139 RZ_API void rz_subprocess_fini(void) {
141  do {
142  if (InterlockedCompareExchange(&refcount, -1, -1) == 0) {
143  // Shouldn't happen, someone called this function excessively
145  return;
146  }
147  lock = InterlockedExchangePointer(&subproc_mutex, NULL);
148  } while (!lock);
149  if (InterlockedDecrement(&refcount) > 0) {
150  InterlockedExchangePointer(&subproc_mutex, lock);
151  return;
152  }
153  SetEnvironmentVariableW(L"RZ_PIPE_PATH", NULL);
154  // Restore console mode
155  SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode_stdin);
156  SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), mode_stdout);
157  SetConsoleMode(GetStdHandle(STD_ERROR_HANDLE), mode_stderr);
159 }
160 
161 // Create an env block that inherits the current vars but overrides the given ones
162 static LPWCH override_env(const char *envvars[], const char *envvals[], size_t env_size) {
163  LPWCH ret = NULL;
164  LPWCH parent_env = NULL;
165  size_t i;
166  LPWSTR *wenvvars = calloc(env_size, sizeof(LPWSTR));
167  LPWSTR *wenvvals = calloc(env_size, sizeof(LPWSTR));
168  parent_env = GetEnvironmentStringsW();
169  if (!wenvvars || !wenvvals || !parent_env) {
170  goto error;
171  }
172 
173  for (i = 0; i < env_size; i++) {
174  wenvvars[i] = rz_utf8_to_utf16(envvars[i]);
175  wenvvals[i] = rz_utf8_to_utf16(envvals[i]);
176  if (!wenvvars[i] || !wenvvals[i]) {
177  goto error;
178  }
179  }
180 
181  RzVector buf;
182  rz_vector_init(&buf, sizeof(wchar_t), NULL, NULL);
183  LPWCH cur = parent_env;
184  while (true) {
185  LPWCH var_begin = cur;
186  // wprintf (L"ENV: %s\n", cur);
187  while (*cur && *cur != L'=') {
188  cur++;
189  }
190  if (!*cur) {
191  cur++;
192  if (!*cur) {
193  break;
194  }
195  continue;
196  }
197  bool overridden = false;
198  for (i = 0; i < env_size; i++) {
199  size_t overlen = lstrlenW(wenvvars[i]);
200  size_t curlen = cur - var_begin;
201  if (overlen == curlen && !memcmp(var_begin, wenvvars[i], overlen)) {
202  overridden = true;
203  break;
204  }
205  }
206  while (*cur) {
207  cur++;
208  }
209  if (!overridden) {
210  rz_vector_insert_range(&buf, buf.len, var_begin, cur - var_begin + 1);
211  }
212  cur++;
213  if (!*cur) {
214  // \0\0 marks the end
215  break;
216  }
217  }
218 
219  wchar_t c;
220  for (i = 0; i < env_size; i++) {
221  rz_vector_insert_range(&buf, buf.len, wenvvars[i], lstrlenW(wenvvars[i]));
222  c = L'=';
223  rz_vector_push(&buf, &c);
224  rz_vector_insert_range(&buf, buf.len, wenvvals[i], lstrlenW(wenvvals[i]));
225  c = L'\0';
226  rz_vector_push(&buf, &c);
227  }
228  c = '\0';
229  rz_vector_push(&buf, &c);
230  ret = buf.a;
231 
232 error:
233  if (parent_env) {
234  FreeEnvironmentStringsW(parent_env);
235  }
236  for (i = 0; i < env_size; i++) {
237  if (wenvvars) {
238  free(wenvvars[i]);
239  }
240  if (wenvvals) {
241  free(wenvvals[i]);
242  }
243  }
244  free(wenvvars);
245  free(wenvvals);
246  return ret;
247 }
248 
251  const HANDLE curr_stdin_handle = (HANDLE)_get_osfhandle(fileno(stdin));
252  const HANDLE curr_stdout_handle = (HANDLE)_get_osfhandle(fileno(stdout));
253  const HANDLE curr_stderr_handle = (HANDLE)_get_osfhandle(fileno(stderr));
254  HANDLE stdin_read = curr_stdin_handle;
255  HANDLE stdout_write = curr_stdout_handle;
256  HANDLE stderr_write = curr_stderr_handle;
257  LPWSTR lpFilePart;
258  PWCHAR cmd_exe = RZ_NEWS0(WCHAR, MAX_PATH);
259 #if NTDDI_VERSION >= NTDDI_VISTA
260  LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL;
261 #endif
263 
264  PWCHAR file = rz_utf8_to_utf16(opt->file);
265  if (!file) {
266  return NULL;
267  }
268 
269  if (!rz_file_exists(opt->file)) {
270  DWORD len;
271  if ((len = SearchPathW(NULL, file, L".exe", MAX_PATH, cmd_exe, &lpFilePart)) < 1) {
272  RZ_LOG_DEBUG("SearchPath failed for %s\n", opt->file);
273  free(file);
274  return NULL;
275  }
276  if (len > MAX_PATH) {
277  PWCHAR tmp = realloc(cmd_exe, sizeof(WCHAR) * len);
278  if (!tmp) {
279  free(cmd_exe);
280  free(file);
281  return NULL;
282  }
283  cmd_exe = tmp;
284  SearchPathW(NULL, file, L".exe", len, cmd_exe, &lpFilePart);
285  }
286  free(file);
287  } else {
288  cmd_exe = file;
289  }
290 
291  char **argv = calloc(opt->args_size + 1, sizeof(char *));
292  if (!argv) {
293  return NULL;
294  }
295  argv[0] = ""; // a space is required to work correctly.
296  if (opt->args_size) {
297  memcpy(argv + 1, opt->args, sizeof(char *) * opt->args_size);
298  }
299  char *cmd = rz_str_format_msvc_argv(opt->args_size + 1, (const char **)argv);
300  free(argv);
301  if (!cmd) {
302  return NULL;
303  }
304  PWCHAR cmdline = rz_utf8_to_utf16(cmd);
305  if (!cmdline) {
306  goto error;
307  }
308 
309  {
310  char *log_executable = rz_utf16_to_utf8(cmd_exe);
311  if (log_executable) {
312  RZ_LOG_DEBUG("%s%s\n", log_executable, cmd);
313  free(log_executable);
314  }
315  }
316 
318  if (!proc) {
319  goto error;
320  }
321  proc->ret = -1;
322  proc->stdout_read = NULL;
323  proc->stderr_read = NULL;
324  proc->stdin_write = NULL;
325 
326  SECURITY_ATTRIBUTES sattrs;
327  sattrs.nLength = sizeof(sattrs);
328  sattrs.bInheritHandle = TRUE;
329  sattrs.lpSecurityDescriptor = NULL;
330 
332  if (!create_pipe_overlap(&proc->stdout_read, &stdout_write, &sattrs, 0, FILE_FLAG_OVERLAPPED, 0)) {
333  proc->stdout_read = stdout_write = NULL;
334  goto error;
335  }
336  if (!SetHandleInformation(proc->stdout_read, HANDLE_FLAG_INHERIT, 0)) {
337  goto error;
338  }
339  }
341  if (!create_pipe_overlap(&proc->stderr_read, &stderr_write, &sattrs, 0, FILE_FLAG_OVERLAPPED, 0)) {
342  proc->stdout_read = stderr_write = NULL;
343  goto error;
344  }
345  if (!SetHandleInformation(proc->stderr_read, HANDLE_FLAG_INHERIT, 0)) {
346  goto error;
347  }
348  } else if (opt->stderr_pipe == RZ_SUBPROCESS_PIPE_STDOUT) {
349  proc->stderr_read = proc->stdout_read;
350  stderr_write = stdout_write;
351  }
352 
354  if (!CreatePipe(&stdin_read, &proc->stdin_write, &sattrs, 0)) {
355  stdin_read = proc->stdin_write = NULL;
356  goto error;
357  }
358  if (!SetHandleInformation(proc->stdin_write, HANDLE_FLAG_INHERIT, 0)) {
359  goto error;
360  }
361  }
362 
363  PROCESS_INFORMATION proc_info = { 0 };
364  DWORD dwCreationFlags = CREATE_UNICODE_ENVIRONMENT;
365  STARTUPINFOW start_info_short = { .cb = sizeof(STARTUPINFOW) };
366  STARTUPINFOW *start_info = &start_info_short;
367 #if NTDDI_VERSION >= NTDDI_VISTA
368  STARTUPINFOEXW start_infoex = { .StartupInfo.cb = sizeof(STARTUPINFOEXW) };
369  if (has_procthreadattr) {
370  SIZE_T attr_list_size = 0;
371  if (!lpInitializeProcThreadAttributeList(NULL, 1, 0, &attr_list_size) &&
372  GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
373  goto error;
374  }
375  attr_list = malloc(attr_list_size);
376  if (!attr_list) {
377  goto error;
378  }
379  if (!lpInitializeProcThreadAttributeList(attr_list, 1, 0, &attr_list_size)) {
380  goto error;
381  }
382  HANDLE handle_list[3] = { stdin_read, stdout_write };
384  handle_list[2] = stderr_write;
385  }
386  const int num_handles = opt->stderr_pipe != RZ_SUBPROCESS_PIPE_STDOUT ? 3 : 2;
387  if (!lpUpdateProcThreadAttribute(attr_list, 0, PROC_THREAD_ATTRIBUTE_HANDLE_LIST, handle_list, num_handles * sizeof(HANDLE), NULL, NULL)) {
388  goto error;
389  }
390  start_info = (STARTUPINFOW *)&start_infoex;
391  start_infoex.lpAttributeList = attr_list;
392  dwCreationFlags |= EXTENDED_STARTUPINFO_PRESENT;
393  } else {
394  lock = get_subprocess_lock();
395  }
396 #else
397  lock = get_subprocess_lock();
398 #endif
399 
400  start_info->hStdError = stderr_write;
401  start_info->hStdOutput = stdout_write;
402  start_info->hStdInput = stdin_read;
403  start_info->dwFlags = STARTF_USESTDHANDLES;
404 
405  LPWSTR env = override_env(opt->envvars, opt->envvals, opt->env_size);
406  if (!CreateProcessW(
407  cmd_exe, // exe
408  cmdline, // command line
409  NULL, // process security attributes
410  NULL, // primary thread security attributes
411  TRUE, // handles are inherited
412  dwCreationFlags, // creation flags
413  env, // use parent's environment
414  NULL, // use parent's current directory
415  start_info, // STARTUPINFO pointer
416  &proc_info)) { // receives PROCESS_INFORMATION
417  free(env);
418  rz_sys_perror("CreateProcess");
419  goto error;
420  }
421  free(env);
422 
423  CloseHandle(proc_info.hThread);
424  proc->proc = proc_info.hProcess;
425 
426 beach:
427 
428  if (lock) {
430  }
431 #if NTDDI_VERSION >= NTDDI_VISTA
432  if (attr_list) {
433  lpDeleteProcThreadAttributeList(attr_list);
434  free(attr_list);
435  }
436 #endif
437 
438  if (stdin_read && stdin_read != curr_stdin_handle) {
439  CloseHandle(stdin_read);
440  }
441  if (stderr_write && stderr_write != curr_stderr_handle && stderr_write != stdout_write) {
442  CloseHandle(stderr_write);
443  }
444  if (stdout_write && stdout_write != curr_stdout_handle) {
445  CloseHandle(stdout_write);
446  }
447  free(cmd_exe);
448  free(cmdline);
449  return proc;
450 error:
451  if (proc) {
452  if (proc->stderr_read && proc->stderr_read != proc->stdout_read) {
453  CloseHandle(proc->stderr_read);
454  }
455  if (proc->stdout_read) {
456  CloseHandle(proc->stdout_read);
457  }
458  if (proc->stdin_write) {
459  CloseHandle(proc->stdin_write);
460  }
461  free(proc);
462  proc = NULL;
463  }
464  goto beach;
465 }
466 
467 static bool do_read(HANDLE *f, char *buf, size_t buf_size, size_t n_bytes, OVERLAPPED *overlapped) {
468  size_t to_read = buf_size;
469  if (n_bytes && to_read > n_bytes) {
470  to_read = n_bytes;
471  }
472  if (!ReadFile(f, buf, to_read, NULL, overlapped)) {
473  if (GetLastError() != ERROR_IO_PENDING) { /* EOF or some other error */
474  return true;
475  }
476  }
477  return false;
478 }
479 
480 static void cancel_read(HANDLE *f, RzStrBuf *sb, char *buf, OVERLAPPED *overlapped) {
481  if (!CancelIo(f)) {
482  rz_sys_perror("CancelIo");
483  }
484  DWORD bytes_transferred;
485  if (GetOverlappedResult(f, overlapped, &bytes_transferred, TRUE) || GetLastError() == ERROR_OPERATION_ABORTED) {
486  rz_strbuf_append_n(sb, buf, bytes_transferred);
487  } else {
488  rz_sys_perror("GetOverlappedResult");
489  }
490  CloseHandle(overlapped->hEvent);
491 }
492 
493 static RzSubprocessWaitReason subprocess_wait(RzSubprocess *proc, ut64 timeout_ms, int pipe_fd, size_t n_bytes) {
494  OVERLAPPED stdout_overlapped = { 0 };
495  OVERLAPPED stderr_overlapped = { 0 };
496  ut64 timeout_us_abs = UT64_MAX;
497  if (timeout_ms != UT64_MAX) {
498  timeout_us_abs = rz_time_now_mono() + timeout_ms * RZ_USEC_PER_MSEC;
499  }
500 
501  char stdout_buf[BUFFER_SIZE + 1];
502  char stderr_buf[BUFFER_SIZE + 1];
503  bool stdout_enabled = (pipe_fd & RZ_SUBPROCESS_STDOUT) && proc->stdout_read;
504  bool stderr_enabled = (pipe_fd & RZ_SUBPROCESS_STDERR) && proc->stderr_read && proc->stderr_read != proc->stdout_read;
505  bool stdout_eof = false;
506  bool stderr_eof = false;
507  bool child_dead = false;
508  bool bytes_enabled = n_bytes != 0;
509 
510  if (stdout_enabled) {
511  stdout_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
512  if (!stdout_overlapped.hEvent) {
513  return RZ_SUBPROCESS_DEAD;
514  }
515  }
516  if (stderr_enabled) {
517  stderr_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
518  if (!stderr_overlapped.hEvent) {
519  CloseHandle(stdout_overlapped.hEvent);
520  return RZ_SUBPROCESS_DEAD;
521  }
522  }
523  if (stdout_enabled) {
524  stdout_eof = do_read(proc->stdout_read, stdout_buf, sizeof(stdout_buf) - 1, n_bytes, &stdout_overlapped);
525  }
526  if (stderr_enabled) {
527  stderr_eof = do_read(proc->stderr_read, stderr_buf, sizeof(stderr_buf) - 1, n_bytes, &stderr_overlapped);
528  }
529  DWORD timeout = timeout_us_abs == UT64_MAX
530  ? INFINITE
531  : (DWORD)(timeout_us_abs / RZ_USEC_PER_MSEC);
532  RzVector handles;
533  bool did_once = false;
534  rz_vector_init(&handles, sizeof(HANDLE), NULL, NULL);
535  while ((!bytes_enabled || n_bytes) && !child_dead) {
536  rz_vector_clear(&handles);
537  size_t stdout_index = 0;
538  size_t stderr_index = 0;
539  size_t proc_index = 0;
540  if (stdout_enabled && !stdout_eof) {
541  stdout_index = handles.len;
542  rz_vector_push(&handles, &stdout_overlapped.hEvent);
543  }
544  if (stderr_enabled && !stderr_eof) {
545  stderr_index = handles.len;
546  rz_vector_push(&handles, &stderr_overlapped.hEvent);
547  }
548  if (!child_dead) {
549  proc_index = handles.len;
550  rz_vector_push(&handles, &proc->proc);
551  }
552 
553  if (timeout_us_abs != UT64_MAX) {
554  ut64 now = rz_time_now_mono();
555  if (now >= timeout_us_abs) {
556  if (did_once) {
557  rz_vector_clear(&handles);
558  if (stdout_enabled) {
559  cancel_read(proc->stderr_read, &proc->out, stdout_buf, &stderr_overlapped);
560  }
561  if (stderr_enabled) {
562  cancel_read(proc->stderr_read, &proc->err, stderr_buf, &stderr_overlapped);
563  }
564  return RZ_SUBPROCESS_TIMEDOUT;
565  }
566  timeout = 0;
567  } else {
568  timeout = (DWORD)((timeout_us_abs - now) / RZ_USEC_PER_MSEC);
569  }
570  }
571  did_once = true;
572  DWORD signaled = WaitForMultipleObjects(handles.len, handles.a, FALSE, timeout);
573  if (stdout_enabled && !stdout_eof && signaled == stdout_index) {
574  DWORD r;
575  BOOL res = GetOverlappedResult(proc->stdout_read, &stdout_overlapped, &r, TRUE);
576  if (!res) {
577  stdout_eof = true;
578  continue;
579  }
580  rz_strbuf_append_n(&proc->out, (const char *)stdout_buf, r);
581  ResetEvent(stdout_overlapped.hEvent);
582  if (r >= 0 && n_bytes) {
583  n_bytes -= r;
584  if (n_bytes <= 0) {
585  break;
586  }
587  }
588  stdout_eof = do_read(proc->stdout_read, stdout_buf, sizeof(stdout_buf) - 1, n_bytes, &stdout_overlapped);
589  continue;
590  }
591  if (stderr_enabled && !stderr_eof && signaled == stderr_index) {
592  DWORD r;
593  BOOL res = GetOverlappedResult(proc->stderr_read, &stderr_overlapped, &r, TRUE);
594  if (!res) {
595  stderr_eof = true;
596  continue;
597  }
598  rz_strbuf_append_n(&proc->err, (const char *)stderr_buf, r);
599  if (r >= 0 && n_bytes) {
600  n_bytes -= r;
601  if (n_bytes <= 0) {
602  break;
603  }
604  }
605  ResetEvent(stderr_overlapped.hEvent);
606  stderr_eof = do_read(proc->stderr_read, stderr_buf, sizeof(stderr_buf) - 1, n_bytes, &stderr_overlapped);
607  continue;
608  }
609  if (!child_dead && signaled == proc_index) {
610  child_dead = true;
611  DWORD exit_code;
612  if (GetExitCodeProcess(proc->proc, &exit_code)) {
613  proc->ret = exit_code;
614  }
615  continue;
616  }
617  break;
618  }
619  rz_vector_clear(&handles);
620  if (stdout_overlapped.hEvent) {
621  CloseHandle(stdout_overlapped.hEvent);
622  }
623  if (stderr_overlapped.hEvent) {
624  CloseHandle(stderr_overlapped.hEvent);
625  }
626  return child_dead ? RZ_SUBPROCESS_DEAD : RZ_SUBPROCESS_BYTESREAD;
627 }
628 
630  CloseHandle(proc->stdin_write);
631  proc->stdin_write = NULL;
632  // Empty buffers and read everything we can
633  rz_strbuf_fini(&proc->out);
634  rz_strbuf_init(&proc->out);
635  rz_strbuf_fini(&proc->err);
636  rz_strbuf_init(&proc->err);
638 }
639 
641  TerminateProcess(proc->proc, 255);
642 }
643 
645  if (!proc->stdin_write) {
646  return -1;
647  }
648  DWORD read;
649  return WriteFile(proc->stdin_write, buf, buf_size, &read, NULL) ? buf_size : -1;
650 }
651 
653  rz_strbuf_fini(&proc->out);
654  rz_strbuf_init(&proc->out);
655  if (proc->stdout_read) {
657  }
658  return &proc->out;
659 }
660 
662  rz_strbuf_fini(&proc->out);
663  rz_strbuf_init(&proc->out);
664  if (proc->stdout_read) {
665  char c = '\0';
666  RzSubprocessWaitReason reason;
667  // FIXME: the timeout should also be checked globally here
668  do {
669  reason = subprocess_wait(proc, timeout_ms, RZ_SUBPROCESS_STDOUT, 1);
670  c = rz_strbuf_get(&proc->out)[rz_strbuf_length(&proc->out) - 1];
671  } while (c != '\n' && reason == RZ_SUBPROCESS_BYTESREAD);
672  }
673  return &proc->out;
674 }
675 
678  if (!out) {
679  return NULL;
680  }
681  out->out = rz_subprocess_out(proc, &out->out_len);
682  out->err = rz_subprocess_err(proc, &out->err_len);
683  out->ret = proc->ret;
684  return out;
685 }
686 
688  if (!proc) {
689  return;
690  }
691  if (proc->stdin_write) {
692  CloseHandle(proc->stdin_write);
693  }
694  if (proc->stderr_read && proc->stderr_read != proc->stdout_read) {
695  CloseHandle(proc->stderr_read);
696  }
697  if (proc->stdout_read) {
698  CloseHandle(proc->stdout_read);
699  }
700  CloseHandle(proc->proc);
701  free(proc);
702 }
703 #else // __WINDOWS__
704 
705 #include <errno.h>
706 #include <sys/wait.h>
707 
710  int stdin_fd;
713  int killpipe[2];
714  int ret;
717 };
718 
721 static int sigchld_pipe[2];
723 
724 static void subprocess_lock(void) {
726 }
727 
728 static void subprocess_unlock(void) {
730 }
731 
732 static void handle_sigchld(int sig) {
733  ut8 b = 1;
734  rz_xwrite(sigchld_pipe[1], &b, 1);
735 }
736 
737 static void *sigchld_th(void *th) {
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 }
786 
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 }
813 
815  rz_sys_signal(SIGCHLD, SIG_IGN);
816  ut8 b = 0;
817  rz_xwrite(sigchld_pipe[1], &b, 1);
824 }
825 
826 static char **create_child_env(const char *envvars[], const char *envvals[], size_t env_size) {
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 }
881 
882 static void destroy_child_env(char **child_env) {
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 }
892 
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 }
1054 
1055 static size_t read_to_strbuf(RzStrBuf *sb, int fd, bool *fd_eof, size_t n_bytes) {
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 }
1071 
1085 static RzSubprocessWaitReason subprocess_wait(RzSubprocess *proc, ut64 timeout_ms, int pipe_fd, size_t n_bytes) {
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 }
1177 
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 }
1198 
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 }
1216 
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 }
1233 
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 }
1255 
1257  kill(proc->pid, SIGKILL);
1258 }
1259 
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 }
1272 
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 }
1295 #endif
1296 
1298  return proc->ret;
1299 }
1300 
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 }
1311 
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 }
1322 
1324  if (!out) {
1325  return;
1326  }
1327  free(out->out);
1328  free(out->err);
1329  free(out);
1330 }
1331 
1346  const char *file, const char *args[], size_t args_size,
1347  const char *envvars[], const char *envvals[], size_t env_size) {
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 }
size_t len
Definition: 6502dis.c:15
#define rd()
lzma_index ** i
Definition: index.h:629
static SblHeader sb
Definition: bin_mbn.c:26
const lzma_allocator const uint8_t size_t uint8_t * out
Definition: block.h:528
#define SIGKILL
struct java_attribute_t Attribute
#define RZ_API
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static fork write
Definition: sflib.h:33
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 cmd
Definition: sflib.h:79
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
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
static int buf_size
Definition: debug_qnx.c:35
static int do_read(zip_t *z, const char *name, zip_flags_t flags, enum when when_ex, int ze_ex, int se_ex)
Definition: fread.c:168
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
#define INVALID_HANDLE_VALUE
Definition: iowin32.c:21
InterlockedDecrement
Definition: kernel.h:55
InterlockedIncrement
Definition: kernel.h:56
InterlockedCompareExchange
Definition: kernel.h:54
uint8_t ut8
Definition: lh5801.h:11
void * p
Definition: libc.cpp:67
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
RZ_API void rz_th_free(RZ_NULLABLE RzThread *th)
Frees a RzThread structure.
Definition: thread.c:246
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 bool rz_th_wait(RZ_NONNULL RzThread *th)
Awaits indefinetely for a thread to join.
Definition: thread.c:231
void * realloc(void *ptr, size_t size)
Definition: malloc.c:144
void * malloc(size_t size)
Definition: malloc.c:123
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 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
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
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 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
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")
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
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
int args
Definition: mipsasm.c:18
int n
Definition: mipsasm.c:19
#define TRUE
Definition: mybfd.h:103
#define FALSE
Definition: mybfd.h:102
#define rz_warn_if_reached()
Definition: rz_assert.h:29
RZ_API bool rz_file_exists(const char *str)
Definition: file.c:192
#define RZ_LOG_DEBUG(fmtstr,...)
Definition: rz_log.h:49
RZ_API char * rz_str_newf(const char *fmt,...) RZ_PRINTF_CHECK(1
RZ_API char RZ_API char * rz_str_newlen(const char *str, int len)
Definition: str.c:871
RZ_API char * rz_str_format_msvc_argv(size_t argc, const char **argv)
Definition: str.c:1844
RZ_API char * rz_strbuf_get(RzStrBuf *sb)
Definition: strbuf.c:321
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
RZ_API void rz_strbuf_init(RzStrBuf *sb)
Definition: strbuf.c:33
RZ_API int rz_strbuf_length(RzStrBuf *sb)
Definition: strbuf.c:28
RZ_API bool rz_strbuf_append_n(RzStrBuf *sb, const char *s, size_t l)
Definition: strbuf.c:229
#define RZ_SUBPROCESS_STDOUT
Definition: rz_subprocess.h:27
@ RZ_SUBPROCESS_TIMEDOUT
Definition: rz_subprocess.h:32
@ RZ_SUBPROCESS_BYTESREAD
Definition: rz_subprocess.h:33
@ RZ_SUBPROCESS_DEAD
Definition: rz_subprocess.h:31
enum rz_process_wait_reason_t RzSubprocessWaitReason
#define RZ_SUBPROCESS_STDERR
Definition: rz_subprocess.h:28
@ RZ_SUBPROCESS_PIPE_STDOUT
Definition: rz_subprocess.h:20
@ RZ_SUBPROCESS_PIPE_CREATE
Re-use the same pipe as stdout. It can be used for stderr only.
Definition: rz_subprocess.h:18
RZ_API void rz_sys_set_environ(char **e)
Definition: sys.c:1128
RZ_API int rz_sys_pipe(int pipefd[2], bool close_on_exec)
Definition: sys.c:1458
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_pipe_close(int fd)
Definition: sys.c:1462
RZ_API int rz_sys_execvp(const char *file, char *const argv[])
Definition: sys.c:1525
RZ_API int rz_sys_signal(int sig, void(*handler)(int))
Definition: sys.c:178
RZ_API char ** rz_sys_get_environ(void)
Definition: sys.c:1115
#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 RZ_NEWS(x, y)
Definition: rz_types.h:283
#define rz_sys_perror(x)
Definition: rz_types.h:336
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define RZ_NEW(x)
Definition: rz_types.h:285
#define rz_xwrite(fd, buf, count)
Definition: rz_types.h:642
#define RZ_NEWS0(x, y)
Definition: rz_types.h:282
#define UT64_MAX
Definition: rz_types_base.h:86
RZ_API void rz_pvector_remove_data(RzPVector *vec, void *x)
Definition: vector.c:362
RZ_API void rz_pvector_init(RzPVector *vec, RzPVectorFree free)
Definition: vector.c:298
RZ_API void * rz_vector_push(RzVector *vec, void *x)
Definition: vector.c:197
static void ** rz_pvector_push(RzPVector *vec, void *x)
Definition: rz_vector.h:300
RZ_API void * rz_vector_insert_range(RzVector *vec, size_t index, void *first, size_t count)
Definition: vector.c:167
RZ_API void rz_vector_clear(RzVector *vec)
Definition: vector.c:68
RZ_API void rz_vector_init(RzVector *vec, size_t elem_size, RzVectorFree free, void *free_user)
Definition: vector.c:33
RZ_API void rz_pvector_clear(RzPVector *vec)
Definition: vector.c:326
#define rz_pvector_foreach(vec, it)
Definition: rz_vector.h:334
#define FD_ZERO(set)
Definition: sftypes.h:204
#define FD_ISSET(d, set)
Definition: sftypes.h:214
#define O_NONBLOCK
Definition: sftypes.h:494
#define FD_SET(d, set)
Definition: sftypes.h:212
#define EINTR
Definition: sftypes.h:114
int pid_t
Definition: sftypes.h:38
#define F_SETFL
Definition: sftypes.h:507
int ssize_t
Definition: sftypes.h:39
#define b(i)
Definition: sha256.c:42
#define f(i)
Definition: sha256.c:46
#define c(i)
Definition: sha256.c:43
#define SIZE_MAX
Definition: malloc.c:26
Definition: gzappend.c:170
Definition: z80asm.h:102
size_t env_size
Specify how to deal with subprocess stdin.
Definition: rz_subprocess.h:69
const char * file
< Name of the executable to run. It is searched also in PATH
Definition: rz_subprocess.h:59
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
RzStrBuf err
Definition: subprocess.c:716
RzStrBuf out
Definition: subprocess.c:715
Definition: thread.h:84
void * a
Definition: rz_vector.h:46
size_t len
Definition: rz_vector.h:47
long tv_sec
Definition: sftypes.h:84
long tv_usec
Definition: sftypes.h:85
RZ_API RzSubprocessOutput * rz_subprocess_drain(RzSubprocess *proc)
Definition: subprocess.c:1260
RZ_API RzSubprocessWaitReason rz_subprocess_wait(RzSubprocess *proc, ut64 timeout_ms)
Definition: subprocess.c:1185
static RzThreadLock * subprocs_mutex
Definition: subprocess.c:720
static size_t read_to_strbuf(RzStrBuf *sb, int fd, bool *fd_eof, size_t n_bytes)
Definition: subprocess.c:1055
static void * sigchld_th(void *th)
Definition: subprocess.c:737
RZ_API void rz_subprocess_free(RzSubprocess *proc)
Definition: subprocess.c:1273
RZ_API ut8 * rz_subprocess_out(RzSubprocess *proc, int *length)
Definition: subprocess.c:1301
static char ** create_child_env(const char *envvars[], const char *envvals[], size_t env_size)
Definition: subprocess.c:826
static RzThread * sigchld_thread
Definition: subprocess.c:722
RZ_API RzSubprocess * rz_subprocess_start_opt(RzSubprocessOpt *opt)
Definition: subprocess.c:893
RZ_API void rz_subprocess_fini(void)
Definition: subprocess.c:814
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)
Definition: subprocess.c:1345
RZ_API void rz_subprocess_output_free(RzSubprocessOutput *out)
Definition: subprocess.c:1323
#define BUFFER_SIZE
Definition: subprocess.c:8
static void destroy_child_env(char **child_env)
Definition: subprocess.c:882
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
RZ_API ut8 * rz_subprocess_err(RzSubprocess *proc, int *length)
Definition: subprocess.c:1312
RZ_API ssize_t rz_subprocess_stdin_write(RzSubprocess *proc, const ut8 *buf, size_t buf_size)
Definition: subprocess.c:1206
static RzPVector subprocs
Definition: subprocess.c:719
RZ_API bool rz_subprocess_init(void)
Definition: subprocess.c:787
RZ_API RzStrBuf * rz_subprocess_stdout_read(RzSubprocess *proc, size_t n, ut64 timeout_ms)
Definition: subprocess.c:1225
static int sigchld_pipe[2]
Definition: subprocess.c:721
static void subprocess_unlock(void)
Definition: subprocess.c:728
RZ_API int rz_subprocess_ret(RzSubprocess *proc)
Definition: subprocess.c:1297
RZ_API void rz_subprocess_kill(RzSubprocess *proc)
Definition: subprocess.c:1256
RZ_API RzStrBuf * rz_subprocess_stdout_readline(RzSubprocess *proc, ut64 timeout_ms)
Definition: subprocess.c:1241
static void handle_sigchld(int sig)
Definition: subprocess.c:732
static void subprocess_lock(void)
Definition: subprocess.c:724
uv_pipe_t stdin_pipe
Definition: main.c:15
uv_pipe_t stdout_pipe
Definition: main.c:16
uv_timer_t timeout
Definition: main.c:9
char ** environ
struct Proc * proc
#define STDOUT_FILENO
Definition: private.h:41
#define STDERR_FILENO
Definition: private.h:45
#define STDIN_FILENO
Definition: private.h:37
static char ** env
Definition: sys.c:32
RZ_API void rz_th_lock_leave(RZ_NONNULL RzThreadLock *thl)
Releases a RzThreadLock structure.
Definition: thread_lock.c:75
RZ_API void rz_th_lock_free(RZ_NULLABLE RzThreadLock *thl)
Frees a RzThreadLock structure.
Definition: thread_lock.c:89
RZ_API RZ_OWN RzThreadLock * rz_th_lock_new(bool recursive)
Allocates and initialize a RzThreadLock structure.
Definition: thread_lock.c:14
RZ_API void rz_th_lock_enter(RZ_NONNULL RzThreadLock *thl)
Acquires a RzThreadLock structure.
Definition: thread_lock.c:45
static void lock(volatile int *lk)
Definition: malloc.c:61
void error(const char *msg)
Definition: untgz.c:593
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
DWORD LPWSTR
DWORD * HANDLE
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
PVOID
DWORD
static const z80_opcode fd[]
Definition: z80_tab.h:997
static int file
Definition: z80asm.c:58
#define L
Definition: zip_err_str.c:7
int read(izstream &zs, T *x, Items items)
Definition: zstream.h:115