unix.pp 49 KB

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