/src/rt/rust_run_program.cpp

http://github.com/jruderman/rust · C++ · 198 lines · 190 code · 5 blank · 3 comment · 5 complexity · 7c4076639d90e2174bded654ddc77452 MD5 · raw file

  1. #include "rust_kernel.h"
  2. #ifdef __APPLE__
  3. #include <crt_externs.h>
  4. #endif
  5. #if defined(__WIN32__)
  6. #include <process.h>
  7. #include <io.h>
  8. bool backslash_run_ends_in_quote(char const *c) {
  9. while (*c == '\\') ++c;
  10. return *c == '"';
  11. }
  12. void append_first_char(char *&buf, char const *c) {
  13. switch (*c) {
  14. case '"':
  15. // Escape quotes.
  16. *buf++ = '\\';
  17. *buf++ = '"';
  18. break;
  19. case '\\':
  20. if (backslash_run_ends_in_quote(c)) {
  21. // Double all backslashes that are in runs before quotes.
  22. *buf++ = '\\';
  23. *buf++ = '\\';
  24. } else {
  25. // Pass other backslashes through unescaped.
  26. *buf++ = '\\';
  27. }
  28. break;
  29. default:
  30. *buf++ = *c;
  31. }
  32. }
  33. bool contains_whitespace(char const *arg) {
  34. while (*arg) {
  35. switch (*arg++) {
  36. case ' ':
  37. case '\t':
  38. return true;
  39. }
  40. }
  41. return false;
  42. }
  43. void append_arg(char *& buf, char const *arg, bool last) {
  44. bool quote = contains_whitespace(arg);
  45. if (quote)
  46. *buf++ = '"';
  47. while (*arg)
  48. append_first_char(buf, arg++);
  49. if (quote)
  50. *buf++ = '"';
  51. if (! last) {
  52. *buf++ = ' ';
  53. } else {
  54. *buf++ = '\0';
  55. }
  56. }
  57. extern "C" CDECL int
  58. rust_run_program(const char* argv[],
  59. void* envp,
  60. const char* dir,
  61. int in_fd, int out_fd, int err_fd) {
  62. STARTUPINFO si;
  63. ZeroMemory(&si, sizeof(STARTUPINFO));
  64. si.cb = sizeof(STARTUPINFO);
  65. si.dwFlags = STARTF_USESTDHANDLES;
  66. HANDLE curproc = GetCurrentProcess();
  67. HANDLE origStdin = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0);
  68. if (!DuplicateHandle(curproc, origStdin,
  69. curproc, &si.hStdInput, 0, 1, DUPLICATE_SAME_ACCESS))
  70. return -1;
  71. HANDLE origStdout = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1);
  72. if (!DuplicateHandle(curproc, origStdout,
  73. curproc, &si.hStdOutput, 0, 1, DUPLICATE_SAME_ACCESS))
  74. return -1;
  75. HANDLE origStderr = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2);
  76. if (!DuplicateHandle(curproc, origStderr,
  77. curproc, &si.hStdError, 0, 1, DUPLICATE_SAME_ACCESS))
  78. return -1;
  79. size_t cmd_len = 0;
  80. for (const char** arg = argv; *arg; arg++) {
  81. cmd_len += strlen(*arg);
  82. cmd_len += 3; // Two quotes plus trailing space or \0
  83. }
  84. cmd_len *= 2; // Potentially backslash-escape everything.
  85. char* cmd = (char*)malloc(cmd_len);
  86. char* pos = cmd;
  87. for (const char** arg = argv; *arg; arg++) {
  88. append_arg(pos, *arg, *(arg+1) == NULL);
  89. }
  90. PROCESS_INFORMATION pi;
  91. BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE,
  92. 0, envp, dir, &si, &pi);
  93. CloseHandle(si.hStdInput);
  94. CloseHandle(si.hStdOutput);
  95. CloseHandle(si.hStdError);
  96. free(cmd);
  97. if (!created) return -1;
  98. return (int)pi.hProcess;
  99. }
  100. extern "C" CDECL int
  101. rust_process_wait(int proc) {
  102. DWORD status;
  103. while (true) {
  104. if (GetExitCodeProcess((HANDLE)proc, &status) &&
  105. status != STILL_ACTIVE)
  106. return (int)status;
  107. WaitForSingleObject((HANDLE)proc, INFINITE);
  108. }
  109. }
  110. #elif defined(__GNUC__)
  111. #include <sys/file.h>
  112. #include <signal.h>
  113. #include <sys/ioctl.h>
  114. #include <unistd.h>
  115. #include <termios.h>
  116. #ifdef __FreeBSD__
  117. extern char **environ;
  118. #endif
  119. extern "C" CDECL int
  120. rust_run_program(const char* argv[],
  121. void* envp,
  122. const char* dir,
  123. int in_fd, int out_fd, int err_fd) {
  124. int pid = fork();
  125. if (pid != 0) return pid;
  126. sigset_t sset;
  127. sigemptyset(&sset);
  128. sigprocmask(SIG_SETMASK, &sset, NULL);
  129. if (in_fd) dup2(in_fd, 0);
  130. if (out_fd) dup2(out_fd, 1);
  131. if (err_fd) dup2(err_fd, 2);
  132. /* Close all other fds. */
  133. for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd);
  134. if (dir) {
  135. int result = chdir(dir);
  136. // FIXME (#2674): need error handling
  137. assert(!result && "chdir failed");
  138. }
  139. if (envp) {
  140. #ifdef __APPLE__
  141. *_NSGetEnviron() = (char **)envp;
  142. #else
  143. environ = (char **)envp;
  144. #endif
  145. }
  146. execvp(argv[0], (char * const *)argv);
  147. exit(1);
  148. }
  149. extern "C" CDECL int
  150. rust_process_wait(int proc) {
  151. // FIXME: stub; exists to placate linker. (#2692)
  152. return 0;
  153. }
  154. #else
  155. #error "Platform not supported."
  156. #endif
  157. //
  158. // Local Variables:
  159. // mode: C++
  160. // fill-column: 78;
  161. // indent-tabs-mode: nil
  162. // c-basic-offset: 4
  163. // buffer-file-coding-system: utf-8-unix
  164. // compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
  165. // End:
  166. //