unix.pp 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Michael Van Canneyt,
  5. BSD parts (c) 2000 by Marco van de Voort
  6. members of the Free Pascal development team.
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY;without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. Unit Unix;
  14. Interface
  15. Uses UnixUtil,BaseUnix,UnixType;
  16. {$i aliasptp.inc}
  17. {$define POSIXWORKAROUND}
  18. { Get Types and Constants }
  19. {$i sysconst.inc}
  20. {$ifdef FreeBSD}
  21. {$i systypes.inc}
  22. {$else}
  23. {$ifndef FPC_USE_LIBC}
  24. {$i systypes.inc}
  25. {$endif FPC_USE_LIBC}
  26. {$endif}
  27. {Get error numbers, some more signal definitions and other OS dependant
  28. types (that are not POSIX) }
  29. {i errno.inc}
  30. {$I signal.inc}
  31. {$i ostypes.inc}
  32. {********************
  33. File
  34. ********************}
  35. Const
  36. P_IN = 1; // pipes (?)
  37. P_OUT = 2;
  38. Const
  39. LOCK_SH = 1; // flock constants ?
  40. LOCK_EX = 2;
  41. LOCK_UN = 8;
  42. LOCK_NB = 4;
  43. Type
  44. Tpipe = baseunix.tfildes; // compability.
  45. pglob = ^tglob;
  46. tglob = record
  47. name : pchar;
  48. next : pglob;
  49. end;
  50. {******************************************************************************
  51. Procedure/Functions
  52. ******************************************************************************}
  53. {**************************
  54. Time/Date Handling
  55. ***************************}
  56. var
  57. tzdaylight : boolean;
  58. tzname : array[boolean] of pchar;
  59. { timezone support }
  60. procedure GetLocalTimezone(timer:cint;var leap_correct,leap_hit:cint);
  61. procedure GetLocalTimezone(timer:cint);
  62. procedure ReadTimezoneFile(fn:string);
  63. function GetTimezoneFile:string;
  64. Function GetEpochTime: cint;
  65. procedure GetTime (var hour,min,sec,msec,usec:word);
  66. procedure GetTime (var hour,min,sec,sec100:word);
  67. procedure GetTime (var hour,min,sec:word);
  68. Procedure GetDate (Var Year,Month,Day:Word);
  69. Procedure GetDateTime (Var Year,Month,Day,hour,minute,second:Word);
  70. function SetTime (Hour,Min,Sec:word) : Boolean;
  71. function SetDate (Year,Month,Day:Word) : Boolean;
  72. function SetDateTime (Year,Month,Day,hour,minute,second:Word) : Boolean;
  73. {**************************
  74. Process Handling
  75. ***************************}
  76. function CreateShellArgV (const prog:string):ppchar;
  77. function CreateShellArgV (const prog:Ansistring):ppchar;
  78. procedure FreeShellArgV(p:ppchar);
  79. // These are superceded by the fpExec functions that are more pascallike
  80. // and have less limitations. However I'll leave them in for a while, to
  81. // not frustrate things too much
  82. // but they might not make it to 2.0
  83. Function Execv (const path:pathstr;args:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  84. Function Execv (const path: AnsiString;args:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  85. Function Execvp (Path: Pathstr;Args:ppchar;Ep:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  86. Function Execvp (Path: AnsiString; Args:ppchar;Ep:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  87. Function Execl (const Todo: String):cint; {$ifndef ver1_0}deprecated; {$endif}
  88. Function Execl (const Todo: Ansistring):cint; {$ifndef ver1_0}deprecated; {$endif}
  89. Function Execle (Todo: String;Ep:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  90. Function Execle (Todo: AnsiString;Ep:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  91. Function Execlp (Todo: string;Ep:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  92. Function Execlp (Todo: Ansistring;Ep:ppchar):cint; {$ifndef ver1_0}deprecated; {$endif}
  93. //
  94. // These are much better, in nearly all ways.
  95. //
  96. function FpExecLE (Const PathName:AnsiString;const S:Array Of AnsiString;MyEnv:ppchar):cint;
  97. function FpExecL(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  98. function FpExecLP(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  99. function FpExecV(Const PathName:AnsiString;args:ppchar):cint;
  100. function FpExecVP(Const PathName:AnsiString;args:ppchar):cint;
  101. function FpExecVPE(Const PathName:AnsiString;args,env:ppchar):cint;
  102. Function Shell (const Command:String):cint;
  103. Function Shell (const Command:AnsiString):cint;
  104. Function fpSystem(const Command:AnsiString):cint;
  105. Function WaitProcess (Pid:cint):cint; { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  106. Function WIFSTOPPED (Status: Integer): Boolean;
  107. Function W_EXITCODE (ReturnCode, Signal: Integer): Integer;
  108. Function W_STOPCODE (Signal: Integer): Integer;
  109. {**************************
  110. File Handling
  111. ***************************}
  112. {$ifndef FPC_USE_LIBC} // defined using cdecl for libc.
  113. Function fsync (fd : cint) : cint;
  114. Function Flock (fd,mode : cint) : cint ;
  115. Function fStatFS (Fd: cint;Var Info:tstatfs):cint;
  116. Function StatFS (Path:pchar;Var Info:tstatfs):cint;
  117. {$endif}
  118. Function Flock (var T : text;mode : cint) : cint;
  119. Function Flock (var F : File;mode : cint) : cint;
  120. Function SelectText (var T:Text;TimeOut :PTimeVal):cint;
  121. Function SelectText (var T:Text;TimeOut :cint):cint;
  122. {**************************
  123. Directory Handling
  124. ***************************}
  125. procedure SeekDir(p:pdir;loc:clong);
  126. function TellDir(p:pdir):clong;
  127. {**************************
  128. Pipe/Fifo/Stream
  129. ***************************}
  130. Function AssignPipe (var pipe_in,pipe_out:cint):cint;
  131. Function AssignPipe (var pipe_in,pipe_out:text):cint;
  132. Function AssignPipe (var pipe_in,pipe_out:file):cint;
  133. //Function PClose (Var F:text) : cint;
  134. //Function PClose (Var F:file) : cint;
  135. Function POpen (var F:text;const Prog:String;rw:char):cint;
  136. Function POpen (var F:file;const Prog:String;rw:char):cint;
  137. function AssignStream(Var StreamIn,Streamout:text;Const Prog:String) : cint;
  138. function AssignStream(var StreamIn, StreamOut, StreamErr: Text; const prog: String): cint;
  139. {$ifndef BSD}
  140. Function GetDomainName:String;
  141. Function GetHostName:String;
  142. {$endif}
  143. {**************************
  144. Memory functions
  145. ***************************}
  146. const
  147. PROT_READ = $1; { page can be read }
  148. PROT_WRITE = $2; { page can be written }
  149. PROT_EXEC = $4; { page can be executed }
  150. PROT_NONE = $0; { page can not be accessed }
  151. MAP_SHARED = $1; { Share changes }
  152. // MAP_PRIVATE = $2; { Changes are private }
  153. MAP_TYPE = $f; { Mask for type of mapping }
  154. MAP_FIXED = $10; { Interpret addr exactly }
  155. // MAP_ANONYMOUS = $20; { don't use a file }
  156. {$ifdef Linux}
  157. MAP_GROWSDOWN = $100; { stack-like segment }
  158. MAP_DENYWRITE = $800; { ETXTBSY }
  159. MAP_EXECUTABLE = $1000; { mark it as an executable }
  160. MAP_LOCKED = $2000; { pages are locked }
  161. MAP_NORESERVE = $4000; { don't check for reservations }
  162. {$else}
  163. {$ifdef FreeBSD}
  164. // FreeBSD defines MAP_COPY=MAP_PRIVATE=$2;
  165. MAP_FILE = $0000; { map from file (default) }
  166. MAP_ANON = $1000; { allocated from memory, swap space }
  167. MAP_RENAME = $0020; { Sun: rename private pages to file }
  168. MAP_NORESERVE = $0040; { Sun: don't reserve needed swap area }
  169. MAP_INHERIT = $0080; { region is retained after exec }
  170. MAP_NOEXTEND = $0100; { for MAP_FILE, don't change file size }
  171. MAP_HASSEMAPHORE = $0200; { region may contain semaphores }
  172. MAP_STACK = $0400; { region grows down, like a stack }
  173. MAP_NOSYNC = $0800; { page to but do not sync underlying file}
  174. MAP_NOCORE = $20000;{ dont include these pages in a coredump}
  175. {$endif}
  176. {$endif}
  177. {**************************
  178. Utility functions
  179. ***************************}
  180. Type
  181. TFSearchOption = (NoCurrentDirectory,
  182. CurrentDirectoryFirst,
  183. CurrentDirectoryLast);
  184. Function FExpand (Const Path: PathStr):PathStr;
  185. Function FSearch (const path:pathstr;dirlist:string):pathstr;
  186. Function FSearch (const path:AnsiString;dirlist:Ansistring;CurrentDirStrategy:TFSearchOption):AnsiString;
  187. Function FSearch (const path:AnsiString;dirlist:AnsiString):AnsiString;
  188. Function Glob (Const path:pathstr):pglob;
  189. Procedure Globfree (var p:pglob);
  190. procedure SigRaise (sig:integer);
  191. {$ifdef FPC_USE_LIBC}
  192. const clib = 'c';
  193. {$i unxdeclh.inc}
  194. {$else}
  195. {$i unxsysch.inc} // calls used in system and not reexported from baseunix
  196. {$endif}
  197. {******************************************************************************
  198. Implementation
  199. ******************************************************************************}
  200. {$i unxovlh.inc}
  201. Implementation
  202. Uses Strings{$ifndef FPC_USE_LIBC},Syscall{$endif};
  203. {$i unxovl.inc}
  204. {$ifndef FPC_USE_LIBC}
  205. {$i syscallh.inc}
  206. {$i ossysch.inc}
  207. {$i unxsysc.inc}
  208. {$endif}
  209. { Get the definitions of textrec and filerec }
  210. {$i textrec.inc}
  211. {$i filerec.inc}
  212. {$ifndef FPC_USE_LIBC}
  213. { Raw System calls are in Syscalls.inc}
  214. {$ifdef Linux} // Linux has more "oldlinux" compability.
  215. {$i sysc11.inc}
  216. {$else}
  217. {$i syscalls.inc}
  218. {$endif}
  219. {$endif}
  220. {$i unixsysc.inc} {Has platform specific libc part under ifdef, besides
  221. syscalls}
  222. Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
  223. {******************************************************************************
  224. Process related calls
  225. ******************************************************************************}
  226. { Most calls of WaitPID do not handle the result correctly, this funktion treats errors more correctly }
  227. Function WaitProcess(Pid:cint):cint; { like WaitPid(PID,@result,0) Handling of Signal interrupts (errno=EINTR), returning the Exitcode of Process (>=0) or -Status if terminated}
  228. var ret,r,s : cint;
  229. begin
  230. s:=$7F00;
  231. repeat
  232. r:=fpWaitPid(Pid,@s,0);
  233. if (r=-1) and (fpgeterrno=ESysEIntr) Then
  234. r:=0;
  235. until (r<>0);
  236. if (r=-1) or (r=0) then // 0 is not a valid return and should never occur (it means status invalid when using WNOHANG)
  237. WaitProcess:=-1 // return -1 to indicate an error. fpwaitpid updated it.
  238. else
  239. begin
  240. {$ifndef Solaris}
  241. { at least correct for Linux and Darwin (JM) }
  242. if (s and $7F)=0 then // Only this is a valid returncode
  243. {$else}
  244. if (s and $FF)=0 then // Only this is a valid returncode
  245. {$endif}
  246. WaitProcess:=s shr 8
  247. else if (s>0) then // Until now there is not use of the highest bit , but check this for the future
  248. WaitProcess:=-s // normal case
  249. else
  250. WaitProcess:=s; // s<0 should not occur, but wie return also a negativ value
  251. end;
  252. end;
  253. function InternalCreateShellArgV(cmd:pChar; len:cint):ppchar;
  254. {
  255. Create an argv which executes a command in a shell using /bin/sh -c
  256. }
  257. const Shell = '/bin/sh'#0'-c'#0;
  258. var
  259. pp,p : ppchar;
  260. // temp : string; !! Never pass a local var back!!
  261. begin
  262. getmem(pp,4*4);
  263. p:=pp;
  264. p^:=@Shell[1];
  265. inc(p);
  266. p^:=@Shell[9];
  267. inc(p);
  268. getmem(p^,len+1);
  269. move(cmd^,p^^,len);
  270. pchar(p^)[len]:=#0;
  271. inc(p);
  272. p^:=Nil;
  273. InternalCreateShellArgV:=pp;
  274. end;
  275. function CreateShellArgV(const prog:string):ppchar;
  276. begin
  277. CreateShellArgV:=InternalCreateShellArgV(@prog[1],length(prog));
  278. end;
  279. function CreateShellArgV(const prog:Ansistring):ppchar;
  280. {
  281. Create an argv which executes a command in a shell using /bin/sh -c
  282. using a AnsiString;
  283. }
  284. begin
  285. CreateShellArgV:=InternalCreateShellArgV(@prog[1],length(prog)); // if ppc works like delphi this also work when @prog[1] is invalid (len=0)
  286. end;
  287. procedure FreeShellArgV(p:ppchar);
  288. begin
  289. if (p<>nil) then begin
  290. freemem(p[2]);
  291. freemem(p);
  292. end;
  293. end;
  294. Function Execv(const path: AnsiString;args:ppchar):cint;
  295. {
  296. Overloaded ansistring version.
  297. }
  298. begin
  299. Execv:=fpExecVe(Path,Args,envp);
  300. end;
  301. Function Execvp(Path: AnsiString; Args:ppchar;Ep:ppchar):cint;
  302. {
  303. Overloaded ansistring version
  304. }
  305. var
  306. thepath : Ansistring;
  307. begin
  308. if path[1]<>'/' then
  309. begin
  310. Thepath:=strpas(fpgetenv('PATH'));
  311. if thepath='' then
  312. thepath:='.';
  313. Path:=FSearch(path,thepath)
  314. end
  315. else
  316. Path:='';
  317. if Path='' then
  318. Begin
  319. fpsetErrno(ESysEnoEnt);
  320. Exit(-1);
  321. end
  322. else
  323. Execvp:=fpExecve(Path,args,ep);
  324. end;
  325. Function Execv(const path:pathstr;args:ppchar):cint;
  326. {
  327. Replaces the current program by the program specified in path,
  328. arguments in args are passed to Execve.
  329. the current environment is passed on.
  330. }
  331. begin
  332. Execv:=fpExecve(path,args,envp);
  333. end;
  334. Function Execvp(Path:Pathstr;Args:ppchar;Ep:ppchar):cint;
  335. {
  336. This does the same as Execve, only it searches the PATH environment
  337. for the place of the Executable, except when Path starts with a slash.
  338. if the PATH environment variable is unavailable, the path is set to '.'
  339. }
  340. var
  341. thepath : string;
  342. begin
  343. if path[1]<>'/' then
  344. begin
  345. Thepath:=strpas(fpgetenv('PATH'));
  346. if thepath='' then
  347. thepath:='.';
  348. Path:=FSearch(path,thepath)
  349. end
  350. else
  351. Path:='';
  352. if Path='' then
  353. Begin
  354. fpsetErrno(ESysEnoEnt);
  355. Exit(-1);
  356. end
  357. else
  358. execvp:=fpExecve(Path,args,ep);
  359. end;
  360. Function Execle(Todo:string;Ep:ppchar):cint;
  361. {
  362. This procedure takes the string 'Todo', parses it for command and
  363. command options, and Executes the command with the given options.
  364. The string 'Todo' shoud be of the form 'command options', options
  365. separated by commas.
  366. the PATH environment is not searched for 'command'.
  367. The specified environment(in 'ep') is passed on to command
  368. }
  369. var
  370. p : ppchar;
  371. begin
  372. p:=StringToPPChar(ToDo,0);
  373. if (p=nil) or (p^=nil) then
  374. Begin
  375. fpsetErrno(ESysEnoEnt);
  376. Exit(-1);
  377. end
  378. else
  379. execle:=fpExecVE(p^,p,EP);
  380. end;
  381. function Execle(Todo:AnsiString;Ep:ppchar):cint;
  382. {
  383. This procedure takes the string 'Todo', parses it for command and
  384. command options, and Executes the command with the given options.
  385. The string 'Todo' shoud be of the form 'command options', options
  386. separated by commas.
  387. the PATH environment is not searched for 'command'.
  388. The specified environment(in 'ep') is passed on to command
  389. }
  390. var
  391. p : ppchar;
  392. begin
  393. p:=StringToPPChar(ToDo,0);
  394. if (p=nil) or (p^=nil) then
  395. Begin
  396. fpsetErrno(ESysEnoEnt);
  397. Exit(-1);
  398. end;
  399. ExecLe:=fpExecVE(p^,p,EP);
  400. end;
  401. Function Execl(const Todo:string):cint;
  402. {
  403. This procedure takes the string 'Todo', parses it for command and
  404. command options, and Executes the command with the given options.
  405. The string 'Todo' shoud be of the form 'command options', options
  406. separated by commas.
  407. the PATH environment is not searched for 'command'.
  408. The current environment is passed on to command
  409. }
  410. begin
  411. Execl:=ExecLE(ToDo,EnvP);
  412. end;
  413. Function Execlp(Todo:string;Ep:ppchar):cint;
  414. {
  415. This procedure takes the string 'Todo', parses it for command and
  416. command options, and Executes the command with the given options.
  417. The string 'Todo' shoud be of the form 'command options', options
  418. separated by commas.
  419. the PATH environment is searched for 'command'.
  420. The specified environment (in 'ep') is passed on to command
  421. }
  422. var
  423. p : ppchar;
  424. begin
  425. p:=StringToPPchar(todo,0);
  426. if (p=nil) or (p^=nil) then
  427. Begin
  428. fpsetErrno(ESysEnoEnt);
  429. Exit(-1);
  430. end;
  431. Execlp:=ExecVP(StrPas(p^),p,EP);
  432. end;
  433. Function Execlp(Todo: Ansistring;Ep:ppchar):cint;
  434. {
  435. Overloaded ansistring version.
  436. }
  437. var
  438. p : ppchar;
  439. begin
  440. p:=StringToPPchar(todo,0);
  441. if (p=nil) or (p^=nil) then
  442. Begin
  443. fpsetErrno(ESysEnoEnt);
  444. Exit(-1);
  445. end;
  446. execlp:=ExecVP(StrPas(p^),p,EP);
  447. end;
  448. function intFpExecVEMaybeP (Const PathName:AnsiString;Args,MyEnv:ppchar;SearchPath:Boolean):cint;
  449. // does an ExecVE, but still has to handle P
  450. // execv variants call this directly, execl variants indirectly via
  451. // intfpexecl
  452. Var
  453. NewCmd : ansistring;
  454. ThePath : AnsiString;
  455. Error : cint;
  456. NrParam : longint;
  457. Begin
  458. If SearchPath and (pos('/',pathname)=0) Then
  459. Begin
  460. // The above could be better. (check if not escaped/quoted '/' 's) ?
  461. // (Jilles says this is ok)
  462. // Stevens says only search if newcmd contains no '/'
  463. // fsearch is not ansistring clean yet.
  464. ThePath:=fpgetenv('PATH');
  465. if thepath='' then
  466. thepath:='.'; // FreeBSD uses _PATH_DEFPATH = /usr/bin:/bin
  467. // but a quick check showed that _PATH_DEFPATH
  468. // varied from OS to OS
  469. newcmd:=FSearch(pathname,thepath,NoCurrentDirectory);
  470. // FreeBSD libc keeps on trying till a file is successfully run.
  471. // Stevens says "try each path prefix"
  472. // execp puts newcmd here.
  473. args^:=pchar(newcmd);
  474. End;
  475. // repeat
  476. // if searchpath then args^:=pchar(commandtorun)
  477. IntFpExecVEMaybeP:=fpExecVE(Args^,Args,MyEnv);
  478. {
  479. // Code that if exec fails due to permissions, tries to run it with sh
  480. // Should we deallocate p on fail? -> no fpexit is run no matter what
  481. //
  482. }
  483. // if intfpexecvemaybep=-1 then zoekvolgende file.
  484. // until (Goexit) or SearchExit;
  485. {
  486. If IntFpExec=-1 Then
  487. Begin
  488. Error:=fpGetErrno
  489. Case Error of
  490. ESysE2Big : Exit(-1);
  491. ESysELoop,
  492. : Exit(-1);
  493. }
  494. end;
  495. function intFpExecl (Const PathName:AnsiString;const s:array of ansistring;MyEnv:ppchar;SearchPath:Boolean):cint;
  496. { Handles the array of ansistring -> ppchar conversion.
  497. Base for the the "l" variants.
  498. }
  499. var p:ppchar;
  500. begin
  501. If PathName='' Then
  502. Begin
  503. fpsetErrno(ESysEnoEnt);
  504. Exit(-1); // Errno?
  505. End;
  506. p:=ArrayStringToPPchar(s,1);
  507. if p=NIL Then
  508. Begin
  509. GetMem(p,2*sizeof(pchar));
  510. if p=nil then
  511. begin
  512. {$ifdef xunix}
  513. fpseterrno(ESysEnoMem);
  514. {$endif}
  515. fpseterrno(ESysEnoEnt);
  516. exit(-1);
  517. end;
  518. p[1]:=nil;
  519. End;
  520. p^:=pchar(PathName);
  521. IntFPExecL:=intFpExecVEMaybeP(PathName,p,MyEnv,SearchPath);
  522. // If we come here, no attempts were executed successfully.
  523. Freemem(p);
  524. end;
  525. function FpExecLE (Const PathName:AnsiString;const S:Array Of AnsiString;MyEnv:ppchar):cint;
  526. Begin
  527. FpExecLE:=intFPExecl(PathName,s,MyEnv,false);
  528. End;
  529. function FpExecL(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  530. Begin
  531. FpExecL:=intFPExecl(PathName,S,EnvP,false);
  532. End;
  533. function FpExecLP(Const PathName:AnsiString;const S:Array Of AnsiString):cint;
  534. Begin
  535. FpExecLP:=intFPExecl(PathName,S,EnvP,True);
  536. End;
  537. function FpExecV(Const PathName:AnsiString;args:ppchar):cint;
  538. Begin
  539. fpexecV:=intFpExecVEMaybeP (PathName,args,envp,false);
  540. End;
  541. function FpExecVP(Const PathName:AnsiString;args:ppchar):cint;
  542. Begin
  543. fpexecVP:=intFpExecVEMaybeP (PathName,args,envp,true);
  544. End;
  545. function FpExecVPE(Const PathName:AnsiString;args,env:ppchar):cint;
  546. Begin
  547. fpexecVPE:=intFpExecVEMaybeP (PathName,args,env,true);
  548. End;
  549. // exect and execvP (ExecCapitalP) are not implement
  550. // Non POSIX anyway.
  551. // Exect turns on tracing for the process
  552. // execvP has the searchpath as array of ansistring ( const char *search_path)
  553. {$define FPC_USE_FPEXEC}
  554. Function Shell(const Command:String):cint;
  555. {
  556. Executes the shell, and passes it the string Command. (Through /bin/sh -c)
  557. The current environment is passed to the shell.
  558. It waits for the shell to exit, and returns its exit status.
  559. If the Exec call failed exit status 127 is reported.
  560. }
  561. { Changed the structure:
  562. - the previous version returns an undefinied value if fork fails
  563. - it returns the status of Waitpid instead of the Process returnvalue (see the doc to Shell)
  564. - it uses exit(127) not ExitProc (The Result in pp386: going on Compiling in 2 processes!)
  565. - ShellArgs are now released
  566. - The Old CreateShellArg gives back pointers to a local var
  567. }
  568. var
  569. {$ifndef FPC_USE_FPEXEC}
  570. p : ppchar;
  571. {$endif}
  572. pid : cint;
  573. begin
  574. {$ifndef FPC_USE_FPEXEC}
  575. p:=CreateShellArgv(command);
  576. {$endif}
  577. pid:=fpfork;
  578. if pid=0 then // We are in the Child
  579. begin
  580. {This is the child.}
  581. {$ifndef FPC_USE_FPEXEC}
  582. fpExecve(p^,p,envp);
  583. {$else}
  584. fpexecl('/bin/sh',['-c',Command]);
  585. {$endif}
  586. fpExit(127); // was Exit(127)
  587. end
  588. else if (pid<>-1) then // Successfull started
  589. Shell:=WaitProcess(pid)
  590. else // no success
  591. Shell:=-1; // indicate an error
  592. {$ifndef FPC_USE_FPEXEC}
  593. FreeShellArgV(p);
  594. {$endif}
  595. end;
  596. Function Shell(const Command:AnsiString):cint;
  597. {
  598. AnsiString version of Shell
  599. }
  600. var
  601. {$ifndef FPC_USE_FPEXEC}
  602. p : ppchar;
  603. {$endif}
  604. pid : cint;
  605. begin { Changes as above }
  606. {$ifndef FPC_USE_FPEXEC}
  607. p:=CreateShellArgv(command);
  608. {$endif}
  609. pid:=fpfork;
  610. if pid=0 then // We are in the Child
  611. begin
  612. {$ifdef FPC_USE_FPEXEC}
  613. fpexecl('/bin/sh',['-c',Command]);
  614. {$else}
  615. fpExecve(p^,p,envp);
  616. {$endif}
  617. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  618. end
  619. else if (pid<>-1) then // Successfull started
  620. Shell:=WaitProcess(pid)
  621. else // no success
  622. Shell:=-1;
  623. {$ifndef FPC_USE_FPEXEC}
  624. FreeShellArgV(p);
  625. {$ENDIF}
  626. end;
  627. {$ifdef FPC_USE_LIBC}
  628. function xfpsystem(p:pchar):cint; cdecl; external clib name 'system';
  629. Function fpSystem(const Command:AnsiString):cint;
  630. begin
  631. fpsystem:=xfpsystem(pchar(command));
  632. end;
  633. {$else}
  634. Function fpSystem(const Command:AnsiString):cint;
  635. {
  636. AnsiString version of Shell
  637. }
  638. var
  639. pid,savedpid : cint;
  640. pstat : cint;
  641. ign,intact,
  642. quitact : SigactionRec;
  643. newsigblock,
  644. oldsigblock : tsigset;
  645. begin { Changes as above }
  646. if command='' then exit(1);
  647. {$ifdef FreeBSD}
  648. ign.sa_handler:=TSigAction(SIG_IGN);
  649. {$else}
  650. ign.sa_handler:=SignalHandler(SIG_IGN);
  651. {$endif}
  652. fpsigemptyset(ign.sa_mask);
  653. ign.sa_flags:=0;
  654. fpsigaction(SIGINT, @ign, @intact);
  655. fpsigaction(SIGQUIT, @ign, @quitact);
  656. fpsigemptyset(newsigblock);
  657. fpsigaddset(newsigblock,SIGCHLD);
  658. fpsigprocmask(SIG_BLOCK,newsigblock,oldsigblock);
  659. pid:=fpfork;
  660. if pid=0 then // We are in the Child
  661. begin
  662. fpsigaction(SIGINT,@intact,NIL);
  663. fpsigaction(SIGQUIT,@quitact,NIL);
  664. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  665. fpexecl('/bin/sh',['-c',Command]);
  666. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  667. end
  668. else if (pid<>-1) then // Successfull started
  669. begin
  670. savedpid:=pid;
  671. repeat
  672. pid:=fpwaitpid(savedpid,@pstat,0);
  673. until (pid<>-1) and (fpgeterrno()<>ESysEintr);
  674. if pid=-1 Then
  675. fpsystem:=-1
  676. else
  677. fpsystem:=pstat;
  678. end
  679. else // no success
  680. fpsystem:=-1;
  681. fpsigaction(SIGINT,@intact,NIL);
  682. fpsigaction(SIGQUIT,@quitact,NIL);
  683. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  684. end;
  685. {$endif}
  686. Function WIFSTOPPED(Status: Integer): Boolean;
  687. begin
  688. WIFSTOPPED:=((Status and $FF)=$7F);
  689. end;
  690. Function W_EXITCODE(ReturnCode, Signal: Integer): Integer;
  691. begin
  692. W_EXITCODE:=(ReturnCode shl 8) or Signal;
  693. end;
  694. Function W_STOPCODE(Signal: Integer): Integer;
  695. begin
  696. W_STOPCODE:=(Signal shl 8) or $7F;
  697. end;
  698. {******************************************************************************
  699. Date and Time related calls
  700. ******************************************************************************}
  701. Function GetEpochTime: cint;
  702. {
  703. Get the number of seconds since 00:00, January 1 1970, GMT
  704. the time NOT corrected any way
  705. }
  706. begin
  707. GetEpochTime:=fptime;
  708. end;
  709. procedure GetTime(var hour,min,sec,msec,usec:word);
  710. {
  711. Gets the current time, adjusted to local time
  712. }
  713. var
  714. year,day,month:Word;
  715. tz:timeval;
  716. begin
  717. fpgettimeofday(@tz,nil);
  718. EpochToLocal(tz.tv_sec,year,month,day,hour,min,sec);
  719. msec:=tz.tv_usec div 1000;
  720. usec:=tz.tv_usec mod 1000;
  721. end;
  722. procedure GetTime(var hour,min,sec,sec100:word);
  723. {
  724. Gets the current time, adjusted to local time
  725. }
  726. var
  727. usec : word;
  728. begin
  729. gettime(hour,min,sec,sec100,usec);
  730. sec100:=sec100 div 10;
  731. end;
  732. Procedure GetTime(Var Hour,Min,Sec:Word);
  733. {
  734. Gets the current time, adjusted to local time
  735. }
  736. var
  737. msec,usec : Word;
  738. Begin
  739. gettime(hour,min,sec,msec,usec);
  740. End;
  741. Procedure GetDate(Var Year,Month,Day:Word);
  742. {
  743. Gets the current date, adjusted to local time
  744. }
  745. var
  746. hour,minute,second : word;
  747. Begin
  748. EpochToLocal(fptime,year,month,day,hour,minute,second);
  749. End;
  750. Procedure GetDateTime(Var Year,Month,Day,hour,minute,second:Word);
  751. {
  752. Gets the current date, adjusted to local time
  753. }
  754. Begin
  755. EpochToLocal(fptime,year,month,day,hour,minute,second);
  756. End;
  757. {$ifndef BSD} // this can be done nicer, but I still have
  758. // to think about what to do with this func.
  759. {$ifdef linux}
  760. {$ifdef FPC_USE_LIBC}
  761. function intstime (t:ptime_t):cint; external name 'stime';
  762. {$endif}
  763. Function stime (t : cint) : boolean;
  764. begin
  765. {$ifdef FPC_USE_LIBC}
  766. stime:=intstime(@t)=0;
  767. {$else}
  768. stime:=do_SysCall(Syscall_nr_stime,cint(@t))=0;
  769. {$endif}
  770. end;
  771. {$endif}
  772. {$endif}
  773. {$ifdef BSD}
  774. Function stime (t : cint) : Boolean;
  775. begin
  776. end;
  777. {$endif}
  778. Function SetTime(Hour,Min,Sec:word) : boolean;
  779. var
  780. Year, Month, Day : Word;
  781. begin
  782. GetDate (Year, Month, Day);
  783. SetTime:=stime ( LocalToEpoch ( Year, Month, Day, Hour, Min, Sec ) );
  784. end;
  785. Function SetDate(Year,Month,Day:Word) : boolean;
  786. var
  787. Hour, Minute, Second, Sec100 : Word;
  788. begin
  789. GetTime ( Hour, Minute, Second, Sec100 );
  790. SetDate:=stime ( LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) );
  791. end;
  792. Function SetDateTime(Year,Month,Day,hour,minute,second:Word) : Boolean;
  793. begin
  794. SetDateTime:=stime ( LocalToEpoch ( Year, Month, Day, Hour, Minute, Second ) );
  795. end;
  796. { Include timezone handling routines which use /usr/share/timezone info }
  797. {$i timezone.inc}
  798. {******************************************************************************
  799. FileSystem calls
  800. ******************************************************************************}
  801. Function Execl(const Todo:Ansistring):cint;
  802. {
  803. Overloaded AnsiString Version of ExecL.
  804. }
  805. begin
  806. Execl:=ExecLE(ToDo,EnvP);
  807. end;
  808. Function Flock (var T : text;mode : cint) : cint;
  809. begin
  810. Flock:=Flock(TextRec(T).Handle,mode);
  811. end;
  812. Function Flock (var F : File;mode : cint) :cint;
  813. begin
  814. Flock:=Flock(FileRec(F).Handle,mode);
  815. end;
  816. Function SelectText(var T:Text;TimeOut :PTimeval):cint;
  817. Var
  818. F:TfdSet;
  819. begin
  820. if textrec(t).mode=fmclosed then
  821. begin
  822. fpseterrno(ESysEBADF);
  823. exit(-1);
  824. end;
  825. FpFD_ZERO(f);
  826. fpFD_SET(textrec(T).handle,f);
  827. if textrec(T).mode=fminput then
  828. SelectText:=fpselect(textrec(T).handle+1,@f,nil,nil,TimeOut)
  829. else
  830. SelectText:=fpselect(textrec(T).handle+1,nil,@f,nil,TimeOut);
  831. end;
  832. Function SelectText(var T:Text;TimeOut :cint):cint;
  833. var
  834. p : PTimeVal;
  835. tv : TimeVal;
  836. begin
  837. if TimeOut=-1 then
  838. p:=nil
  839. else
  840. begin
  841. tv.tv_Sec:=Timeout div 1000;
  842. tv.tv_Usec:=(Timeout mod 1000)*1000;
  843. p:=@tv;
  844. end;
  845. SelectText:=SelectText(T,p);
  846. end;
  847. {******************************************************************************
  848. Directory
  849. ******************************************************************************}
  850. procedure SeekDir(p:pdir;loc:clong);
  851. begin
  852. if p=nil then
  853. begin
  854. fpseterrno(ESysEBADF);
  855. exit;
  856. end;
  857. {$ifndef bsd}
  858. p^.dd_nextoff:=fplseek(p^.dd_fd,loc,seek_set);
  859. {$endif}
  860. p^.dd_size:=0;
  861. p^.dd_loc:=0;
  862. end;
  863. function TellDir(p:pdir):clong;
  864. begin
  865. if p=nil then
  866. begin
  867. fpseterrno(ESysEBADF);
  868. telldir:=-1;
  869. exit;
  870. end;
  871. telldir:=fplseek(p^.dd_fd,0,seek_cur)
  872. { We could try to use the nextoff field here, but on my 1.2.13
  873. kernel, this gives nothing... This may have to do with
  874. the readdir implementation of libc... I also didn't find any trace of
  875. the field in the kernel code itself, So I suspect it is an artifact of libc.
  876. Michael. }
  877. end;
  878. {******************************************************************************
  879. Pipes/Fifo
  880. ******************************************************************************}
  881. Procedure OpenPipe(var F:Text);
  882. begin
  883. case textrec(f).mode of
  884. fmoutput :
  885. if textrec(f).userdata[1]<>P_OUT then
  886. textrec(f).mode:=fmclosed;
  887. fminput :
  888. if textrec(f).userdata[1]<>P_IN then
  889. textrec(f).mode:=fmclosed;
  890. else
  891. textrec(f).mode:=fmclosed;
  892. end;
  893. end;
  894. Function IOPipe(var F:text):cint;
  895. begin
  896. IOPipe:=0;
  897. case textrec(f).mode of
  898. fmoutput :
  899. begin
  900. { first check if we need something to write, else we may
  901. get a SigPipe when Close() is called (PFV) }
  902. if textrec(f).bufpos>0 then
  903. IOPipe:=fpwrite(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufpos);
  904. end;
  905. fminput : Begin
  906. textrec(f).bufend:=fpread(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufsize);
  907. IOPipe:=textrec(f).bufend;
  908. End;
  909. end;
  910. textrec(f).bufpos:=0;
  911. end;
  912. Function FlushPipe(var F:Text):cint;
  913. begin
  914. FlushPipe:=0;
  915. if (textrec(f).mode=fmoutput) and (textrec(f).bufpos<>0) then
  916. FlushPipe:=IOPipe(f);
  917. textrec(f).bufpos:=0;
  918. end;
  919. Function ClosePipe(var F:text):cint;
  920. begin
  921. textrec(f).mode:=fmclosed;
  922. ClosePipe:=fpclose(textrec(f).handle);
  923. end;
  924. Function AssignPipe(var pipe_in,pipe_out:text):cint;
  925. {
  926. Sets up a pair of file variables, which act as a pipe. The first one can
  927. be read from, the second one can be written to.
  928. }
  929. var
  930. f_in,f_out : cint;
  931. begin
  932. if AssignPipe(f_in,f_out)=-1 then
  933. exit(-1);
  934. { Set up input }
  935. Assign(Pipe_in,'');
  936. Textrec(Pipe_in).Handle:=f_in;
  937. Textrec(Pipe_in).Mode:=fmInput;
  938. Textrec(Pipe_in).userdata[1]:=P_IN;
  939. TextRec(Pipe_in).OpenFunc:=@OpenPipe;
  940. TextRec(Pipe_in).InOutFunc:=@IOPipe;
  941. TextRec(Pipe_in).FlushFunc:=@FlushPipe;
  942. TextRec(Pipe_in).CloseFunc:=@ClosePipe;
  943. { Set up output }
  944. Assign(Pipe_out,'');
  945. Textrec(Pipe_out).Handle:=f_out;
  946. Textrec(Pipe_out).Mode:=fmOutput;
  947. Textrec(Pipe_out).userdata[1]:=P_OUT;
  948. TextRec(Pipe_out).OpenFunc:=@OpenPipe;
  949. TextRec(Pipe_out).InOutFunc:=@IOPipe;
  950. TextRec(Pipe_out).FlushFunc:=@FlushPipe;
  951. TextRec(Pipe_out).CloseFunc:=@ClosePipe;
  952. AssignPipe:=0;
  953. end;
  954. Function AssignPipe(var pipe_in,pipe_out:file):cint;
  955. {
  956. Sets up a pair of file variables, which act as a pipe. The first one can
  957. be read from, the second one can be written to.
  958. If the operation was unsuccesful,
  959. }
  960. var
  961. f_in,f_out : cint;
  962. begin
  963. if AssignPipe(f_in,f_out)=-1 then
  964. exit(-1);
  965. { Set up input }
  966. Assign(Pipe_in,'');
  967. Filerec(Pipe_in).Handle:=f_in;
  968. Filerec(Pipe_in).Mode:=fmInput;
  969. Filerec(Pipe_in).recsize:=1;
  970. Filerec(Pipe_in).userdata[1]:=P_IN;
  971. { Set up output }
  972. Assign(Pipe_out,'');
  973. Filerec(Pipe_out).Handle:=f_out;
  974. Filerec(Pipe_out).Mode:=fmoutput;
  975. Filerec(Pipe_out).recsize:=1;
  976. Filerec(Pipe_out).userdata[1]:=P_OUT;
  977. AssignPipe:=0;
  978. end;
  979. Function PCloseText(Var F:text):cint;
  980. {
  981. May not use @PClose due overloading
  982. }
  983. begin
  984. PCloseText:=PClose(f);
  985. end;
  986. function POpen(var F:text;const Prog:String;rw:char):cint;
  987. {
  988. Starts the program in 'Prog' and makes it's input or out put the
  989. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  990. F, will be read from stdin by the program in 'Prog'. The inverse is true
  991. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  992. read from 'f'.
  993. }
  994. var
  995. pipi,
  996. pipo : text;
  997. pid : pid_t;
  998. pl : ^cint;
  999. pp : ppchar;
  1000. ret : cint;
  1001. begin
  1002. rw:=upcase(rw);
  1003. if not (rw in ['R','W']) then
  1004. begin
  1005. FpSetErrno(ESysEnoent);
  1006. exit(-1);
  1007. end;
  1008. if AssignPipe(pipi,pipo)=-1 Then
  1009. Exit(-1);
  1010. pid:=fpfork; // vfork in FreeBSD.
  1011. if pid=-1 then
  1012. begin
  1013. close(pipi);
  1014. close(pipo);
  1015. exit(-1);
  1016. end;
  1017. if pid=0 then
  1018. begin
  1019. { We're in the child }
  1020. if rw='W' then
  1021. begin
  1022. close(pipo);
  1023. ret:=fpdup2(pipi,input);
  1024. close(pipi);
  1025. if ret=-1 then
  1026. halt(127);
  1027. end
  1028. else
  1029. begin
  1030. close(pipi);
  1031. ret:=fpdup2(pipo,output);
  1032. close(pipo);
  1033. if ret=-1 then
  1034. halt(127);
  1035. end;
  1036. {$ifdef FPC_USE_FPEXEC}
  1037. fpexecl('/bin/sh',['-c',Prog]);
  1038. {$else}
  1039. pp:=createshellargv(prog);
  1040. fpExecve(pp^,pp,envp);
  1041. {$endif}
  1042. halt(127);
  1043. end
  1044. else
  1045. begin
  1046. { We're in the parent }
  1047. if rw='W' then
  1048. begin
  1049. close(pipi);
  1050. f:=pipo;
  1051. textrec(f).bufptr:=@textrec(f).buffer;
  1052. end
  1053. else
  1054. begin
  1055. close(pipo);
  1056. f:=pipi;
  1057. textrec(f).bufptr:=@textrec(f).buffer;
  1058. end;
  1059. {Save the process ID - needed when closing }
  1060. pl:=@(textrec(f).userdata[2]);
  1061. pl^:=pid;
  1062. textrec(f).closefunc:=@PCloseText;
  1063. end;
  1064. ret:=0;
  1065. end;
  1066. Function POpen(var F:file;const Prog:String;rw:char):cint;
  1067. {
  1068. Starts the program in 'Prog' and makes it's input or out put the
  1069. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  1070. F, will be read from stdin by the program in 'Prog'. The inverse is true
  1071. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  1072. read from 'f'.
  1073. }
  1074. var
  1075. pipi,
  1076. pipo : file;
  1077. pid : cint;
  1078. pl : ^cint;
  1079. p,pp : ppchar;
  1080. temp : string[255];
  1081. ret : cint;
  1082. begin
  1083. rw:=upcase(rw);
  1084. if not (rw in ['R','W']) then
  1085. begin
  1086. FpSetErrno(ESysEnoent);
  1087. exit(-1);
  1088. end;
  1089. ret:=AssignPipe(pipi,pipo);
  1090. if ret=-1 then
  1091. exit(-1);
  1092. pid:=fpfork;
  1093. if pid=-1 then
  1094. begin
  1095. close(pipi);
  1096. close(pipo);
  1097. exit(-1);
  1098. end;
  1099. if pid=0 then
  1100. begin
  1101. { We're in the child }
  1102. if rw='W' then
  1103. begin
  1104. close(pipo);
  1105. ret:=fpdup2(filerec(pipi).handle,stdinputhandle);
  1106. close(pipi);
  1107. if ret=-1 then
  1108. halt(127);
  1109. end
  1110. else
  1111. begin
  1112. close(pipi);
  1113. ret:=fpdup2(filerec(pipo).handle,stdoutputhandle);
  1114. close(pipo);
  1115. if ret=1 then
  1116. halt(127);
  1117. end;
  1118. {$ifdef FPC_USE_FPEXEC}
  1119. fpexecl('/bin/sh',['-c',Prog]);
  1120. {$else}
  1121. getmem(pp,sizeof(pchar)*4);
  1122. temp:='/bin/sh'#0'-c'#0+prog+#0;
  1123. p:=pp;
  1124. p^:=@temp[1];
  1125. inc(p);
  1126. p^:=@temp[9];
  1127. inc(p);
  1128. p^:=@temp[12];
  1129. inc(p);
  1130. p^:=Nil;
  1131. fpExecve(ansistring('/bin/sh'),pp,envp);
  1132. {$endif}
  1133. halt(127);
  1134. end
  1135. else
  1136. begin
  1137. { We're in the parent }
  1138. if rw='W' then
  1139. begin
  1140. close(pipi);
  1141. f:=pipo;
  1142. end
  1143. else
  1144. begin
  1145. close(pipo);
  1146. f:=pipi;
  1147. end;
  1148. {Save the process ID - needed when closing }
  1149. pl:=@(filerec(f).userdata[2]);
  1150. pl^:=pid;
  1151. end;
  1152. POpen:=0;
  1153. end;
  1154. Function AssignStream(Var StreamIn,Streamout:text;Const Prog:String) : cint;
  1155. {
  1156. Starts the program in 'Prog' and makes its input and output the
  1157. other end of two pipes, which are the stdin and stdout of a program
  1158. specified in 'Prog'.
  1159. streamout can be used to write to the program, streamin can be used to read
  1160. the output of the program. See the following diagram :
  1161. Parent Child
  1162. STreamout --> Input
  1163. Streamin <-- Output
  1164. Return value is the process ID of the process being spawned, or -1 in case of failure.
  1165. }
  1166. var
  1167. pipi,
  1168. pipo : text;
  1169. pid : cint;
  1170. pl : ^cint;
  1171. begin
  1172. AssignStream:=-1;
  1173. if AssignPipe(streamin,pipo)=-1 Then
  1174. exit(-1);
  1175. if AssignPipe(pipi,streamout)=-1 Then // shouldn't this close streamin and pipo?
  1176. exit(-1);
  1177. pid:=fpfork;
  1178. if pid=-1 then
  1179. begin
  1180. close(pipi);
  1181. close(pipo);
  1182. close (streamin);
  1183. close (streamout);
  1184. exit;
  1185. end;
  1186. if pid=0 then
  1187. begin
  1188. { We're in the child }
  1189. { Close what we don't need }
  1190. close(streamout);
  1191. close(streamin);
  1192. if fpdup2(pipi,input)=-1 Then
  1193. halt(127);
  1194. close(pipi);
  1195. If fpdup2(pipo,output)=-1 Then
  1196. halt (127);
  1197. close(pipo);
  1198. Execl(Prog);
  1199. halt(127);
  1200. end
  1201. else
  1202. begin
  1203. { we're in the parent}
  1204. close(pipo);
  1205. close(pipi);
  1206. {Save the process ID - needed when closing }
  1207. pl:=@(textrec(StreamIn).userdata[2]);
  1208. pl^:=pid;
  1209. textrec(StreamIn).closefunc:=@PCloseText;
  1210. {Save the process ID - needed when closing }
  1211. pl:=@(textrec(StreamOut).userdata[2]);
  1212. pl^:=pid;
  1213. textrec(StreamOut).closefunc:=@PCloseText;
  1214. AssignStream:=Pid;
  1215. end;
  1216. end;
  1217. function AssignStream(var StreamIn, StreamOut, StreamErr: Text; const prog: String):cint;
  1218. {
  1219. Starts the program in 'prog' and makes its input, output and error output the
  1220. other end of three pipes, which are the stdin, stdout and stderr of a program
  1221. specified in 'prog'.
  1222. StreamOut can be used to write to the program, StreamIn can be used to read
  1223. the output of the program, StreamErr reads the error output of the program.
  1224. See the following diagram :
  1225. Parent Child
  1226. StreamOut --> StdIn (input)
  1227. StreamIn <-- StdOut (output)
  1228. StreamErr <-- StdErr (error output)
  1229. }
  1230. var
  1231. PipeIn, PipeOut, PipeErr: text;
  1232. pid: cint;
  1233. pl: ^cint;
  1234. begin
  1235. AssignStream := -1;
  1236. // Assign pipes
  1237. if AssignPipe(StreamIn, PipeOut)=-1 Then
  1238. Exit(-1);
  1239. If AssignPipe(StreamErr, PipeErr)=-1 Then
  1240. begin
  1241. Close(StreamIn);
  1242. Close(PipeOut);
  1243. exit(-1);
  1244. end;
  1245. if AssignPipe(PipeIn, StreamOut)=-1 Then
  1246. begin
  1247. Close(StreamIn);
  1248. Close(PipeOut);
  1249. Close(StreamErr);
  1250. Close(PipeErr);
  1251. exit(-1);
  1252. end;
  1253. // Fork
  1254. pid := fpFork;
  1255. if pid=-1 then begin
  1256. Close(StreamIn);
  1257. Close(PipeOut);
  1258. Close(StreamErr);
  1259. Close(PipeErr);
  1260. Close(PipeIn);
  1261. Close(StreamOut);
  1262. exit(-1);
  1263. end;
  1264. if pid = 0 then begin
  1265. // *** We are in the child ***
  1266. // Close what we don not need
  1267. Close(StreamOut);
  1268. Close(StreamIn);
  1269. Close(StreamErr);
  1270. // Connect pipes
  1271. if fpdup2(PipeIn, Input)=-1 Then
  1272. Halt(127);
  1273. Close(PipeIn);
  1274. if fpdup2(PipeOut, Output)=-1 Then
  1275. Halt(127);
  1276. Close(PipeOut);
  1277. if fpdup2(PipeErr, StdErr)=-1 Then
  1278. Halt(127);
  1279. Close(PipeErr);
  1280. // Execute program
  1281. Execl(Prog);
  1282. Halt(127);
  1283. end else begin
  1284. // *** We are in the parent ***
  1285. Close(PipeErr);
  1286. Close(PipeOut);
  1287. Close(PipeIn);
  1288. // Save the process ID - needed when closing
  1289. pl := @(TextRec(StreamIn).userdata[2]);
  1290. pl^ := pid;
  1291. TextRec(StreamIn).closefunc := @PCloseText;
  1292. // Save the process ID - needed when closing
  1293. pl := @(TextRec(StreamOut).userdata[2]);
  1294. pl^ := pid;
  1295. TextRec(StreamOut).closefunc := @PCloseText;
  1296. // Save the process ID - needed when closing
  1297. pl := @(TextRec(StreamErr).userdata[2]);
  1298. pl^ := pid;
  1299. TextRec(StreamErr).closefunc := @PCloseText;
  1300. AssignStream := pid;
  1301. end;
  1302. end;
  1303. {******************************************************************************
  1304. General information calls
  1305. ******************************************************************************}
  1306. {$ifndef BSD}
  1307. Function GetDomainName:String; { linux only!}
  1308. // domainname is a glibc extension.
  1309. {
  1310. Get machines domain name. Returns empty string if not set.
  1311. }
  1312. Var
  1313. Sysn : utsname;
  1314. begin
  1315. If fpUname(sysn)<>0 then
  1316. getdomainname:=''
  1317. else
  1318. getdomainname:=strpas(@Sysn.domain[0]);
  1319. end;
  1320. {$endif}
  1321. Function GetHostName:String;
  1322. {
  1323. Get machines name. Returns empty string if not set.
  1324. }
  1325. Var
  1326. Sysn : utsname;
  1327. begin
  1328. If fpuname(sysn)=-1 then
  1329. gethostname:=''
  1330. else
  1331. gethostname:=strpas(@Sysn.nodename[0]);
  1332. end;
  1333. {******************************************************************************
  1334. Signal handling calls
  1335. ******************************************************************************}
  1336. procedure SigRaise(sig:integer);
  1337. begin
  1338. fpKill(fpGetPid,Sig);
  1339. end;
  1340. {******************************************************************************
  1341. Utility calls
  1342. ******************************************************************************}
  1343. {
  1344. Function Octal(l:cint):cint;
  1345. {
  1346. Convert an octal specified number to decimal;
  1347. }
  1348. var
  1349. octnr,
  1350. oct : cint;
  1351. begin
  1352. octnr:=0;
  1353. oct:=0;
  1354. while (l>0) do
  1355. begin
  1356. oct:=oct or ((l mod 10) shl octnr);
  1357. l:=l div 10;
  1358. inc(octnr,3);
  1359. end;
  1360. Octal:=oct;
  1361. end;
  1362. }
  1363. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  1364. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  1365. {$I fexpand.inc}
  1366. {$UNDEF FPC_FEXPAND_GETENVPCHAR}
  1367. {$UNDEF FPC_FEXPAND_TILDE}
  1368. Function FSearch(const path:pathstr;dirlist:string):pathstr;
  1369. {
  1370. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1371. returns an empty string if not found. Wildcards are NOT allowed.
  1372. If dirlist is empty, it is set to '.'
  1373. }
  1374. Var
  1375. NewDir : PathStr;
  1376. p1 : cint;
  1377. Info : Stat;
  1378. Begin
  1379. {Replace ':' with ';'}
  1380. for p1:=1 to length(dirlist) do
  1381. if dirlist[p1]=':' then
  1382. dirlist[p1]:=';';
  1383. {Check for WildCards}
  1384. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1385. FSearch:='' {No wildcards allowed in these things.}
  1386. Else
  1387. Begin
  1388. Dirlist:='.;'+dirlist;{Make sure current dir is first to be searched.}
  1389. Repeat
  1390. p1:=Pos(';',DirList);
  1391. If p1=0 Then
  1392. p1:=255;
  1393. NewDir:=Copy(DirList,1,P1 - 1);
  1394. if NewDir[Length(NewDir)]<>'/' then
  1395. NewDir:=NewDir+'/';
  1396. NewDir:=NewDir+Path;
  1397. Delete(DirList,1,p1);
  1398. if (FpStat(NewDir,Info)>=0) and
  1399. (not fpS_ISDIR(Info.st_Mode)) then
  1400. Begin
  1401. If Pos('./',NewDir)=1 Then
  1402. Delete(NewDir,1,2);
  1403. {DOS strips off an initial .\}
  1404. End
  1405. Else
  1406. NewDir:='';
  1407. Until (DirList='') or (Length(NewDir) > 0);
  1408. FSearch:=NewDir;
  1409. End;
  1410. End;
  1411. Function FSearch(const path:AnsiString;dirlist:Ansistring;CurrentDirStrategy:TFSearchOption):AnsiString;
  1412. {
  1413. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1414. returns an empty string if not found. Wildcards are NOT allowed.
  1415. If dirlist is empty, it is set to '.'
  1416. This function tries to make FSearch use ansistrings, and decrease
  1417. stringhandling overhead at the same time.
  1418. }
  1419. Var
  1420. NewDir : PathStr;
  1421. p1 : cint;
  1422. Info : Stat;
  1423. i,j : cint;
  1424. p : pchar;
  1425. Begin
  1426. if CurrentDirStrategy=CurrentDirectoryFirst Then
  1427. Dirlist:='.:'+dirlist; {Make sure current dir is first to be searched.}
  1428. if CurrentDirStrategy=CurrentDirectoryLast Then
  1429. Dirlist:=dirlist+':.'; {Make sure current dir is last to be searched.}
  1430. {Replace ':' and ';' with #0}
  1431. for p1:=1 to length(dirlist) do
  1432. if (dirlist[p1]=':') or (dirlist[p1]=';') then
  1433. dirlist[p1]:=#0;
  1434. {Check for WildCards}
  1435. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1436. FSearch:='' {No wildcards allowed in these things.}
  1437. Else
  1438. Begin
  1439. p:=pchar(dirlist);
  1440. i:=length(dirlist);
  1441. j:=1;
  1442. Repeat
  1443. NewDir:=p+'/'+Path;
  1444. if (FpStat(NewDir,Info)>=0) and
  1445. (not fpS_ISDIR(Info.st_Mode)) then
  1446. Begin
  1447. If Pos('./',NewDir)=1 Then
  1448. Delete(NewDir,1,2);
  1449. {DOS strips off an initial .\}
  1450. End
  1451. Else
  1452. NewDir:='';
  1453. while (j<=i) and (p^<>#0) do begin inc(j); inc(p); end;
  1454. if p^=#0 then inc(p);
  1455. Until (j>=i) or (Length(NewDir) > 0);
  1456. FSearch:=NewDir;
  1457. End;
  1458. End;
  1459. Function FSearch(const path:AnsiString;dirlist:Ansistring):AnsiString;
  1460. Begin
  1461. FSearch:=FSearch(path,dirlist,CurrentDirectoryFirst);
  1462. End;
  1463. Procedure Globfree(var p : pglob);
  1464. {
  1465. Release memory occupied by pglob structure, and names in it.
  1466. sets p to nil.
  1467. }
  1468. var
  1469. temp : pglob;
  1470. begin
  1471. while assigned(p) do
  1472. begin
  1473. temp:=p^.next;
  1474. if assigned(p^.name) then
  1475. freemem(p^.name);
  1476. dispose(p);
  1477. p:=temp;
  1478. end;
  1479. end;
  1480. Function Glob(Const path:pathstr):pglob;
  1481. {
  1482. Fills a tglob structure with entries matching path,
  1483. and returns a pointer to it. Returns nil on error,
  1484. linuxerror is set accordingly.
  1485. }
  1486. var
  1487. temp,
  1488. temp2 : string[255];
  1489. thedir : pdir;
  1490. buffer : pdirent;
  1491. root,
  1492. current : pglob;
  1493. begin
  1494. { Get directory }
  1495. temp:=dirname(path);
  1496. if temp='' then
  1497. temp:='.';
  1498. temp:=temp+#0;
  1499. thedir:=fpopendir(@temp[1]);
  1500. if thedir=nil then
  1501. exit(nil);
  1502. temp:=basename(path,''); { get the pattern }
  1503. if thedir^.dd_fd<0 then
  1504. exit(nil);
  1505. {get the entries}
  1506. root:=nil;
  1507. current:=nil;
  1508. repeat
  1509. buffer:=fpreaddir(thedir^);
  1510. if buffer=nil then
  1511. break;
  1512. temp2:=strpas(@(buffer^.d_name[0]));
  1513. if fnmatch(temp,temp2) then
  1514. begin
  1515. if root=nil then
  1516. begin
  1517. new(root);
  1518. current:=root;
  1519. end
  1520. else
  1521. begin
  1522. new(current^.next);
  1523. current:=current^.next;
  1524. end;
  1525. if current=nil then
  1526. begin
  1527. fpseterrno(ESysENOMEM);
  1528. globfree(root);
  1529. break;
  1530. end;
  1531. current^.next:=nil;
  1532. getmem(current^.name,length(temp2)+1);
  1533. if current^.name=nil then
  1534. begin
  1535. fpseterrno(ESysENOMEM);
  1536. globfree(root);
  1537. break;
  1538. end;
  1539. move(buffer^.d_name[0],current^.name^,length(temp2)+1);
  1540. end;
  1541. until false;
  1542. fpclosedir(thedir^);
  1543. glob:=root;
  1544. end;
  1545. {--------------------------------
  1546. Stat.Mode Macro's
  1547. --------------------------------}
  1548. Initialization
  1549. InitLocalTime;
  1550. finalization
  1551. DoneLocalTime;
  1552. End.
  1553. {
  1554. $Log$
  1555. Revision 1.68 2004-03-04 22:15:17 marco
  1556. * UnixType changes. Please report problems to me.
  1557. Revision 1.66 2004/02/16 13:21:18 marco
  1558. * fpexec for popen
  1559. Revision 1.65 2004/02/14 21:12:14 marco
  1560. * provisorische fix voor Michael's problemen
  1561. Revision 1.64 2004/02/14 18:22:15 marco
  1562. * fpsystem, and some FPC_USE_LIBC fixes. (FreeBSD needs systypes.inc, also when FPC_USE_LIBC, it only contains types like statfs
  1563. Revision 1.63 2004/02/13 10:50:22 marco
  1564. * Hopefully last large changes to fpexec and friends.
  1565. - naming conventions changes from Michael.
  1566. - shell functions get alternative under ifdef.
  1567. - arraystring function moves to unixutil
  1568. - unixutil now regards quotes in stringtoppchar.
  1569. - sysutils/unix get executeprocess(ansi,array of ansi), and
  1570. both executeprocess functions are fixed
  1571. - Sysutils/win32 get executeprocess(ansi,array of ansi)
  1572. Revision 1.62 2004/02/12 16:20:58 marco
  1573. * currentpath stuff fixed for fsearch
  1574. Revision 1.61 2004/02/12 15:31:06 marco
  1575. * First version of fpexec change. Still under ifdef or silently overloaded
  1576. Revision 1.60 2004/01/23 08:11:18 jonas
  1577. * only include systypes.inc if FPC_USE_LIBC is not defined
  1578. Revision 1.59 2004/01/22 13:46:14 marco
  1579. bsd
  1580. Revision 1.58 2004/01/04 21:05:01 jonas
  1581. * declare C-library routines as external in libc so we generate proper
  1582. import entries for Darwin
  1583. Revision 1.57 2004/01/04 20:53:02 jonas
  1584. * don't use systypes if FPC_USE_LIBC is defined
  1585. Revision 1.56 2004/01/04 16:24:05 jonas
  1586. * fixed WaitProcess in case of SysEintr
  1587. Revision 1.55 2003/12/31 20:24:25 marco
  1588. * export statfs(pchar)
  1589. Revision 1.54 2003/12/30 15:43:20 marco
  1590. * linux now compiles with FPC_USE_LIBC
  1591. Revision 1.53 2003/12/30 12:24:01 marco
  1592. * FPC_USE_LIBC
  1593. Revision 1.52 2003/12/08 17:16:30 peter
  1594. * fsearch should only find files
  1595. Revision 1.51 2003/11/19 17:11:40 marco
  1596. * termio unit
  1597. Revision 1.50 2003/11/19 10:54:32 marco
  1598. * some simple restructures
  1599. Revision 1.49 2003/11/17 11:28:08 marco
  1600. * Clone moved to linux, + few small unit unix changes
  1601. Revision 1.48 2003/11/17 10:05:51 marco
  1602. * threads for FreeBSD. Not working tho
  1603. Revision 1.47 2003/11/14 17:30:14 marco
  1604. * weeehoo linuxerror is no more :-)
  1605. Revision 1.46 2003/11/14 16:44:48 marco
  1606. * stream functions converted to work without linuxerror
  1607. Revision 1.45 2003/11/13 18:44:06 marco
  1608. * small fi
  1609. Revision 1.44 2003/11/12 22:19:45 marco
  1610. * more linuxeror fixes
  1611. Revision 1.43 2003/11/03 09:42:28 marco
  1612. * Peter's Cardinal<->Longint fixes patch
  1613. Revision 1.42 2003/10/30 16:42:58 marco
  1614. * fixes for old syscall() convention removing
  1615. Revision 1.41 2003/10/12 19:40:43 marco
  1616. * ioctl fixes. IDE now starts, but
  1617. Revision 1.40 2003/09/29 14:36:06 peter
  1618. * fixed for stricter compiler
  1619. Revision 1.39 2003/09/27 12:51:33 peter
  1620. * fpISxxx macros renamed to C compliant fpS_ISxxx
  1621. Revision 1.38 2003/09/20 12:38:29 marco
  1622. * FCL now compiles for FreeBSD with new 1.1. Now Linux.
  1623. Revision 1.37 2003/09/17 19:07:44 marco
  1624. * more fixes for Unix<->unixutil
  1625. Revision 1.36 2003/09/17 17:30:46 marco
  1626. * Introduction of unixutil
  1627. Revision 1.35 2003/09/16 21:46:27 marco
  1628. * small fixes, checking things on linux
  1629. Revision 1.34 2003/09/16 20:52:24 marco
  1630. * small cleanups. Mostly killing of already commented code in unix etc
  1631. Revision 1.33 2003/09/16 16:13:56 marco
  1632. * fdset functions renamed to fp<posix name>
  1633. Revision 1.32 2003/09/15 20:08:49 marco
  1634. * small fixes. FreeBSD now cycles
  1635. Revision 1.31 2003/09/14 20:15:01 marco
  1636. * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
  1637. Revision 1.30 2003/07/08 21:23:24 peter
  1638. * sparc fixes
  1639. Revision 1.29 2003/05/30 19:58:40 marco
  1640. * Getting NetBSD/i386 to compile.
  1641. Revision 1.28 2003/05/29 19:16:16 marco
  1642. * fixed a small *BSD gotcha
  1643. Revision 1.27 2003/05/24 20:39:54 jonas
  1644. * fixed ExitCode translation in WaitProcess for Linux and Darwin (and
  1645. probably other BSD's as well)
  1646. Revision 1.26 2003/03/11 08:27:59 michael
  1647. * stringtoppchar should use tabs instead of backspace as delimiter
  1648. Revision 1.25 2002/12/18 16:50:39 marco
  1649. * Unix RTL generic parts. Linux working, *BSD will follow shortly
  1650. Revision 1.24 2002/09/07 16:01:28 peter
  1651. * old logs removed and tabs fixed
  1652. Revision 1.23 2002/08/06 13:30:46 sg
  1653. * replaced some Longints with Cardinals, to mach the C headers
  1654. * updated the termios record
  1655. Revision 1.22 2002/03/05 20:04:25 michael
  1656. + Patch from Sebastian for FCNTL call
  1657. Revision 1.21 2002/01/02 12:22:54 marco
  1658. * Removed ifdef arround getepoch.
  1659. }