PageRenderTime 26ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ssfossil/fossil/src/popen.c

https://github.com/paulfitz/coopy
C | 187 lines | 130 code | 11 blank | 46 comment | 7 complexity | a266e1183d329d7e682bc7159be35663 MD5 | raw file
  1. /*
  2. ** Copyright (c) 2010 D. Richard Hipp
  3. **
  4. ** This program is free software; you can redistribute it and/or
  5. ** modify it under the terms of the Simplified BSD License (also
  6. ** known as the "2-Clause License" or "FreeBSD License".)
  7. ** This program is distributed in the hope that it will be useful,
  8. ** but without any warranty; without even the implied warranty of
  9. ** merchantability or fitness for a particular purpose.
  10. **
  11. ** Author contact information:
  12. ** drh@hwaci.com
  13. ** http://www.hwaci.com/drh/
  14. **
  15. *******************************************************************************
  16. **
  17. ** This file contains an implementation of a bi-directional popen().
  18. */
  19. #include "config.h"
  20. #include "popen.h"
  21. #ifdef _WIN32
  22. #include <windows.h>
  23. #include <fcntl.h>
  24. /*
  25. ** Print a fatal error and quit.
  26. */
  27. static void win32_fatal_error(const char *zMsg){
  28. fossil_fatal("%s");
  29. }
  30. #endif
  31. #ifdef _WIN32
  32. /*
  33. ** On windows, create a child process and specify the stdin, stdout,
  34. ** and stderr channels for that process to use.
  35. **
  36. ** Return the number of errors.
  37. */
  38. static int win32_create_child_process(
  39. char *zCmd, /* The command that the child process will run */
  40. HANDLE hIn, /* Standard input */
  41. HANDLE hOut, /* Standard output */
  42. HANDLE hErr, /* Standard error */
  43. DWORD *pChildPid /* OUT: Child process handle */
  44. ){
  45. STARTUPINFO si;
  46. PROCESS_INFORMATION pi;
  47. BOOL rc;
  48. memset(&si, 0, sizeof(si));
  49. si.cb = sizeof(si);
  50. si.dwFlags = STARTF_USESTDHANDLES;
  51. SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, TRUE);
  52. si.hStdInput = hIn;
  53. SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, TRUE);
  54. si.hStdOutput = hOut;
  55. SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, TRUE);
  56. si.hStdError = hErr;
  57. rc = CreateProcess(
  58. NULL, /* Application Name */
  59. zCmd, /* Command-line */
  60. NULL, /* Process attributes */
  61. NULL, /* Thread attributes */
  62. TRUE, /* Inherit Handles */
  63. 0, /* Create flags */
  64. NULL, /* Environment */
  65. NULL, /* Current directory */
  66. &si, /* Startup Info */
  67. &pi /* Process Info */
  68. );
  69. if( rc ){
  70. CloseHandle( pi.hProcess );
  71. CloseHandle( pi.hThread );
  72. *pChildPid = pi.dwProcessId;
  73. }else{
  74. win32_fatal_error("cannot create child process");
  75. }
  76. return rc!=0;
  77. }
  78. #endif
  79. /*
  80. ** Create a child process running shell command "zCmd". *ppOut is
  81. ** a FILE that becomes the standard input of the child process.
  82. ** (The caller writes to *ppOut in order to send text to the child.)
  83. ** *ppIn is stdout from the child process. (The caller
  84. ** reads from *ppIn in order to receive input from the child.)
  85. ** Note that *ppIn is an unbuffered file descriptor, not a FILE.
  86. ** The process ID of the child is written into *pChildPid.
  87. **
  88. ** Return the number of errors.
  89. */
  90. int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
  91. #ifdef _WIN32
  92. HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
  93. SECURITY_ATTRIBUTES saAttr;
  94. DWORD childPid = 0;
  95. int fd;
  96. saAttr.nLength = sizeof(saAttr);
  97. saAttr.bInheritHandle = TRUE;
  98. saAttr.lpSecurityDescriptor = NULL;
  99. hStderr = GetStdHandle(STD_ERROR_HANDLE);
  100. if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
  101. win32_fatal_error("cannot create pipe for stdout");
  102. }
  103. SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
  104. if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
  105. win32_fatal_error("cannot create pipe for stdin");
  106. }
  107. SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
  108. win32_create_child_process((char*)zCmd,
  109. hStdinRd, hStdoutWr, hStderr,&childPid);
  110. *pChildPid = childPid;
  111. *pfdIn = _open_osfhandle((long)hStdoutRd, 0);
  112. fd = _open_osfhandle((long)hStdinWr, 0);
  113. *ppOut = _fdopen(fd, "w");
  114. CloseHandle(hStdinRd);
  115. CloseHandle(hStdoutWr);
  116. return 0;
  117. #else
  118. int pin[2], pout[2];
  119. *pfdIn = 0;
  120. *ppOut = 0;
  121. *pChildPid = 0;
  122. if( pipe(pin)<0 ){
  123. return 1;
  124. }
  125. if( pipe(pout)<0 ){
  126. close(pin[0]);
  127. close(pin[1]);
  128. return 1;
  129. }
  130. *pChildPid = fork();
  131. if( *pChildPid<0 ){
  132. close(pin[0]);
  133. close(pin[1]);
  134. close(pout[0]);
  135. close(pout[1]);
  136. *pChildPid = 0;
  137. return 1;
  138. }
  139. if( *pChildPid==0 ){
  140. /* This is the child process */
  141. close(0);
  142. dup(pout[0]);
  143. close(pout[0]);
  144. close(pout[1]);
  145. close(1);
  146. dup(pin[1]);
  147. close(pin[0]);
  148. close(pin[1]);
  149. execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
  150. return 1;
  151. }else{
  152. /* This is the parent process */
  153. close(pin[1]);
  154. *pfdIn = pin[0];
  155. close(pout[0]);
  156. *ppOut = fdopen(pout[1], "w");
  157. return 0;
  158. }
  159. #endif
  160. }
  161. /*
  162. ** Close the connection to a child process previously created using
  163. ** popen2(). Kill off the child process, then close the pipes.
  164. */
  165. void pclose2(int fdIn, FILE *pOut, int childPid){
  166. #ifdef _WIN32
  167. /* Not implemented, yet */
  168. close(fdIn);
  169. fclose(pOut);
  170. #else
  171. close(fdIn);
  172. fclose(pOut);
  173. kill(childPid, SIGINT);
  174. #endif
  175. }