unix.pp 33 KB

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