process.inc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2008 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. Const
  11. PriorityConstants : Array [TProcessPriority] of Integer =
  12. (20,20,0,-20);
  13. Const
  14. GeometryOption : String = '-geometry';
  15. TitleOption : String ='-title';
  16. procedure TProcess.CloseProcessHandles;
  17. begin
  18. // Do nothing. Win32 call.
  19. end;
  20. Function TProcess.PeekExitStatus : Boolean;
  21. var
  22. res: cint;
  23. begin
  24. repeat
  25. res:=fpWaitPid(Handle,pcint(@FExitCode),WNOHANG);
  26. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  27. result:=res=Handle;
  28. If Result then
  29. FExitCode:=wexitstatus(FExitCode)
  30. else
  31. FexitCode:=0;
  32. end;
  33. Type
  34. TPCharArray = Array[Word] of pchar;
  35. PPCharArray = ^TPcharArray;
  36. Function StringsToPCharList(List : TStrings) : PPChar;
  37. Var
  38. I : Integer;
  39. S : String;
  40. begin
  41. I:=(List.Count)+1;
  42. GetMem(Result,I*sizeOf(PChar));
  43. PPCharArray(Result)^[List.Count]:=Nil;
  44. For I:=0 to List.Count-1 do
  45. begin
  46. S:=List[i];
  47. Result[i]:=StrNew(PChar(S));
  48. end;
  49. end;
  50. Procedure FreePCharList(List : PPChar);
  51. Var
  52. I : integer;
  53. begin
  54. I:=0;
  55. While List[i]<>Nil do
  56. begin
  57. StrDispose(List[i]);
  58. Inc(I);
  59. end;
  60. FreeMem(List);
  61. end;
  62. Procedure CommandToList(S : String; List : TStrings);
  63. Function GetNextWord : String;
  64. Const
  65. WhiteSpace = [' ',#8,#10];
  66. Literals = ['"',''''];
  67. Var
  68. Wstart,wend : Integer;
  69. InLiteral : Boolean;
  70. LastLiteral : char;
  71. begin
  72. WStart:=1;
  73. While (WStart<=Length(S)) and (S[WStart] in WhiteSpace) do
  74. Inc(WStart);
  75. WEnd:=WStart;
  76. InLiteral:=False;
  77. LastLiteral:=#0;
  78. While (Wend<=Length(S)) and (Not (S[Wend] in WhiteSpace) or InLiteral) do
  79. begin
  80. if S[Wend] in Literals then
  81. If InLiteral then
  82. InLiteral:=Not (S[Wend]=LastLiteral)
  83. else
  84. begin
  85. InLiteral:=True;
  86. LastLiteral:=S[Wend];
  87. end;
  88. inc(wend);
  89. end;
  90. Result:=Copy(S,WStart,WEnd-WStart);
  91. if (Length(Result) > 0)
  92. and (Result[1] = Result[Length(Result)]) // if 1st char = last char and..
  93. and (Result[1] in Literals) then // it's one of the literals, then
  94. Result:=Copy(Result, 2, Length(Result) - 2); //delete the 2 (but not others in it)
  95. While (WEnd<=Length(S)) and (S[Wend] in WhiteSpace) do
  96. inc(Wend);
  97. Delete(S,1,WEnd-1);
  98. end;
  99. Var
  100. W : String;
  101. begin
  102. While Length(S)>0 do
  103. begin
  104. W:=GetNextWord;
  105. If (W<>'') then
  106. List.Add(W);
  107. end;
  108. end;
  109. Function MakeCommand(P : TProcess) : PPchar;
  110. {$ifdef darwin}
  111. Const
  112. TerminalApp = 'open';
  113. {$endif}
  114. {$ifdef haiku}
  115. Const
  116. TerminalApp = 'Terminal';
  117. {$endif}
  118. Var
  119. Cmd : String;
  120. S : TStringList;
  121. G : String;
  122. begin
  123. if (P.ApplicationName='') then
  124. begin
  125. If (P.CommandLine='') then
  126. Raise EProcess.Create(SNoCommandline);
  127. Cmd:=P.CommandLine;
  128. end
  129. else
  130. begin
  131. If (P.CommandLine='') then
  132. Cmd:=P.ApplicationName
  133. else
  134. Cmd:=P.CommandLine;
  135. end;
  136. S:=TStringList.Create;
  137. try
  138. CommandToList(Cmd,S);
  139. if poNewConsole in P.Options then
  140. begin
  141. {$ifdef haiku}
  142. If (P.ApplicationName<>'') then
  143. begin
  144. S.Insert(0,P.ApplicationName);
  145. S.Insert(0,'--title');
  146. end;
  147. {$endif}
  148. {$if defined(darwin) or defined(haiku)}
  149. S.Insert(0,TerminalApp);
  150. {$else}
  151. S.Insert(0,'-e');
  152. If (P.ApplicationName<>'') then
  153. begin
  154. S.Insert(0,P.ApplicationName);
  155. S.Insert(0,'-title');
  156. end;
  157. if suoUseCountChars in P.StartupOptions then
  158. begin
  159. S.Insert(0,Format('%dx%d',[P.dwXCountChars,P.dwYCountChars]));
  160. S.Insert(0,'-geometry');
  161. end;
  162. S.Insert(0,'xterm');
  163. {$endif}
  164. end;
  165. {$ifndef haiku}
  166. if (P.ApplicationName<>'') then
  167. begin
  168. S.Add(TitleOption);
  169. S.Add(P.ApplicationName);
  170. end;
  171. G:='';
  172. if (suoUseSize in P.StartupOptions) then
  173. g:=format('%dx%d',[P.dwXSize,P.dwYsize]);
  174. if (suoUsePosition in P.StartupOptions) then
  175. g:=g+Format('+%d+%d',[P.dwX,P.dwY]);
  176. if G<>'' then
  177. begin
  178. S.Add(GeometryOption);
  179. S.Add(g);
  180. end;
  181. {$endif}
  182. Result:=StringsToPcharList(S);
  183. Finally
  184. S.free;
  185. end;
  186. end;
  187. Function GetLastError : Integer;
  188. begin
  189. Result:=-1;
  190. end;
  191. Type
  192. TPipeEnd = (peRead,peWrite);
  193. TPipePair = Array[TPipeEnd] of cint;
  194. Procedure CreatePipes(Var HI,HO,HE : TPipePair; CE : Boolean);
  195. Procedure CreatePair(Var P : TPipePair);
  196. begin
  197. If not CreatePipeHandles(P[peRead],P[peWrite]) then
  198. Raise EProcess.Create('Failed to create pipes');
  199. end;
  200. Procedure ClosePair(Var P : TPipePair);
  201. begin
  202. if (P[peRead]<>-1) then
  203. FileClose(P[peRead]);
  204. if (P[peWrite]<>-1) then
  205. FileClose(P[peWrite]);
  206. end;
  207. begin
  208. HO[peRead]:=-1;HO[peWrite]:=-1;
  209. HI[peRead]:=-1;HI[peWrite]:=-1;
  210. HE[peRead]:=-1;HE[peWrite]:=-1;
  211. Try
  212. CreatePair(HO);
  213. CreatePair(HI);
  214. If CE then
  215. CreatePair(HE);
  216. except
  217. ClosePair(HO);
  218. ClosePair(HI);
  219. If CE then
  220. ClosePair(HE);
  221. Raise;
  222. end;
  223. end;
  224. Function safefpdup2(fildes, fildes2 : cInt): cInt;
  225. begin
  226. repeat
  227. safefpdup2:=fpdup2(fildes,fildes2);
  228. until (safefpdup2<>-1) or (fpgeterrno<>ESysEINTR);
  229. end;
  230. Procedure TProcess.Execute;
  231. Var
  232. HI,HO,HE : TPipePair;
  233. PID : Longint;
  234. FEnv : PPChar;
  235. Argv : PPChar;
  236. fd : Integer;
  237. res : cint;
  238. FoundName,
  239. PName : String;
  240. begin
  241. If (poUsePipes in FProcessOptions) then
  242. CreatePipes(HI,HO,HE,Not (poStdErrToOutPut in FProcessOptions));
  243. Try
  244. if FEnvironment.Count<>0 then
  245. FEnv:=StringsToPcharList(FEnvironment)
  246. else
  247. FEnv:=Nil;
  248. Try
  249. Argv:=MakeCommand(Self);
  250. Try
  251. If (Argv<>Nil) and (ArgV[0]<>Nil) then
  252. PName:=StrPas(Argv[0])
  253. else
  254. begin
  255. // This should never happen, actually.
  256. PName:=ApplicationName;
  257. If (PName='') then
  258. PName:=CommandLine;
  259. end;
  260. if not FileExists(PName) then begin
  261. FoundName := ExeSearch(Pname,fpgetenv('PATH'));
  262. if FoundName<>'' then
  263. PName:=FoundName
  264. else
  265. raise EProcess.CreateFmt(SErrNoSuchProgram,[PName]);
  266. end;
  267. {$if (defined(DARWIN) or defined(SUNOS))}
  268. { can't use vfork in case the child has to be
  269. suspended immediately, because with vfork the
  270. child borrows the execution thread of the parent
  271. unit it either exits or execs -> potential
  272. deadlock depending on how quickly the SIGSTOP
  273. signal is delivered }
  274. if not(poRunSuspended in Options) then
  275. Pid:=fpvfork
  276. else
  277. Pid:=fpfork;
  278. {$else}
  279. Pid:=fpfork;
  280. {$endif}
  281. if Pid<0 then
  282. Raise EProcess.Create('Failed to Fork process');
  283. if (PID>0) then
  284. begin
  285. // Parent process. Copy process information.
  286. FProcessHandle:=PID;
  287. FThreadHandle:=PID;
  288. FProcessId:=PID;
  289. //FThreadId:=PID;
  290. end
  291. else
  292. begin
  293. { We're in the child }
  294. if (FCurrentDirectory<>'') then
  295. ChDir(FCurrentDirectory);
  296. if PoUsePipes in Options then
  297. begin
  298. FileClose(HI[peWrite]);
  299. safefpdup2(HI[peRead],0);
  300. FileClose(HO[peRead]);
  301. safefpdup2(HO[peWrite],1);
  302. if (poStdErrToOutPut in Options) then
  303. safefpdup2(HO[peWrite],2)
  304. else
  305. begin
  306. FileClose(HE[peRead]);
  307. safefpdup2(HE[peWrite],2);
  308. end
  309. end
  310. else if poNoConsole in Options then
  311. begin
  312. fd:=FileOpen('/dev/null',fmOpenReadWrite or fmShareDenyNone);
  313. safefpdup2(fd,0);
  314. safefpdup2(fd,1);
  315. safefpdup2(fd,2);
  316. end;
  317. if (poRunSuspended in Options) then
  318. sigraise(SIGSTOP);
  319. if FEnv<>Nil then
  320. fpexecve(PName,Argv,Fenv)
  321. else
  322. fpexecv(PName,argv);
  323. fpExit(127);
  324. end
  325. Finally
  326. FreePcharList(Argv);
  327. end;
  328. Finally
  329. If (FEnv<>Nil) then
  330. FreePCharList(FEnv);
  331. end;
  332. Finally
  333. if POUsePipes in FProcessOptions then
  334. begin
  335. FileClose(HO[peWrite]);
  336. FileClose(HI[peRead]);
  337. if Not (poStdErrToOutPut in FProcessOptions) then
  338. FileClose(HE[peWrite]);
  339. CreateStreams(HI[peWrite],HO[peRead],HE[peRead]);
  340. end;
  341. end;
  342. FRunning:=True;
  343. if not (csDesigning in ComponentState) and // This would hang the IDE !
  344. (poWaitOnExit in FProcessOptions) and
  345. not (poRunSuspended in FProcessOptions) then
  346. WaitOnExit;
  347. end;
  348. Function TProcess.WaitOnExit : Boolean;
  349. Var
  350. R : Dword;
  351. begin
  352. if FRunning then
  353. fexitcode:=waitprocess(handle);
  354. Result:=(fexitcode>=0);
  355. FRunning:=False;
  356. end;
  357. Function TProcess.Suspend : Longint;
  358. begin
  359. If fpkill(Handle,SIGSTOP)<>0 then
  360. Result:=-1
  361. else
  362. Result:=1;
  363. end;
  364. Function TProcess.Resume : LongInt;
  365. begin
  366. If fpKill(Handle,SIGCONT)<>0 then
  367. Result:=-1
  368. else
  369. Result:=0;
  370. end;
  371. Function TProcess.Terminate(AExitCode : Integer) : Boolean;
  372. begin
  373. Result:=False;
  374. Result:=fpkill(Handle,SIGTERM)=0;
  375. If Result then
  376. begin
  377. If Running then
  378. Result:=fpkill(Handle,SIGKILL)=0;
  379. end;
  380. { the fact that the signal has been sent does not
  381. mean that the process has already handled the
  382. signal -> wait instead of calling getexitstatus }
  383. if Result then
  384. WaitOnExit;
  385. end;
  386. Procedure TProcess.SetShowWindow (Value : TShowWindowOptions);
  387. begin
  388. FShowWindow:=Value;
  389. end;