2
0

unix.pp 32 KB

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