unix.pp 49 KB

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