unix.pp 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949
  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;
  1333. {$ifndef FPC_USE_LIBC}
  1334. external name 'FPC_SYSC_GETDOMAINNAME';
  1335. {$else FPC_USE_LIBC}
  1336. cdecl; external clib name 'getdomainname';
  1337. {$endif FPC_USE_LIBC}
  1338. Function GetDomainName:String; { linux only!}
  1339. // domainname is a glibc extension.
  1340. {
  1341. Get machines domain name. Returns empty string if not set.
  1342. }
  1343. begin
  1344. if intGetDomainName(@getdomainname[1],255)=-1 then
  1345. getdomainname:=''
  1346. else
  1347. getdomainname[0]:=chr(strlen(@getdomainname[1]));
  1348. end;
  1349. {$endif}
  1350. Function GetHostName:String;
  1351. {
  1352. Get machines name. Returns empty string if not set.
  1353. }
  1354. Var
  1355. Sysn : utsname;
  1356. begin
  1357. If fpuname(sysn)=-1 then
  1358. gethostname:=''
  1359. else
  1360. gethostname:=strpas(@Sysn.nodename[0]);
  1361. end;
  1362. {******************************************************************************
  1363. Signal handling calls
  1364. ******************************************************************************}
  1365. procedure SigRaise(sig:integer);
  1366. begin
  1367. fpKill(fpGetPid,Sig);
  1368. end;
  1369. {******************************************************************************
  1370. Utility calls
  1371. ******************************************************************************}
  1372. {
  1373. Function Octal(l:cint):cint;
  1374. {
  1375. Convert an octal specified number to decimal;
  1376. }
  1377. var
  1378. octnr,
  1379. oct : cint;
  1380. begin
  1381. octnr:=0;
  1382. oct:=0;
  1383. while (l>0) do
  1384. begin
  1385. oct:=oct or ((l mod 10) shl octnr);
  1386. l:=l div 10;
  1387. inc(octnr,3);
  1388. end;
  1389. Octal:=oct;
  1390. end;
  1391. }
  1392. {$DEFINE FPC_FEXPAND_TILDE} { Tilde is expanded to home }
  1393. {$DEFINE FPC_FEXPAND_GETENVPCHAR} { GetEnv result is a PChar }
  1394. {$I fexpand.inc}
  1395. {$UNDEF FPC_FEXPAND_GETENVPCHAR}
  1396. {$UNDEF FPC_FEXPAND_TILDE}
  1397. Function FSearch(const path:pathstr;dirlist:string):pathstr;
  1398. {
  1399. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1400. returns an empty string if not found. Wildcards are NOT allowed.
  1401. If dirlist is empty, it is set to '.'
  1402. }
  1403. Var
  1404. NewDir : PathStr;
  1405. p1 : cint;
  1406. Info : Stat;
  1407. Begin
  1408. {Replace ':' with ';'}
  1409. for p1:=1 to length(dirlist) do
  1410. if dirlist[p1]=':' then
  1411. dirlist[p1]:=';';
  1412. {Check for WildCards}
  1413. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1414. FSearch:='' {No wildcards allowed in these things.}
  1415. Else
  1416. Begin
  1417. Dirlist:='.;'+dirlist;{Make sure current dir is first to be searched.}
  1418. Repeat
  1419. p1:=Pos(';',DirList);
  1420. If p1=0 Then
  1421. p1:=255;
  1422. NewDir:=Copy(DirList,1,P1 - 1);
  1423. if NewDir[Length(NewDir)]<>'/' then
  1424. NewDir:=NewDir+'/';
  1425. NewDir:=NewDir+Path;
  1426. Delete(DirList,1,p1);
  1427. if (FpStat(NewDir,Info)>=0) and
  1428. (not fpS_ISDIR(Info.st_Mode)) then
  1429. Begin
  1430. If Pos('./',NewDir)=1 Then
  1431. Delete(NewDir,1,2);
  1432. {DOS strips off an initial .\}
  1433. End
  1434. Else
  1435. NewDir:='';
  1436. Until (DirList='') or (Length(NewDir) > 0);
  1437. FSearch:=NewDir;
  1438. End;
  1439. End;
  1440. Function FSearch(const path:AnsiString;dirlist:Ansistring;CurrentDirStrategy:TFSearchOption):AnsiString;
  1441. {
  1442. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1443. returns an empty string if not found. Wildcards are NOT allowed.
  1444. If dirlist is empty, it is set to '.'
  1445. This function tries to make FSearch use ansistrings, and decrease
  1446. stringhandling overhead at the same time.
  1447. }
  1448. Var
  1449. NewDir : PathStr;
  1450. p1 : cint;
  1451. Info : Stat;
  1452. i,j : cint;
  1453. p : pchar;
  1454. Begin
  1455. if CurrentDirStrategy=CurrentDirectoryFirst Then
  1456. Dirlist:='.:'+dirlist; {Make sure current dir is first to be searched.}
  1457. if CurrentDirStrategy=CurrentDirectoryLast Then
  1458. Dirlist:=dirlist+':.'; {Make sure current dir is last to be searched.}
  1459. {Replace ':' and ';' with #0}
  1460. for p1:=1 to length(dirlist) do
  1461. if (dirlist[p1]=':') or (dirlist[p1]=';') then
  1462. dirlist[p1]:=#0;
  1463. {Check for WildCards}
  1464. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1465. FSearch:='' {No wildcards allowed in these things.}
  1466. Else
  1467. Begin
  1468. p:=pchar(dirlist);
  1469. i:=length(dirlist);
  1470. j:=1;
  1471. Repeat
  1472. NewDir:=ansistring(p)+'/'+Path;
  1473. if (FpStat(NewDir,Info)>=0) and
  1474. (not fpS_ISDIR(Info.st_Mode)) then
  1475. Begin
  1476. If Pos('./',NewDir)=1 Then
  1477. Delete(NewDir,1,2);
  1478. {DOS strips off an initial .\}
  1479. End
  1480. Else
  1481. NewDir:='';
  1482. while (j<=i) and (p^<>#0) do begin inc(j); inc(p); end;
  1483. if p^=#0 then inc(p);
  1484. Until (j>=i) or (Length(NewDir) > 0);
  1485. FSearch:=NewDir;
  1486. End;
  1487. End;
  1488. Function FSearch(const path:AnsiString;dirlist:Ansistring):AnsiString;
  1489. Begin
  1490. FSearch:=FSearch(path,dirlist,CurrentDirectoryFirst);
  1491. End;
  1492. Procedure Globfree(var p : pglob);
  1493. {
  1494. Release memory occupied by pglob structure, and names in it.
  1495. sets p to nil.
  1496. }
  1497. var
  1498. temp : pglob;
  1499. begin
  1500. while assigned(p) do
  1501. begin
  1502. temp:=p^.next;
  1503. if assigned(p^.name) then
  1504. freemem(p^.name);
  1505. dispose(p);
  1506. p:=temp;
  1507. end;
  1508. end;
  1509. Function Glob(Const path:pathstr):pglob;
  1510. {
  1511. Fills a tglob structure with entries matching path,
  1512. and returns a pointer to it. Returns nil on error,
  1513. linuxerror is set accordingly.
  1514. }
  1515. var
  1516. temp,
  1517. temp2 : string[255];
  1518. thedir : pdir;
  1519. buffer : pdirent;
  1520. root,
  1521. current : pglob;
  1522. begin
  1523. { Get directory }
  1524. temp:=dirname(path);
  1525. if temp='' then
  1526. temp:='.';
  1527. temp:=temp+#0;
  1528. thedir:=fpopendir(@temp[1]);
  1529. if thedir=nil then
  1530. exit(nil);
  1531. temp:=basename(path,''); { get the pattern }
  1532. if thedir^.dd_fd<0 then
  1533. exit(nil);
  1534. {get the entries}
  1535. root:=nil;
  1536. current:=nil;
  1537. repeat
  1538. buffer:=fpreaddir(thedir^);
  1539. if buffer=nil then
  1540. break;
  1541. temp2:=strpas(@(buffer^.d_name[0]));
  1542. if fnmatch(temp,temp2) then
  1543. begin
  1544. if root=nil then
  1545. begin
  1546. new(root);
  1547. current:=root;
  1548. end
  1549. else
  1550. begin
  1551. new(current^.next);
  1552. current:=current^.next;
  1553. end;
  1554. if current=nil then
  1555. begin
  1556. fpseterrno(ESysENOMEM);
  1557. globfree(root);
  1558. break;
  1559. end;
  1560. current^.next:=nil;
  1561. getmem(current^.name,length(temp2)+1);
  1562. if current^.name=nil then
  1563. begin
  1564. fpseterrno(ESysENOMEM);
  1565. globfree(root);
  1566. break;
  1567. end;
  1568. move(buffer^.d_name[0],current^.name^,length(temp2)+1);
  1569. end;
  1570. until false;
  1571. fpclosedir(thedir^);
  1572. glob:=root;
  1573. end;
  1574. {--------------------------------
  1575. Stat.Mode Macro's
  1576. --------------------------------}
  1577. Initialization
  1578. InitLocalTime;
  1579. finalization
  1580. DoneLocalTime;
  1581. End.
  1582. {
  1583. $Log$
  1584. Revision 1.74 2004-07-18 14:54:42 jonas
  1585. * fixed BSD getdomainname for FPC_USE_LIBC
  1586. Revision 1.73 2004/07/18 11:27:54 marco
  1587. * small fix for BSD getdomainname. BSD version is based on Sysctl
  1588. Revision 1.72 2004/07/03 13:18:06 daniel
  1589. * Better fix.
  1590. Revision 1.71 2004/07/03 13:15:51 daniel
  1591. * Compilation fix in fsearch
  1592. Revision 1.70 2004/04/23 19:16:25 marco
  1593. * flock -> fpflock because of conflicting structure name
  1594. Revision 1.69 2004/04/22 17:17:13 peter
  1595. * x86-64 fixes
  1596. Revision 1.68 2004/03/04 22:15:17 marco
  1597. * UnixType changes. Please report problems to me.
  1598. Revision 1.66 2004/02/16 13:21:18 marco
  1599. * fpexec for popen
  1600. Revision 1.65 2004/02/14 21:12:14 marco
  1601. * provisorische fix voor Michael's problemen
  1602. Revision 1.64 2004/02/14 18:22:15 marco
  1603. * fpsystem, and some FPC_USE_LIBC fixes. (FreeBSD needs systypes.inc, also when FPC_USE_LIBC, it only contains types like statfs
  1604. Revision 1.63 2004/02/13 10:50:22 marco
  1605. * Hopefully last large changes to fpexec and friends.
  1606. - naming conventions changes from Michael.
  1607. - shell functions get alternative under ifdef.
  1608. - arraystring function moves to unixutil
  1609. - unixutil now regards quotes in stringtoppchar.
  1610. - sysutils/unix get executeprocess(ansi,array of ansi), and
  1611. both executeprocess functions are fixed
  1612. - Sysutils/win32 get executeprocess(ansi,array of ansi)
  1613. Revision 1.62 2004/02/12 16:20:58 marco
  1614. * currentpath stuff fixed for fsearch
  1615. Revision 1.61 2004/02/12 15:31:06 marco
  1616. * First version of fpexec change. Still under ifdef or silently overloaded
  1617. Revision 1.60 2004/01/23 08:11:18 jonas
  1618. * only include systypes.inc if FPC_USE_LIBC is not defined
  1619. Revision 1.59 2004/01/22 13:46:14 marco
  1620. bsd
  1621. Revision 1.58 2004/01/04 21:05:01 jonas
  1622. * declare C-library routines as external in libc so we generate proper
  1623. import entries for Darwin
  1624. Revision 1.57 2004/01/04 20:53:02 jonas
  1625. * don't use systypes if FPC_USE_LIBC is defined
  1626. Revision 1.56 2004/01/04 16:24:05 jonas
  1627. * fixed WaitProcess in case of SysEintr
  1628. Revision 1.55 2003/12/31 20:24:25 marco
  1629. * export statfs(pchar)
  1630. Revision 1.54 2003/12/30 15:43:20 marco
  1631. * linux now compiles with FPC_USE_LIBC
  1632. Revision 1.53 2003/12/30 12:24:01 marco
  1633. * FPC_USE_LIBC
  1634. Revision 1.52 2003/12/08 17:16:30 peter
  1635. * fsearch should only find files
  1636. Revision 1.51 2003/11/19 17:11:40 marco
  1637. * termio unit
  1638. Revision 1.50 2003/11/19 10:54:32 marco
  1639. * some simple restructures
  1640. Revision 1.49 2003/11/17 11:28:08 marco
  1641. * Clone moved to linux, + few small unit unix changes
  1642. Revision 1.48 2003/11/17 10:05:51 marco
  1643. * threads for FreeBSD. Not working tho
  1644. Revision 1.47 2003/11/14 17:30:14 marco
  1645. * weeehoo linuxerror is no more :-)
  1646. Revision 1.46 2003/11/14 16:44:48 marco
  1647. * stream functions converted to work without linuxerror
  1648. Revision 1.45 2003/11/13 18:44:06 marco
  1649. * small fi
  1650. Revision 1.44 2003/11/12 22:19:45 marco
  1651. * more linuxeror fixes
  1652. Revision 1.43 2003/11/03 09:42:28 marco
  1653. * Peter's Cardinal<->Longint fixes patch
  1654. Revision 1.42 2003/10/30 16:42:58 marco
  1655. * fixes for old syscall() convention removing
  1656. Revision 1.41 2003/10/12 19:40:43 marco
  1657. * ioctl fixes. IDE now starts, but
  1658. Revision 1.40 2003/09/29 14:36:06 peter
  1659. * fixed for stricter compiler
  1660. Revision 1.39 2003/09/27 12:51:33 peter
  1661. * fpISxxx macros renamed to C compliant fpS_ISxxx
  1662. Revision 1.38 2003/09/20 12:38:29 marco
  1663. * FCL now compiles for FreeBSD with new 1.1. Now Linux.
  1664. Revision 1.37 2003/09/17 19:07:44 marco
  1665. * more fixes for Unix<->unixutil
  1666. Revision 1.36 2003/09/17 17:30:46 marco
  1667. * Introduction of unixutil
  1668. Revision 1.35 2003/09/16 21:46:27 marco
  1669. * small fixes, checking things on linux
  1670. Revision 1.34 2003/09/16 20:52:24 marco
  1671. * small cleanups. Mostly killing of already commented code in unix etc
  1672. Revision 1.33 2003/09/16 16:13:56 marco
  1673. * fdset functions renamed to fp<posix name>
  1674. Revision 1.32 2003/09/15 20:08:49 marco
  1675. * small fixes. FreeBSD now cycles
  1676. Revision 1.31 2003/09/14 20:15:01 marco
  1677. * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
  1678. Revision 1.30 2003/07/08 21:23:24 peter
  1679. * sparc fixes
  1680. Revision 1.29 2003/05/30 19:58:40 marco
  1681. * Getting NetBSD/i386 to compile.
  1682. Revision 1.28 2003/05/29 19:16:16 marco
  1683. * fixed a small *BSD gotcha
  1684. Revision 1.27 2003/05/24 20:39:54 jonas
  1685. * fixed ExitCode translation in WaitProcess for Linux and Darwin (and
  1686. probably other BSD's as well)
  1687. Revision 1.26 2003/03/11 08:27:59 michael
  1688. * stringtoppchar should use tabs instead of backspace as delimiter
  1689. Revision 1.25 2002/12/18 16:50:39 marco
  1690. * Unix RTL generic parts. Linux working, *BSD will follow shortly
  1691. Revision 1.24 2002/09/07 16:01:28 peter
  1692. * old logs removed and tabs fixed
  1693. Revision 1.23 2002/08/06 13:30:46 sg
  1694. * replaced some Longints with Cardinals, to mach the C headers
  1695. * updated the termios record
  1696. Revision 1.22 2002/03/05 20:04:25 michael
  1697. + Patch from Sebastian for FCNTL call
  1698. Revision 1.21 2002/01/02 12:22:54 marco
  1699. * Removed ifdef arround getepoch.
  1700. }