unix.pp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Michael Van Canneyt,
  4. BSD parts (c) 2000 by Marco van de Voort
  5. members of the Free Pascal development team.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY;without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. Unit Unix;
  13. Interface
  14. Uses BaseUnix,UnixType;
  15. // If you deprecated new symbols, please annotate the version.
  16. // this makes it easier to decide if they can already be removed.
  17. {$if (defined(BSD) or defined(SUNOS)) and defined(FPC_USE_LIBC)}
  18. {$define USE_VFORK}
  19. {$endif}
  20. {$i aliasptp.inc}
  21. {$i unxconst.inc} { Get Types and Constants only exported in this unit }
  22. {** File handling **}
  23. Const
  24. P_IN = 1; // pipes (?)
  25. P_OUT = 2;
  26. LOCK_SH = 1; // flock constants ?
  27. LOCK_EX = 2;
  28. LOCK_UN = 8;
  29. LOCK_NB = 4;
  30. // The portable MAP_* and PROT_ constants are exported from unit Unix for compability.
  31. PROT_READ = baseunix.PROT_READ; { page can be read }
  32. PROT_WRITE = baseunix.PROT_WRITE; { page can be written }
  33. PROT_EXEC = baseunix.PROT_EXEC; { page can be executed }
  34. PROT_NONE = baseunix.PROT_NONE; { page can not be accessed }
  35. MAP_FAILED = baseunix.MAP_FAILED; { mmap() failed }
  36. MAP_SHARED = baseunix.MAP_SHARED; { Share changes }
  37. MAP_PRIVATE = baseunix.MAP_PRIVATE; { Changes are private }
  38. MAP_TYPE = baseunix.MAP_TYPE; { Mask for type of mapping }
  39. MAP_FIXED = baseunix.MAP_FIXED; { Interpret addr exactly }
  40. {** Time/Date Handling **}
  41. var
  42. tzdaylight : boolean;
  43. tzname : array[boolean] of pchar;
  44. {************ Procedure/Functions ************}
  45. {$IFNDEF DONT_READ_TIMEZONE} // allows to disable linking in and trying for platforms
  46. // it doesn't (yet) work for.
  47. { timezone support }
  48. procedure GetLocalTimezone(timer:cint;var leap_correct,leap_hit:cint);
  49. procedure GetLocalTimezone(timer:cint);
  50. procedure ReadTimezoneFile(fn:string);
  51. function GetTimezoneFile:string;
  52. Procedure ReReadLocalTime;
  53. {$ENDIF}
  54. {** Process Handling **}
  55. function FpExecLE (Const PathName:RawByteString;const S:Array Of RawByteString;MyEnv:ppchar):cint;
  56. function FpExecL (Const PathName:RawByteString;const S:Array Of RawByteString):cint;
  57. function FpExecLP (Const PathName:RawByteString;const S:Array Of RawByteString):cint;
  58. function FpExecLPE(Const PathName:RawByteString;const S:Array Of RawByteString;env:ppchar):cint;
  59. function FpExecV (Const PathName:RawByteString;args:ppchar):cint;
  60. function FpExecVP (Const PathName:RawByteString;args:ppchar):cint;
  61. function FpExecVPE(Const PathName:RawByteString;args,env:ppchar):cint;
  62. Function fpSystem(const Command:RawByteString):cint;
  63. Function WaitProcess (Pid:cint):cint;
  64. Function WIFSTOPPED (Status: Integer): Boolean;
  65. Function W_EXITCODE (ReturnCode, Signal: Integer): Integer;
  66. Function W_STOPCODE (Signal: Integer): Integer;
  67. {** File Handling **}
  68. Function fpFlock (var T : text;mode : cint) : cint;
  69. Function fpFlock (var F : File;mode : cint) : cint;
  70. {** Directory Handling **}
  71. procedure SeekDir(p:pdir;loc:clong);
  72. function TellDir(p:pdir):TOff;
  73. {** Pipe/Fifo/Stream **}
  74. Function AssignPipe (var pipe_in,pipe_out:cint):cint;
  75. Function AssignPipe (var pipe_in,pipe_out:text):cint;
  76. Function AssignPipe (var pipe_in,pipe_out:file):cint;
  77. Function POpen (var F:text;const Prog:RawByteString;rw:char):cint;
  78. Function POpen (var F:file;const Prog:RawByteString;rw:char):cint;
  79. Function POpen (var F:text;const Prog:UnicodeString;rw:char):cint;
  80. Function POpen (var F:file;const Prog:UnicodeString;rw:char):cint;
  81. Function AssignStream(Var StreamIn,Streamout:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  82. Function AssignStream(Var StreamIn,Streamout,streamerr:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  83. Function GetDomainName:String; deprecated; // because linux only.
  84. Function GetHostName:String;
  85. {** Utility functions **}
  86. Type
  87. TFSearchOption = (NoCurrentDirectory,
  88. CurrentDirectoryFirst,
  89. CurrentDirectoryLast);
  90. Function FSearch (const path:RawByteString;dirlist:RawByteString;CurrentDirStrategy:TFSearchOption):RawByteString;
  91. Function FSearch (const path:RawByteString;dirlist:RawByteString):RawByteString;
  92. Function FSearch (const path:UnicodeString;dirlist:UnicodeString;CurrentDirStrategy:TFSearchOption):UnicodeString;
  93. Function FSearch (const path:UnicodeString;dirlist:UnicodeString):UnicodeString;
  94. {$ifdef FPC_USE_LIBC}
  95. const clib = 'c';
  96. {$i unxdeclh.inc}
  97. {$else}
  98. {$i unxsysch.inc} // calls used in system and not reexported from baseunix
  99. {$endif}
  100. {******************************************************************************
  101. Implementation
  102. ******************************************************************************}
  103. {$i unxovlh.inc}
  104. Implementation
  105. Uses
  106. UnixUtil // tzseconds
  107. {$ifndef FPC_USE_LIBC},Syscall{$endif}
  108. ;
  109. {$i unxovl.inc}
  110. {$ifndef FPC_USE_LIBC}
  111. {$i syscallh.inc}
  112. {$i unxsysc.inc}
  113. {$endif}
  114. {$i unxfunc.inc} { Platform specific implementations }
  115. Function getenv(name:string):Pchar; external name 'FPC_SYSC_FPGETENV';
  116. {******************************************************************************
  117. Process related calls
  118. ******************************************************************************}
  119. { Most calls of WaitPID do not handle the result correctly, this funktion treats errors more correctly }
  120. 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}
  121. var
  122. r,s : cint;
  123. begin
  124. s:=$7F00;
  125. repeat
  126. r:=fpWaitPid(Pid,@s,0);
  127. if (r=-1) and (fpgeterrno=ESysEIntr) Then
  128. r:=0;
  129. until (r<>0);
  130. if (r=-1) or (r=0) then // 0 is not a valid return and should never occur (it means status invalid when using WNOHANG)
  131. WaitProcess:=-1 // return -1 to indicate an error. fpwaitpid updated it.
  132. else
  133. begin
  134. if wifexited(s) then
  135. WaitProcess:=wexitstatus(s)
  136. else if (s>0) then // Until now there is not use of the highest bit , but check this for the future
  137. WaitProcess:=-s // normal case
  138. else
  139. WaitProcess:=s; // s<0 should not occur, but wie return also a negativ value
  140. end;
  141. end;
  142. function intFpExecVEMaybeP (Const PathName:RawByteString;Args,MyEnv:ppchar;SearchPath:Boolean):cint;
  143. // does an ExecVE, but still has to handle P
  144. // execv variants call this directly, execl variants indirectly via
  145. // intfpexecl
  146. Var
  147. NewCmd : RawByteString;
  148. ThePath : RawByteString;
  149. Begin
  150. If SearchPath and (pos('/',pathname)=0) Then
  151. Begin
  152. // The above could be better. (check if not escaped/quoted '/'s) ?
  153. // (Jilles says this is ok)
  154. // Stevens says only search if newcmd contains no '/'
  155. // fsearch is not ansistring clean yet.
  156. ThePath:=fpgetenv('PATH');
  157. SetCodePage(ThePath,DefaultSystemCodePage,false);
  158. SetCodePage(ThePath,DefaultFileSystemCodePage,true);
  159. if thepath='' then
  160. thepath:='.'; // FreeBSD uses _PATH_DEFPATH = /usr/bin:/bin
  161. // but a quick check showed that _PATH_DEFPATH
  162. // varied from OS to OS
  163. newcmd:=ToSingleByteFileSystemEncodedFileName(FSearch(pathname,thepath,NoCurrentDirectory));
  164. // FreeBSD libc keeps on trying till a file is successfully run.
  165. // Stevens says "try each path prefix"
  166. // execp puts newcmd here.
  167. args^:=pchar(newcmd);
  168. End else
  169. newcmd:=ToSingleByteFileSystemEncodedFileName(pathname);
  170. // repeat
  171. // if searchpath then args^:=pchar(commandtorun)
  172. IntFpExecVEMaybeP:=fpExecVE(newcmd,Args,MyEnv);
  173. {
  174. // Code that if exec fails due to permissions, tries to run it with sh
  175. // Should we deallocate p on fail? -> no fpexit is run no matter what
  176. //
  177. }
  178. // if intfpexecvemaybep=-1 then seach next file.
  179. // until (Goexit) or SearchExit;
  180. {
  181. If IntFpExec=-1 Then
  182. Begin
  183. Error:=fpGetErrno
  184. Case Error of
  185. ESysE2Big : Exit(-1);
  186. ESysELoop,
  187. : Exit(-1);
  188. }
  189. end;
  190. function intFpExecl (Const PathName:RawByteString;const s:array of RawByteString;MyEnv:ppchar;SearchPath:Boolean):cint;
  191. { Handles the array of ansistring -> ppchar conversion.
  192. Base for the the "l" variants.
  193. }
  194. var p:ppchar;
  195. i:integer;
  196. s2:array of Rawbytestring;
  197. begin
  198. If PathName='' Then
  199. Begin
  200. fpsetErrno(ESysEnoEnt);
  201. Exit(-1); // Errno?
  202. End;
  203. setlength(s2,high(s)+1);
  204. for i:=low(s) to high(s) do
  205. s2[i]:=ToSingleByteFileSystemEncodedFileName(s[i]);
  206. p:=ArrayStringToPPchar(s2,1);
  207. if p=NIL Then
  208. Begin
  209. GetMem(p,2*sizeof(pchar));
  210. if p=nil then
  211. begin
  212. {$ifdef xunix}
  213. fpseterrno(ESysEnoMem);
  214. {$endif}
  215. fpseterrno(ESysEnoEnt);
  216. exit(-1);
  217. end;
  218. p[1]:=nil;
  219. End;
  220. p^:=pchar(PathName);
  221. IntFPExecL:=intFpExecVEMaybeP(PathName,p,MyEnv,SearchPath);
  222. // If we come here, no attempts were executed successfully.
  223. Freemem(p);
  224. end;
  225. function FpExecLE (Const PathName:RawByteString;const S:Array Of RawByteString;MyEnv:ppchar):cint;
  226. Begin
  227. FpExecLE:=intFPExecl(PathName,s,MyEnv,false);
  228. End;
  229. function FpExecL(Const PathName:RawByteString;const S:Array Of RawByteString):cint;
  230. Begin
  231. FpExecL:=intFPExecl(PathName,S,EnvP,false);
  232. End;
  233. function FpExecLP(Const PathName:RawByteString;const S:Array Of RawByteString):cint;
  234. Begin
  235. FpExecLP:=intFPExecl(PathName,S,EnvP,True);
  236. End;
  237. function FpExecLPE(Const PathName:RawByteString;const S:Array Of RawByteString;env:ppchar):cint;
  238. Begin
  239. FpExecLPE:=intFPExecl(PathName,S,Env,True);
  240. End;
  241. function FpExecV(Const PathName:RawByteString;args:ppchar):cint;
  242. Begin
  243. fpexecV:=intFpExecVEMaybeP (PathName,args,envp,false);
  244. End;
  245. function FpExecVP(Const PathName:RawByteString;args:ppchar):cint;
  246. Begin
  247. fpexecVP:=intFpExecVEMaybeP (PathName,args,envp,true);
  248. End;
  249. function FpExecVPE(Const PathName:RawByteString;args,env:ppchar):cint;
  250. Begin
  251. fpexecVPE:=intFpExecVEMaybeP (PathName,args,env,true);
  252. End;
  253. // exect and execvP (ExecCapitalP) are not implement
  254. // Non POSIX anyway.
  255. // Exect turns on tracing for the process
  256. // execvP has the searchpath as array of ansistring ( const char *search_path)
  257. {$define FPC_USE_FPEXEC}
  258. {$if defined(FPC_USE_FPEXEC) and not defined(USE_VFORK)}
  259. {$define SHELL_USE_FPEXEC}
  260. {$endif}
  261. {$ifdef FPC_USE_LIBC}
  262. function xfpsystem(p:pchar):cint; cdecl; external clib name 'system';
  263. Function fpSystem(const Command:RawByteString):cint;
  264. var
  265. cmd: RawByteString;
  266. begin
  267. cmd:=ToSingleByteFileSystemEncodedFileName(Command);
  268. fpsystem:=xfpsystem(pchar(cmd));
  269. end;
  270. {$else}
  271. Function fpSystem(const Command:RawByteString):cint;
  272. var
  273. pid,savedpid : cint;
  274. pstat : cint;
  275. ign,intact,
  276. quitact : SigactionRec;
  277. newsigblock,
  278. oldsigblock : tsigset;
  279. {$ifndef SHELL_USE_FPEXEC}
  280. p : ppchar;
  281. {$endif}
  282. cmd : RawByteString;
  283. begin { Changes as above }
  284. { fpexec* take care of converting the command to the right code page }
  285. if command='' then exit(1);
  286. {$ifndef SHELL_USE_FPEXEC}
  287. p:=CreateShellArgv(command);
  288. {$endif}
  289. ign.sa_handler:=SigActionHandler(SIG_IGN);
  290. fpsigemptyset(ign.sa_mask);
  291. ign.sa_flags:=0;
  292. fpsigaction(SIGINT, @ign, @intact);
  293. fpsigaction(SIGQUIT, @ign, @quitact);
  294. fpsigemptyset(newsigblock);
  295. fpsigaddset(newsigblock,SIGCHLD);
  296. fpsigprocmask(SIG_BLOCK,newsigblock,oldsigblock);
  297. {$ifdef USE_VFORK}
  298. pid:=fpvfork;
  299. {$else USE_VFORK}
  300. pid:=fpfork;
  301. {$endif USE_VFORK}
  302. if pid=0 then // We are in the Child
  303. begin
  304. fpsigaction(SIGINT,@intact,NIL);
  305. fpsigaction(SIGQUIT,@quitact,NIL);
  306. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  307. {$ifndef SHELL_USE_FPEXEC}
  308. fpExecve(p^,p,envp);
  309. {$else}
  310. fpexecl('/bin/sh',['-c',Command]);
  311. {$endif}
  312. fpExit(127); // was exit(127)!! We must exit the Process, not the function
  313. end
  314. else if (pid<>-1) then // Successfull started
  315. begin
  316. savedpid:=pid;
  317. repeat
  318. pid:=fpwaitpid(savedpid,@pstat,0);
  319. until (pid<>-1) and (fpgeterrno()<>ESysEintr);
  320. if pid=-1 Then
  321. fpsystem:=-1
  322. else
  323. fpsystem:=pstat;
  324. end
  325. else // no success
  326. fpsystem:=-1;
  327. fpsigaction(SIGINT,@intact,NIL);
  328. fpsigaction(SIGQUIT,@quitact,NIL);
  329. fpsigprocmask(SIG_SETMASK,@oldsigblock,NIL);
  330. {$ifndef SHELL_USE_FPEXEC}
  331. FreeShellArgV(p);
  332. {$endif}
  333. end;
  334. {$endif}
  335. Function WIFSTOPPED(Status: Integer): Boolean;
  336. begin
  337. WIFSTOPPED:=((Status and $FF)=$7F);
  338. end;
  339. Function W_EXITCODE(ReturnCode, Signal: Integer): Integer;
  340. begin
  341. W_EXITCODE:=(ReturnCode shl 8) or Signal;
  342. end;
  343. Function W_STOPCODE(Signal: Integer): Integer;
  344. begin
  345. W_STOPCODE:=(Signal shl 8) or $7F;
  346. end;
  347. {$IFNDEF DONT_READ_TIMEZONE}
  348. { Include timezone handling routines which use /usr/share/timezone info }
  349. {$i timezone.inc}
  350. {$endif}
  351. {******************************************************************************
  352. FileSystem calls
  353. ******************************************************************************}
  354. Function fpFlock (var T : text;mode : cint) : cint;
  355. begin
  356. {$ifndef beos}
  357. fpFlock:=fpFlock(TextRec(T).Handle,mode);
  358. {$endif}
  359. end;
  360. Function fpFlock (var F : File;mode : cint) :cint;
  361. begin
  362. {$ifndef beos}
  363. fpFlock:=fpFlock(FileRec(F).Handle,mode);
  364. {$endif}
  365. end;
  366. Function SelectText(var T:Text;TimeOut :PTimeval):cint;
  367. Var
  368. F:TfdSet;
  369. begin
  370. if textrec(t).mode=fmclosed then
  371. begin
  372. fpseterrno(ESysEBADF);
  373. exit(-1);
  374. end;
  375. FpFD_ZERO(f);
  376. fpFD_SET(textrec(T).handle,f);
  377. if textrec(T).mode=fminput then
  378. SelectText:=fpselect(textrec(T).handle+1,@f,nil,nil,TimeOut)
  379. else
  380. SelectText:=fpselect(textrec(T).handle+1,nil,@f,nil,TimeOut);
  381. end;
  382. Function SelectText(var T:Text;TimeOut :cint):cint;
  383. var
  384. p : PTimeVal;
  385. tv : TimeVal;
  386. begin
  387. if TimeOut=-1 then
  388. p:=nil
  389. else
  390. begin
  391. tv.tv_Sec:=Timeout div 1000;
  392. tv.tv_Usec:=(Timeout mod 1000)*1000;
  393. p:=@tv;
  394. end;
  395. SelectText:=SelectText(T,p);
  396. end;
  397. {******************************************************************************
  398. Directory
  399. ******************************************************************************}
  400. procedure SeekDir(p:pdir;loc:clong);
  401. begin
  402. if p=nil then
  403. begin
  404. fpseterrno(ESysEBADF);
  405. exit;
  406. end;
  407. {$if not(defined(bsd)) and not(defined(solaris)) and not(defined(beos)) and not(defined(aix)) }
  408. p^.dd_nextoff:=fplseek(p^.dd_fd,loc,seek_set);
  409. {$endif}
  410. {$if not(defined(beos))}
  411. p^.dd_size:=0;
  412. p^.dd_loc:=0;
  413. {$endif}
  414. end;
  415. function TellDir(p:pdir):TOff;
  416. begin
  417. if p=nil then
  418. begin
  419. fpseterrno(ESysEBADF);
  420. telldir:=-1;
  421. exit;
  422. end;
  423. {$ifndef beos}
  424. telldir:=fplseek(p^.dd_fd,0,seek_cur)
  425. {$endif}
  426. { We could try to use the nextoff field here, but on my 1.2.13
  427. kernel, this gives nothing... This may have to do with
  428. the readdir implementation of libc... I also didn't find any trace of
  429. the field in the kernel code itself, So I suspect it is an artifact of libc.
  430. Michael. }
  431. end;
  432. {******************************************************************************
  433. Pipes/Fifo
  434. ******************************************************************************}
  435. Procedure OpenPipe(var F:Text);
  436. begin
  437. case textrec(f).mode of
  438. fmoutput :
  439. if textrec(f).userdata[1]<>P_OUT then
  440. textrec(f).mode:=fmclosed;
  441. fminput :
  442. if textrec(f).userdata[1]<>P_IN then
  443. textrec(f).mode:=fmclosed;
  444. else
  445. textrec(f).mode:=fmclosed;
  446. end;
  447. end;
  448. Function IOPipe(var F:text):cint;
  449. begin
  450. IOPipe:=0;
  451. case textrec(f).mode of
  452. fmoutput :
  453. begin
  454. { first check if we need something to write, else we may
  455. get a SigPipe when Close() is called (PFV) }
  456. if textrec(f).bufpos>0 then
  457. IOPipe:=fpwrite(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufpos);
  458. end;
  459. fminput : Begin
  460. textrec(f).bufend:=fpread(textrec(f).handle,pchar(textrec(f).bufptr),textrec(f).bufsize);
  461. IOPipe:=textrec(f).bufend;
  462. End;
  463. end;
  464. textrec(f).bufpos:=0;
  465. end;
  466. Function FlushPipe(var F:Text):cint;
  467. begin
  468. FlushPipe:=0;
  469. if (textrec(f).mode=fmoutput) and (textrec(f).bufpos<>0) then
  470. FlushPipe:=IOPipe(f);
  471. textrec(f).bufpos:=0;
  472. end;
  473. Function ClosePipe(var F:text):cint;
  474. begin
  475. textrec(f).mode:=fmclosed;
  476. ClosePipe:=fpclose(textrec(f).handle);
  477. end;
  478. Function AssignPipe(var pipe_in,pipe_out:text):cint;
  479. {
  480. Sets up a pair of file variables, which act as a pipe. The first one can
  481. be read from, the second one can be written to.
  482. }
  483. var
  484. f_in,f_out : cint;
  485. begin
  486. if AssignPipe(f_in,f_out)=-1 then
  487. exit(-1);
  488. { Set up input }
  489. Assign(Pipe_in,'');
  490. Textrec(Pipe_in).Handle:=f_in;
  491. Textrec(Pipe_in).Mode:=fmInput;
  492. Textrec(Pipe_in).userdata[1]:=P_IN;
  493. TextRec(Pipe_in).OpenFunc:=@OpenPipe;
  494. TextRec(Pipe_in).InOutFunc:=@IOPipe;
  495. TextRec(Pipe_in).FlushFunc:=@FlushPipe;
  496. TextRec(Pipe_in).CloseFunc:=@ClosePipe;
  497. { Set up output }
  498. Assign(Pipe_out,'');
  499. Textrec(Pipe_out).Handle:=f_out;
  500. Textrec(Pipe_out).Mode:=fmOutput;
  501. Textrec(Pipe_out).userdata[1]:=P_OUT;
  502. TextRec(Pipe_out).OpenFunc:=@OpenPipe;
  503. TextRec(Pipe_out).InOutFunc:=@IOPipe;
  504. TextRec(Pipe_out).FlushFunc:=@FlushPipe;
  505. TextRec(Pipe_out).CloseFunc:=@ClosePipe;
  506. AssignPipe:=0;
  507. end;
  508. Function AssignPipe(var pipe_in,pipe_out:file):cint;
  509. {
  510. Sets up a pair of file variables, which act as a pipe. The first one can
  511. be read from, the second one can be written to.
  512. If the operation was unsuccesful,
  513. }
  514. var
  515. f_in,f_out : cint;
  516. begin
  517. if AssignPipe(f_in,f_out)=-1 then
  518. exit(-1);
  519. { Set up input }
  520. Assign(Pipe_in,'');
  521. Filerec(Pipe_in).Handle:=f_in;
  522. Filerec(Pipe_in).Mode:=fmInput;
  523. Filerec(Pipe_in).recsize:=1;
  524. Filerec(Pipe_in).userdata[1]:=P_IN;
  525. { Set up output }
  526. Assign(Pipe_out,'');
  527. Filerec(Pipe_out).Handle:=f_out;
  528. Filerec(Pipe_out).Mode:=fmoutput;
  529. Filerec(Pipe_out).recsize:=1;
  530. Filerec(Pipe_out).userdata[1]:=P_OUT;
  531. AssignPipe:=0;
  532. end;
  533. Function PCloseText(Var F:text):cint;
  534. {
  535. May not use @PClose due overloading
  536. }
  537. begin
  538. PCloseText:=PClose(f);
  539. end;
  540. Function POpen_internal(var F:text;const Prog:RawByteString;rw:char):cint;
  541. {
  542. Starts the program in 'Prog' and makes it's input or out put the
  543. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  544. F, will be read from stdin by the program in 'Prog'. The inverse is true
  545. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  546. read from 'f'.
  547. }
  548. var
  549. pipi,
  550. pipo : text;
  551. pid : cint;
  552. pl : ^cint;
  553. {$if not defined(FPC_USE_FPEXEC) or defined(USE_VFORK)}
  554. pp : array[0..3] of pchar;
  555. temp : string[255];
  556. {$endif not FPC_USE_FPEXEC or USE_VFORK}
  557. ret : cint;
  558. begin
  559. rw:=upcase(rw);
  560. if not (rw in ['R','W']) then
  561. begin
  562. FpSetErrno(ESysEnoent);
  563. exit(-1);
  564. end;
  565. ret:=AssignPipe(pipi,pipo);
  566. if ret=-1 then
  567. exit(-1);
  568. {$ifdef USE_VFORK}
  569. pid:=fpvfork;
  570. {$else USE_VFORK}
  571. pid:=fpfork;
  572. {$endif USE_VFORK}
  573. if pid=-1 then
  574. begin
  575. close(pipi);
  576. close(pipo);
  577. exit(-1);
  578. end;
  579. if pid=0 then
  580. begin
  581. { We're in the child }
  582. if rw='W' then
  583. begin
  584. if (textrec(pipi).handle <> stdinputhandle) then
  585. begin
  586. ret:=fpdup2(pipi,input);
  587. {$ifdef USE_VFORK}
  588. fpclose(textrec(pipi).handle);
  589. {$else USE_VFORK}
  590. close(pipi);
  591. {$endif USE_VFORK}
  592. end;
  593. {$ifdef USE_VFORK}
  594. fpclose(textrec(pipo).handle);
  595. {$else USE_VFORK}
  596. close(pipo);
  597. {$endif USE_VFORK}
  598. if ret=-1 then
  599. fpexit(127);
  600. end
  601. else
  602. begin
  603. {$ifdef USE_VFORK}
  604. fpclose(textrec(pipi).handle);
  605. {$else USE_VFORK}
  606. close(pipi);
  607. {$endif USE_VFORK}
  608. if (textrec(pipo).handle <> stdoutputhandle) then
  609. begin
  610. ret:=fpdup2(pipo,output);
  611. {$ifdef USE_VFORK}
  612. fpclose(textrec(pipo).handle);
  613. {$else USE_VFORK}
  614. close(pipo);
  615. {$endif USE_VFORK}
  616. end;
  617. if ret=-1 then
  618. fpexit(127);
  619. end;
  620. {$if defined(FPC_USE_FPEXEC) and not defined(USE_VFORK)}
  621. fpexecl(pchar('/bin/sh'),['-c',Prog]);
  622. {$else}
  623. temp:='/bin/sh'#0'-c'#0;
  624. pp[0]:=@temp[1];
  625. pp[1]:=@temp[9];
  626. pp[2]:=@prog[1];
  627. pp[3]:=Nil;
  628. fpExecve('/bin/sh',@pp,envp);
  629. {$endif}
  630. fpexit(127);
  631. end
  632. else
  633. begin
  634. { We're in the parent }
  635. if rw='W' then
  636. begin
  637. close(pipi);
  638. f:=pipo;
  639. end
  640. else
  641. begin
  642. close(pipo);
  643. f:=pipi;
  644. end;
  645. textrec(f).bufptr:=@textrec(f).buffer;
  646. {Save the process ID - needed when closing }
  647. pl:=pcint(@textrec(f).userdata[2]);
  648. { avoid alignment error on sparc }
  649. move(pid,pl^,sizeof(pid));
  650. textrec(f).closefunc:=@PCloseText;
  651. end;
  652. POpen_internal:=0;
  653. end;
  654. Function POpen_internal(var F:file;const Prog:RawByteString;rw:char):cint;
  655. {
  656. Starts the program in 'Prog' and makes it's input or out put the
  657. other end of a pipe. If rw is 'w' or 'W', then whatever is written to
  658. F, will be read from stdin by the program in 'Prog'. The inverse is true
  659. for 'r' or 'R' : whatever the program in 'Prog' writes to stdout, can be
  660. read from 'f'.
  661. }
  662. var
  663. pipi,
  664. pipo : file;
  665. pid : cint;
  666. pl : ^cint;
  667. {$if not defined(FPC_USE_FPEXEC) or defined(USE_VFORK)}
  668. pp : array[0..3] of pchar;
  669. temp : string[255];
  670. {$endif not FPC_USE_FPEXEC or USE_VFORK}
  671. ret : cint;
  672. begin
  673. rw:=upcase(rw);
  674. if not (rw in ['R','W']) then
  675. begin
  676. FpSetErrno(ESysEnoent);
  677. exit(-1);
  678. end;
  679. ret:=AssignPipe(pipi,pipo);
  680. if ret=-1 then
  681. exit(-1);
  682. {$ifdef USE_VFORK}
  683. pid:=fpvfork;
  684. {$else USE_VFORK}
  685. pid:=fpfork;
  686. {$endif USE_VFORK}
  687. if pid=-1 then
  688. begin
  689. close(pipi);
  690. close(pipo);
  691. exit(-1);
  692. end;
  693. if pid=0 then
  694. begin
  695. { We're in the child }
  696. if rw='W' then
  697. begin
  698. if (filerec(pipi).handle <> stdinputhandle) then
  699. begin
  700. ret:=fpdup2(filerec(pipi).handle,stdinputhandle);
  701. {$ifdef USE_VFORK}
  702. fpclose(filerec(pipi).handle);
  703. {$else USE_VFORK}
  704. close(pipi);
  705. {$endif USE_VFORK}
  706. end;
  707. {$ifdef USE_VFORK}
  708. fpclose(filerec(pipo).handle);
  709. {$else USE_VFORK}
  710. close(pipo);
  711. {$endif USE_VFORK}
  712. if ret=-1 then
  713. fpexit(127);
  714. end
  715. else
  716. begin
  717. {$ifdef USE_VFORK}
  718. fpclose(filerec(pipi).handle);
  719. {$else USE_VFORK}
  720. close(pipi);
  721. {$endif USE_VFORK}
  722. if (filerec(pipo).handle <> stdoutputhandle) then
  723. begin
  724. ret:=fpdup2(filerec(pipo).handle,stdoutputhandle);
  725. {$ifdef USE_VFORK}
  726. fpclose(filerec(pipo).handle);
  727. {$else USE_VFORK}
  728. close(pipo);
  729. {$endif USE_VFORK}
  730. end;
  731. if ret=-1 then
  732. fpexit(127);
  733. end;
  734. {$if defined(FPC_USE_FPEXEC) and not defined(USE_VFORK)}
  735. fpexecl(pchar('/bin/sh'),['-c',Prog]);
  736. {$else}
  737. temp:='/bin/sh'#0'-c'#0;
  738. pp[0]:=@temp[1];
  739. pp[1]:=@temp[9];
  740. pp[2]:=@prog[1];
  741. pp[3]:=Nil;
  742. fpExecve('/bin/sh',@pp,envp);
  743. {$endif}
  744. fpexit(127);
  745. end
  746. else
  747. begin
  748. { We're in the parent }
  749. if rw='W' then
  750. begin
  751. close(pipi);
  752. f:=pipo;
  753. end
  754. else
  755. begin
  756. close(pipo);
  757. f:=pipi;
  758. end;
  759. {Save the process ID - needed when closing }
  760. pl:=pcint(@filerec(f).userdata[2]);
  761. { avoid alignment error on sparc }
  762. move(pid,pl^,sizeof(pid));
  763. end;
  764. POpen_internal:=0;
  765. end;
  766. Function POpen(var F:text;const Prog:RawByteString;rw:char):cint;
  767. begin
  768. { can't do the ToSingleByteFileSystemEncodedFileName() conversion inside
  769. POpen_internal, because this may destroy the temp rawbytestring result
  770. of that function in the parent before the child is finished with it }
  771. POpen:=POpen_internal(F,ToSingleByteFileSystemEncodedFileName(Prog),rw);
  772. end;
  773. Function POpen(var F:file;const Prog:RawByteString;rw:char):cint;
  774. begin
  775. { can't do the ToSingleByteFileSystemEncodedFileName() conversion inside
  776. POpen_internal, because this may destroy the temp rawbytestring result
  777. of that function in the parent before the child is finished with it }
  778. POpen:=POpen_internal(F,ToSingleByteFileSystemEncodedFileName(Prog),rw);
  779. end;
  780. function POpen(var F: text; const Prog: UnicodeString; rw: char): cint;
  781. begin
  782. POpen:=POpen_internal(F,ToSingleByteFileSystemEncodedFileName(Prog),rw);
  783. end;
  784. function POpen(var F: file; const Prog: UnicodeString; rw: char): cint;
  785. begin
  786. POpen:=POpen_internal(F,ToSingleByteFileSystemEncodedFileName(Prog),rw);
  787. end;
  788. Function AssignStream(Var StreamIn,Streamout:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  789. {
  790. Starts the program in 'Prog' and makes its input and output the
  791. other end of two pipes, which are the stdin and stdout of a program
  792. specified in 'Prog'.
  793. streamout can be used to write to the program, streamin can be used to read
  794. the output of the program. See the following diagram :
  795. Parent Child
  796. STreamout --> Input
  797. Streamin <-- Output
  798. Return value is the process ID of the process being spawned, or -1 in case of failure.
  799. }
  800. var
  801. pipi,
  802. pipo : text;
  803. pid : cint;
  804. pl : ^cint;
  805. begin
  806. AssignStream:=-1;
  807. if AssignPipe(streamin,pipo)=-1 Then
  808. exit(-1);
  809. if AssignPipe(pipi,streamout)=-1 Then
  810. begin
  811. close(streamin);
  812. close(pipo);
  813. exit(-1);
  814. end;
  815. pid:=fpfork;
  816. if pid=-1 then
  817. begin
  818. close(pipi);
  819. close(pipo);
  820. close (streamin);
  821. close (streamout);
  822. exit;
  823. end;
  824. if pid=0 then
  825. begin
  826. { We're in the child }
  827. { Close what we don't need }
  828. close(streamout);
  829. close(streamin);
  830. if fpdup2(pipi,input)=-1 Then
  831. halt(127);
  832. close(pipi);
  833. If fpdup2(pipo,output)=-1 Then
  834. halt (127);
  835. close(pipo);
  836. fpExecl(Prog,args);
  837. halt(127);
  838. end
  839. else
  840. begin
  841. { we're in the parent}
  842. close(pipo);
  843. close(pipi);
  844. {Save the process ID - needed when closing }
  845. pl:=pcint(@textrec(StreamIn).userdata[2]);
  846. { avoid alignment error on sparc }
  847. move(pid,pl^,sizeof(pid));
  848. textrec(StreamIn).closefunc:=@PCloseText;
  849. {Save the process ID - needed when closing }
  850. pl:=pcint(@textrec(StreamOut).userdata[2]);
  851. { avoid alignment error on sparc }
  852. move(pid,pl^,sizeof(pid));
  853. textrec(StreamOut).closefunc:=@PCloseText;
  854. AssignStream:=Pid;
  855. end;
  856. end;
  857. Function AssignStream(Var StreamIn,Streamout,streamerr:text;Const Prog:ansiString;const args : array of ansistring) : cint;
  858. {
  859. Starts the program in 'prog' and makes its input, output and error output the
  860. other end of three pipes, which are the stdin, stdout and stderr of a program
  861. specified in 'prog'.
  862. StreamOut can be used to write to the program, StreamIn can be used to read
  863. the output of the program, StreamErr reads the error output of the program.
  864. See the following diagram :
  865. Parent Child
  866. StreamOut --> StdIn (input)
  867. StreamIn <-- StdOut (output)
  868. StreamErr <-- StdErr (error output)
  869. }
  870. var
  871. PipeIn, PipeOut, PipeErr: text;
  872. pid: cint;
  873. pl: ^cint;
  874. begin
  875. AssignStream := -1;
  876. // Assign pipes
  877. if AssignPipe(StreamIn, PipeOut)=-1 Then
  878. Exit(-1);
  879. If AssignPipe(StreamErr, PipeErr)=-1 Then
  880. begin
  881. Close(StreamIn);
  882. Close(PipeOut);
  883. exit(-1);
  884. end;
  885. if AssignPipe(PipeIn, StreamOut)=-1 Then
  886. begin
  887. Close(StreamIn);
  888. Close(PipeOut);
  889. Close(StreamErr);
  890. Close(PipeErr);
  891. exit(-1);
  892. end;
  893. // Fork
  894. pid := fpFork;
  895. if pid=-1 then begin
  896. Close(StreamIn);
  897. Close(PipeOut);
  898. Close(StreamErr);
  899. Close(PipeErr);
  900. Close(PipeIn);
  901. Close(StreamOut);
  902. exit(-1);
  903. end;
  904. if pid = 0 then begin
  905. // *** We are in the child ***
  906. // Close what we don not need
  907. Close(StreamOut);
  908. Close(StreamIn);
  909. Close(StreamErr);
  910. // Connect pipes
  911. if fpdup2(PipeIn, Input)=-1 Then
  912. Halt(127);
  913. Close(PipeIn);
  914. if fpdup2(PipeOut, Output)=-1 Then
  915. Halt(127);
  916. Close(PipeOut);
  917. if fpdup2(PipeErr, StdErr)=-1 Then
  918. Halt(127);
  919. Close(PipeErr);
  920. // Execute program
  921. fpExecl(Prog,args);
  922. Halt(127);
  923. end else begin
  924. // *** We are in the parent ***
  925. Close(PipeErr);
  926. Close(PipeOut);
  927. Close(PipeIn);
  928. // Save the process ID - needed when closing
  929. pl := pcint(@TextRec(StreamIn).userdata[2]);
  930. { avoid alignment error on sparc }
  931. move(pid,pl^,sizeof(pid));
  932. TextRec(StreamIn).closefunc := @PCloseText;
  933. // Save the process ID - needed when closing
  934. pl := pcint(@TextRec(StreamOut).userdata[2]);
  935. { avoid alignment error on sparc }
  936. move(pid,pl^,sizeof(pid));
  937. TextRec(StreamOut).closefunc := @PCloseText;
  938. // Save the process ID - needed when closing
  939. pl := pcint(@TextRec(StreamErr).userdata[2]);
  940. { avoid alignment error on sparc }
  941. move(pid,pl^,sizeof(pid));
  942. TextRec(StreamErr).closefunc := @PCloseText;
  943. AssignStream := pid;
  944. end;
  945. end;
  946. {******************************************************************************
  947. General information calls
  948. ******************************************************************************}
  949. {$if defined(Linux)}
  950. Function GetDomainName:String; { linux only!}
  951. // domainname is a glibc extension.
  952. {
  953. Get machines domain name. Returns empty string if not set.
  954. }
  955. Var
  956. Sysn : utsname;
  957. begin
  958. If fpUname(sysn)<>0 then
  959. getdomainname:=''
  960. else
  961. getdomainname:=strpas(@Sysn.domain[0]);
  962. end;
  963. {$endif}
  964. {$ifdef sunos}
  965. { sunos doesn't support GetDomainName, see also
  966. http://www.sun.com/software/solaris/programs/abi/appcert_faq.xml#q18
  967. }
  968. Function GetDomainName:String;
  969. begin
  970. GetDomainName:='';
  971. end;
  972. {$endif sunos}
  973. {$ifdef android}
  974. { android doesn't seem to implement GetDomainName
  975. }
  976. Function GetDomainName:String;
  977. begin
  978. GetDomainName:='';
  979. end;
  980. {$endif}
  981. {$if defined(BSD) or defined(aix)}
  982. function intGetDomainName(Name:PChar; NameLen:Cint):cint;
  983. {$ifndef FPC_USE_LIBC}
  984. external name 'FPC_SYSC_GETDOMAINNAME';
  985. {$else FPC_USE_LIBC}
  986. cdecl; external clib name 'getdomainname';
  987. {$endif FPC_USE_LIBC}
  988. Function GetDomainName:String; { linux only!}
  989. // domainname is a glibc extension.
  990. {
  991. Get machines domain name. Returns empty string if not set.
  992. }
  993. begin
  994. if intGetDomainName(@getdomainname[1],255)=-1 then
  995. getdomainname:=''
  996. else
  997. getdomainname[0]:=chr(strlen(@getdomainname[1]));
  998. end;
  999. {$endif}
  1000. Function GetHostName:String;
  1001. {
  1002. Get machines name. Returns empty string if not set.
  1003. }
  1004. Var
  1005. Sysn : utsname;
  1006. begin
  1007. If fpuname(sysn)=-1 then
  1008. gethostname:=''
  1009. else
  1010. gethostname:=strpas(@Sysn.nodename[0]);
  1011. end;
  1012. {******************************************************************************
  1013. Utility calls
  1014. ******************************************************************************}
  1015. Function FSearch(const path:RawByteString;dirlist:RawByteString;CurrentDirStrategy:TFSearchOption):RawByteString;
  1016. {
  1017. Searches for a file 'path' in the list of direcories in 'dirlist'.
  1018. returns an empty string if not found. Wildcards are NOT allowed.
  1019. If dirlist is empty, it is set to '.'
  1020. This function tries to make FSearch use ansistrings, and decrease
  1021. stringhandling overhead at the same time.
  1022. }
  1023. Var
  1024. mypath,
  1025. mydir,NewDir : RawByteString;
  1026. p1 : cint;
  1027. Info : Stat;
  1028. i,j : cint;
  1029. p : pchar;
  1030. Begin
  1031. SetCodePage(dirlist,DefaultFileSystemCodePage);
  1032. if CurrentDirStrategy=CurrentDirectoryFirst Then
  1033. Dirlist:=ToSingleByteFileSystemEncodedFileName('.:')+dirlist {Make sure current dir is first to be searched.}
  1034. else if CurrentDirStrategy=CurrentDirectoryLast Then
  1035. Dirlist:=dirlist+ToSingleByteFileSystemEncodedFileName('.:'); {Make sure current dir is last to be searched.}
  1036. {Replace ':' and ';' with #0}
  1037. for p1:=1 to length(dirlist) do
  1038. if (dirlist[p1]=':') or (dirlist[p1]=';') then
  1039. dirlist[p1]:=#0;
  1040. {Check for WildCards}
  1041. If (Pos('?',Path) <> 0) or (Pos('*',Path) <> 0) Then
  1042. FSearch:='' {No wildcards allowed in these things.}
  1043. Else
  1044. Begin
  1045. mypath:=ToSingleByteFileSystemEncodedFileName(path);
  1046. p:=pchar(dirlist);
  1047. i:=length(dirlist);
  1048. j:=1;
  1049. Repeat
  1050. mydir:=RawByteString(p);
  1051. if (length(mydir)>0) and (mydir[length(mydir)]<>'/') then
  1052. begin
  1053. { concatenate character without influencing code page }
  1054. setlength(mydir,length(mydir)+1);
  1055. mydir[length(mydir)]:='/';
  1056. end;
  1057. NewDir:=mydir+mypath;
  1058. if (FpStat(NewDir,Info)>=0) and
  1059. (not fpS_ISDIR(Info.st_Mode)) then
  1060. Begin
  1061. If Pos('./',NewDir)=1 Then
  1062. Delete(NewDir,1,2);
  1063. {DOS strips off an initial .\}
  1064. End
  1065. Else
  1066. NewDir:='';
  1067. while (j<=i) and (p^<>#0) do begin inc(j); inc(p); end;
  1068. if p^=#0 then inc(p);
  1069. Until (j>=i) or (Length(NewDir) > 0);
  1070. FSearch:=NewDir;
  1071. SetCodePage(FSearch,DefaultRTLFileSystemCodePage);
  1072. End;
  1073. End;
  1074. Function FSearch(const path:RawByteString;dirlist:RawByteString):RawByteString;
  1075. Begin
  1076. FSearch:=FSearch(path,dirlist,CurrentDirectoryFirst);
  1077. End;
  1078. function FSearch(const path: UnicodeString; dirlist: UnicodeString; CurrentDirStrategy: TFSearchOption): UnicodeString;
  1079. begin
  1080. FSearch:=FSearch(ToSingleByteFileSystemEncodedFileName(path),ToSingleByteFileSystemEncodedFileName(dirlist),CurrentDirStrategy);
  1081. end;
  1082. function FSearch(const path: UnicodeString; dirlist: UnicodeString): UnicodeString;
  1083. begin
  1084. FSearch:=FSearch(ToSingleByteFileSystemEncodedFileName(path),ToSingleByteFileSystemEncodedFileName(dirlist),CurrentDirectoryFirst);
  1085. end;
  1086. Initialization
  1087. {$IFNDEF DONT_READ_TIMEZONE}
  1088. InitLocalTime;
  1089. {$endif}
  1090. finalization
  1091. {$IFNDEF DONT_READ_TIMEZONE}
  1092. DoneLocalTime;
  1093. {$endif}
  1094. End.