freeprocess.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. // freeprocess.c
  2. #include <brl.mod/blitz.mod/blitz.h>
  3. #include <stdio.h>
  4. #define HIDECONSOLE 1
  5. #define SHOWCONSOLE 2
  6. #if __APPLE__ || __linux__ || __HAIKU__
  7. #include <sys/ioctl.h>
  8. #include <unistd.h>
  9. #include <sys/wait.h>
  10. #include <signal.h>
  11. int fdClose(size_t fd) {return close(fd);}
  12. BBLONG fdRead(size_t fd,char *buffer,BBLONG count) {return read(fd,buffer,count);}
  13. BBLONG fdWrite(size_t fd,char *buffer,BBLONG count) {return write(fd,buffer,count);}
  14. int fdAvail(size_t fd) {int avail;if (ioctl(fd,FIONREAD,&avail)) avail=avail;return avail;}
  15. int fdFlush(size_t fd) { return 0;}//flush(fd);}
  16. ///return 1 for running, 0 for finished
  17. //
  18. int fdProcessStatus( size_t pid ){
  19. int status=0;
  20. return !waitpid( pid,&status,WNOHANG );
  21. }
  22. //returns 0 for success, -1 for error
  23. //
  24. int fdTerminateProcess(size_t pid){
  25. if( !killpg( pid,SIGTERM ) ){
  26. int status=0;
  27. waitpid( pid,&status,0 );
  28. return 0;
  29. }
  30. return -1;
  31. }
  32. //returns 0 for success, -1 for error
  33. //
  34. int fdKillProcess(size_t pid){
  35. if( !killpg( pid,SIGKILL ) ){
  36. int status=0;
  37. waitpid( pid,&status,0 );
  38. return 0;
  39. }
  40. return -1;
  41. }
  42. static char **makeargv( const char *cmd ){
  43. int n,c;
  44. char *p;
  45. static char *args,**argv;
  46. if( args ) free( args );
  47. if( argv ) free( argv );
  48. args=(char*)malloc( strlen(cmd)+1 );
  49. strcpy( args,cmd );
  50. n=0;
  51. p=args;
  52. while( c=*p++ ){
  53. if( c==' ' ){
  54. continue;
  55. }else if( c=='\"' ){
  56. while( *p && *p!='\"' ) ++p;
  57. }else{
  58. while( *p && *p!=' ' ) ++p;
  59. }
  60. if( *p ) ++p;
  61. ++n;
  62. }
  63. argv=(char**)malloc( (n+1)*sizeof(char*) );
  64. n=0;
  65. p=args;
  66. while( c=*p++ ){
  67. if( c==' ' ){
  68. continue;
  69. }else if( c=='\"' ){
  70. argv[n]=p;
  71. while( *p && *p!='\"' ) ++p;
  72. }else{
  73. argv[n]=p-1;
  74. while( *p && *p!=' ' ) ++p;
  75. }
  76. if( *p ) *p++=0;
  77. ++n;
  78. }
  79. argv[n]=0;
  80. return argv;
  81. }
  82. #define PIPEREAD 0
  83. #define PIPEWRITE 1
  84. static int in[2],out[2],errfd[2];
  85. size_t fdProcess( BBString *bbcmd,size_t *procin,size_t *procout,size_t *procerr,int flags)
  86. {
  87. char *const*argv;
  88. int procid;
  89. //Set-up interprocess communication
  90. if (pipe(in)) return 0;
  91. if (pipe(out)) return 0;
  92. if (pipe(errfd)) return 0;
  93. //Fork process (returned value used to distinguish between child and parent process)
  94. procid=vfork(); //vfork() avoids memory overhead of fork()
  95. //Child process
  96. if (procid==0)
  97. {
  98. #if __linux__
  99. setsid(); //Linux doesn't mind setsid()
  100. #else
  101. setpgid(0,0); //but OS X doesn't like it, therefore resort to using setpgid().
  102. #endif
  103. dup2(out[PIPEREAD],STDIN_FILENO);
  104. close(out[PIPEWRITE]);
  105. dup2(in[PIPEWRITE],STDOUT_FILENO);
  106. close(in[PIPEREAD]);
  107. dup2(errfd[PIPEWRITE],STDERR_FILENO);
  108. close(errfd[PIPEREAD]);
  109. const char *cmd=bbStringToUTF8String(bbcmd);
  110. argv=makeargv(cmd);
  111. bbMemFree(cmd);
  112. execvp(argv[0],argv);
  113. _exit( -1 );
  114. return 0; //Supposedly, we need this for some compilers.
  115. }
  116. //Parent process
  117. if(procid==-1) return 0; //Return if child process couldn't be started.
  118. close(out[PIPEREAD]); //Close the end of the pipes in that the child
  119. close(in[PIPEWRITE]); //process is using.
  120. close(errfd[PIPEWRITE]);
  121. *procin=in[PIPEREAD]; //And return the end of the pipes that we should
  122. *procout=out[PIPEWRITE]; //be using.
  123. *procerr=errfd[PIPEREAD];
  124. return procid;
  125. }
  126. #endif
  127. #ifdef _WIN32
  128. extern int _bbusew;
  129. //#define WIN32_LEAN_AND_MEAN
  130. #include <windows.h>
  131. #include <tlhelp32.h>
  132. // In the Windows world "TerminateProcess" kills a process without
  133. // gracefully asking to stop I/O and other operations first.
  134. // So there is a name clash between Linux' SIGKILL and Windows' TERMINATE
  135. int KillProcessGroup(HANDLE prochandle,int procid)
  136. {
  137. HANDLE snapshot,child;
  138. PROCESSENTRY32 procinfo;
  139. int gotinfo,res;
  140. snapshot=CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
  141. if (snapshot!=INVALID_HANDLE_VALUE)
  142. {
  143. procinfo.dwSize=sizeof(procinfo);
  144. gotinfo=Process32First(snapshot,&procinfo);
  145. while (gotinfo)
  146. {
  147. if (procinfo.th32ParentProcessID==procid)
  148. {
  149. // printf("process=%x parent=%x module=%x path=%s\n",procinfo.th32ProcessID,procinfo.th32ParentProcessID,procinfo.th32ModuleID,procinfo.szExeFile);
  150. child=OpenProcess(PROCESS_ALL_ACCESS,0,procinfo.th32ProcessID);
  151. if (child)
  152. {
  153. res=TerminateProcess(child,-1);
  154. CloseHandle(child);
  155. }
  156. }
  157. gotinfo=Process32Next(snapshot,&procinfo);
  158. }
  159. CloseHandle(snapshot);
  160. }
  161. res=TerminateProcess(prochandle,-1);
  162. return res;
  163. }
  164. int TerminateProcessGroup(HANDLE prochandle,int procid)
  165. {
  166. //for now we just do a kill instead of politely asking all
  167. //sub-windows (gui only) to gracefully end.
  168. return KillProcessGroup(prochandle, procid);
  169. }
  170. int fdClose(size_t fd)
  171. {
  172. return CloseHandle((HANDLE)fd);
  173. }
  174. BBLONG fdRead(size_t fd,char *buffer,BBLONG bytes)
  175. {
  176. int res;
  177. DWORD count;
  178. res=ReadFile((HANDLE)fd,buffer,bytes,&count,0);
  179. if (res) return count;
  180. return 0;
  181. }
  182. BBLONG fdWrite(size_t fd,char *buffer,BBLONG bytes)
  183. {
  184. int res;
  185. DWORD count;
  186. res=WriteFile((HANDLE)fd,buffer,bytes,&count,0);
  187. if (res) return count;
  188. return 0;
  189. }
  190. int fdFlush(size_t fd)
  191. {
  192. int res;
  193. res=FlushFileBuffers((HANDLE)fd);
  194. return res;
  195. }
  196. int fdAvail(size_t fd)
  197. {
  198. int res;
  199. DWORD avail;
  200. res=PeekNamedPipe((HANDLE)fd,0,0,0,&avail,0);
  201. if (res) return avail;
  202. return 0;
  203. }
  204. //returns 1 for running, 0 for finished
  205. int fdProcessStatus( PROCESS_INFORMATION * pi ){
  206. DWORD exitcode;
  207. if( GetExitCodeProcess( pi->hProcess,&exitcode ) ){
  208. if( exitcode==STILL_ACTIVE ) return 1;
  209. CloseHandle( pi->hProcess );
  210. free( pi );
  211. }
  212. return 0;
  213. }
  214. //returns 0 for success
  215. int fdTerminateProcess( PROCESS_INFORMATION * pi ){
  216. int res=TerminateProcessGroup( pi->hProcess,pi->dwProcessId );
  217. CloseHandle( pi->hProcess );
  218. free( pi );
  219. return res;
  220. }
  221. //returns 0 for success
  222. int fdKillProcess( PROCESS_INFORMATION * pi ){
  223. int res=KillProcessGroup( pi->hProcess,pi->dwProcessId );
  224. CloseHandle( pi->hProcess );
  225. free( pi );
  226. return res;
  227. }
  228. PROCESS_INFORMATION * fdProcess( BBString *cmd,size_t *procin,size_t *procout,size_t *procerr,int flags)
  229. {
  230. int res;
  231. int pflags=CREATE_NEW_PROCESS_GROUP;
  232. PROCESS_INFORMATION *pi;
  233. SECURITY_ATTRIBUTES sa={sizeof(sa),0,1};
  234. HANDLE istr,p_ostr; //our in-stream, process out-stream
  235. HANDLE ostr,p_istr; //our out-stream, process in-stream
  236. HANDLE estr,p_estr; //our errin-stream, process errout-stream
  237. if( !CreatePipe( &istr,&p_ostr,&sa,0 ) ){
  238. //unable to create pipe
  239. return 0;
  240. }
  241. if( !CreatePipe( &p_istr,&ostr,&sa,0 ) ){
  242. CloseHandle( istr );
  243. CloseHandle( p_ostr );
  244. //ditto
  245. return 0;
  246. }
  247. if (!CreatePipe(&estr,&p_estr,&sa,0)) {
  248. CloseHandle( istr );
  249. CloseHandle( p_ostr );
  250. CloseHandle( ostr );
  251. CloseHandle( p_istr );
  252. //unable to create pipe
  253. return 0;
  254. }
  255. pi=(PROCESS_INFORMATION*)calloc(1,sizeof(PROCESS_INFORMATION));
  256. if( _bbusew ){
  257. STARTUPINFOW si;
  258. ZeroMemory( &si, sizeof(si) );
  259. si.cb = sizeof(si);
  260. si.dwFlags=STARTF_USESTDHANDLES;
  261. si.wShowWindow=SW_HIDE;
  262. si.hStdInput=p_istr;
  263. si.hStdOutput=p_ostr;
  264. si.hStdError=p_estr;
  265. if (flags&HIDECONSOLE) {
  266. pflags|=CREATE_NO_WINDOW;
  267. }
  268. else if (flags&SHOWCONSOLE) {
  269. pflags|=CREATE_NEW_CONSOLE;
  270. }
  271. else {
  272. pflags|=DETACHED_PROCESS;
  273. }
  274. BBChar *c = bbStringToWString(cmd);
  275. res=CreateProcessW( 0,c,0,0,-1,pflags,0,0,&si,pi );
  276. bbMemFree(c);
  277. }else{
  278. STARTUPINFO si;
  279. ZeroMemory( &si, sizeof(si) );
  280. si.cb = sizeof(si);
  281. si.dwFlags=STARTF_USESTDHANDLES;
  282. si.wShowWindow=SW_HIDE;
  283. si.hStdInput=p_istr;
  284. si.hStdOutput=p_ostr;
  285. si.hStdError=p_estr;
  286. if (flags&HIDECONSOLE) {
  287. pflags|=CREATE_NO_WINDOW;
  288. }
  289. else if (flags&SHOWCONSOLE) {
  290. pflags|=CREATE_NEW_CONSOLE;
  291. }
  292. else {
  293. pflags|=DETACHED_PROCESS;
  294. }
  295. char *c=(char *)bbStringToUTF8String( cmd );
  296. res=CreateProcess( 0,c,0,0,-1,pflags,0,0,&si,pi );
  297. bbMemFree(c);
  298. }
  299. if( !res ){
  300. CloseHandle( istr );
  301. CloseHandle( ostr );
  302. CloseHandle( estr );
  303. CloseHandle( p_istr );
  304. CloseHandle( p_ostr );
  305. CloseHandle( p_estr );
  306. return 0;
  307. }
  308. CloseHandle( pi->hThread );
  309. *procin=(size_t)istr;
  310. *procout=(size_t)ostr;
  311. *procerr=(size_t)estr;
  312. CloseHandle( p_istr );
  313. CloseHandle( p_ostr );
  314. CloseHandle( p_estr );
  315. return pi;
  316. }
  317. #endif