unix.pp 48 KB

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