osmain.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Main OS dependant body of the system unit, loosely modelled
  5. after POSIX. *BSD version (Linux version is near identical)
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. const
  13. { Default creation mode for directories and files }
  14. { read/write permission for everyone }
  15. MODE_OPEN = S_IWUSR OR S_IRUSR OR
  16. S_IWGRP OR S_IRGRP OR
  17. S_IWOTH OR S_IROTH;
  18. { read/write search permission for everyone }
  19. MODE_MKDIR = MODE_OPEN OR
  20. S_IXUSR OR S_IXGRP OR S_IXOTH;
  21. {*****************************************************************************
  22. Misc. System Dependent Functions
  23. *****************************************************************************}
  24. procedure System_exit;
  25. begin
  26. Fpexit(cint(ExitCode));
  27. End;
  28. Function ParamCount: Longint;
  29. Begin
  30. Paramcount:=argc-1
  31. End;
  32. function BackPos(c:char; const s: shortstring): integer;
  33. var
  34. i: integer;
  35. Begin
  36. for i:=length(s) downto 0 do
  37. if s[i] = c then break;
  38. if i=0 then
  39. BackPos := 0
  40. else
  41. BackPos := i;
  42. end;
  43. { variable where full path and filename and executable is stored }
  44. { is setup by the startup of the system unit. }
  45. var
  46. execpathstr : shortstring;
  47. function paramstr(l: longint) : string;
  48. var
  49. s: string;
  50. s1: string;
  51. begin
  52. { stricly conforming POSIX applications }
  53. { have the executing filename as argv[0] }
  54. // if l=0 then
  55. // begin
  56. // paramstr := execpathstr;
  57. // end
  58. // else
  59. paramstr:=strpas(argv[l]);
  60. end;
  61. Procedure Randomize;
  62. Begin
  63. randseed:=longint(Fptime(nil));
  64. End;
  65. {*****************************************************************************
  66. Heap Management
  67. *****************************************************************************}
  68. var
  69. _HEAP : longint;external name 'HEAP';
  70. _HEAPSIZE : longint;external name 'HEAPSIZE';
  71. {$ifndef SYSTEM_HAS_GETHEAPSTART}
  72. function getheapstart:pointer;
  73. begin
  74. getheapstart := @_HEAP;
  75. end;
  76. {$endif}
  77. {$ifndef SYSTEM_HAS_GETHEAPSIZE}
  78. function getheapsize:longint;
  79. begin
  80. getheapsize := _HEAPSIZE;
  81. end;
  82. {$endif}
  83. {*****************************************************************************
  84. Low Level File Routines
  85. *****************************************************************************}
  86. {
  87. The lowlevel file functions should take care of setting the InOutRes to the
  88. correct value if an error has occured, else leave it untouched
  89. }
  90. Function PosixToRunError (PosixErrno : longint) : longint;
  91. {
  92. Convert ErrNo error to the correct Inoutres value
  93. }
  94. begin
  95. if PosixErrNo=0 then { Else it will go through all the cases }
  96. exit(0);
  97. case PosixErrNo of
  98. ESysENFILE,
  99. ESysEMFILE : Inoutres:=4;
  100. ESysENOENT : Inoutres:=2;
  101. ESysEBADF : Inoutres:=6;
  102. ESysENOMEM,
  103. ESysEFAULT : Inoutres:=217;
  104. ESysEINVAL : Inoutres:=218;
  105. ESysEPIPE,
  106. ESysEINTR,
  107. ESysEIO,
  108. ESysEAGAIN,
  109. ESysENOSPC : Inoutres:=101;
  110. ESysENAMETOOLONG : Inoutres := 3;
  111. ESysEROFS,
  112. ESysEEXIST,
  113. ESysENOTEMPTY,
  114. ESysEACCES : Inoutres:=5;
  115. ESysEISDIR : InOutRes:=5;
  116. else
  117. begin
  118. InOutRes := Integer(PosixErrno);
  119. end;
  120. end;
  121. PosixToRunError:=InOutRes;
  122. end;
  123. Function Errno2InoutRes : longint;
  124. begin
  125. Errno2InoutRes:=PosixToRunError(Errno);
  126. InoutRes:=Errno2InoutRes;
  127. end;
  128. Procedure Do_Close(Handle:Longint);
  129. Begin
  130. Fpclose(cint(Handle));
  131. End;
  132. Procedure Do_Erase(p:pchar);
  133. var
  134. fileinfo : stat;
  135. Begin
  136. { verify if the filename is actually a directory }
  137. { if so return error and do nothing, as defined }
  138. { by POSIX }
  139. if Fpstat(p,fileinfo)<0 then
  140. begin
  141. Errno2Inoutres;
  142. exit;
  143. end;
  144. if FpS_ISDIR(fileinfo.st_mode) then
  145. begin
  146. InOutRes := 2;
  147. exit;
  148. end;
  149. if Fpunlink(p)<0 then
  150. Errno2Inoutres
  151. Else
  152. InOutRes:=0;
  153. End;
  154. { truncate at a given position }
  155. procedure do_truncate (handle,fpos:longint);
  156. begin
  157. { should be simulated in cases where it is not }
  158. { available. }
  159. If Fpftruncate(handle,fpos)<0 Then
  160. Errno2Inoutres
  161. Else
  162. InOutRes:=0;
  163. end;
  164. Procedure Do_Rename(p1,p2:pchar);
  165. Begin
  166. If Fprename(p1,p2)<0 Then
  167. Errno2Inoutres
  168. Else
  169. InOutRes:=0;
  170. End;
  171. Function Do_Write(Handle,Addr,Len:Longint):longint;
  172. Begin
  173. repeat
  174. Do_Write:=Fpwrite(Handle,pchar(addr),len);
  175. until (do_write<>-1) or ((ErrNo<>ESysEINTR) and (Errno<>ESysEAgain));
  176. If Do_Write<0 Then
  177. Begin
  178. Errno2InOutRes;
  179. Do_Write:=0;
  180. End
  181. else
  182. InOutRes:=0;
  183. End;
  184. Function Do_Read(Handle,Addr,Len:Longint):Longint;
  185. Begin
  186. repeat
  187. Do_Read:=Fpread(Handle,pchar(addr),len);
  188. until (do_read<>-1) or ((ErrNo<>ESysEINTR) and (ErrNo<>ESysEAgain));
  189. If Do_Read<0 Then
  190. Begin
  191. Errno2InOutRes;
  192. Do_Read:=0;
  193. End
  194. else
  195. InOutRes:=0;
  196. End;
  197. function Do_FilePos(Handle: Longint):longint;
  198. Begin
  199. do_FilePos:=Fplseek(Handle, 0, SEEK_CUR);
  200. If Do_FilePos<0 Then
  201. Errno2InOutRes
  202. else
  203. InOutRes:=0;
  204. End;
  205. Procedure Do_Seek(Handle,Pos:Longint);
  206. Begin
  207. If Fplseek(Handle, pos, SEEK_SET)<0 Then
  208. Errno2Inoutres
  209. Else
  210. InOutRes:=0;
  211. End;
  212. Function Do_SeekEnd(Handle:Longint): Longint;
  213. begin
  214. Do_SeekEnd:=Fplseek(Handle,0,SEEK_END);
  215. If Do_SeekEnd<0 Then
  216. Errno2Inoutres
  217. Else
  218. InOutRes:=0;
  219. end;
  220. Function Do_FileSize(Handle:Longint): Longint;
  221. var
  222. Info : Stat;
  223. Ret : Longint;
  224. Begin
  225. Ret:=Fpfstat(handle,info);
  226. If Ret=0 Then
  227. Do_FileSize:=Info.st_size
  228. else
  229. Do_FileSize:=0;
  230. If Ret<0 Then
  231. Errno2InOutRes
  232. Else
  233. InOutRes:=0;
  234. End;
  235. Procedure Do_Open(var f;p:pchar;flags:longint);
  236. {
  237. FileRec and textrec have both Handle and mode as the first items so
  238. they could use the same routine for opening/creating.
  239. when (flags and $100) the file will be append
  240. when (flags and $1000) the file will be truncate/rewritten
  241. when (flags and $10000) there is no check for close (needed for textfiles)
  242. }
  243. var
  244. oflags : cint;
  245. Begin
  246. { close first if opened }
  247. if ((flags and $10000)=0) then
  248. begin
  249. case FileRec(f).mode of
  250. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  251. fmclosed : ;
  252. else
  253. begin
  254. inoutres:=102; {not assigned}
  255. exit;
  256. end;
  257. end;
  258. end;
  259. { reset file Handle }
  260. FileRec(f).Handle:=UnusedHandle;
  261. { We do the conversion of filemodes here, concentrated on 1 place }
  262. case (flags and 3) of
  263. 0 : begin
  264. oflags :=O_RDONLY;
  265. FileRec(f).mode:=fminput;
  266. end;
  267. 1 : begin
  268. oflags :=O_WRONLY;
  269. FileRec(f).mode:=fmoutput;
  270. end;
  271. 2 : begin
  272. oflags :=O_RDWR;
  273. FileRec(f).mode:=fminout;
  274. end;
  275. end;
  276. if (flags and $1000)=$1000 then
  277. oflags:=oflags or (O_CREAT or O_TRUNC)
  278. else
  279. if (flags and $100)=$100 then
  280. oflags:=oflags or (O_APPEND);
  281. { empty name is special }
  282. if p[0]=#0 then
  283. begin
  284. case FileRec(f).mode of
  285. fminput :
  286. FileRec(f).Handle:=StdInputHandle;
  287. fminout, { this is set by rewrite }
  288. fmoutput :
  289. FileRec(f).Handle:=StdOutputHandle;
  290. fmappend :
  291. begin
  292. FileRec(f).Handle:=StdOutputHandle;
  293. FileRec(f).mode:=fmoutput; {fool fmappend}
  294. end;
  295. end;
  296. exit;
  297. end;
  298. { real open call }
  299. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  300. if (FileRec(f).Handle<0) and
  301. (ErrNo=ESysEROFS) and ((OFlags and O_RDWR)<>0) then
  302. begin
  303. Oflags:=Oflags and not(O_RDWR);
  304. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  305. end;
  306. If Filerec(f).Handle<0 Then
  307. Errno2Inoutres
  308. else
  309. InOutRes:=0;
  310. End;
  311. {*****************************************************************************
  312. Directory Handling
  313. *****************************************************************************}
  314. Procedure MkDir(Const s: String);[IOCheck];
  315. Var
  316. Buffer: Array[0..255] of Char;
  317. Begin
  318. If (s='') or (InOutRes <> 0) then
  319. exit;
  320. Move(s[1], Buffer, Length(s));
  321. Buffer[Length(s)] := #0;
  322. If Fpmkdir(@buffer, MODE_MKDIR)<0 Then
  323. Errno2Inoutres
  324. Else
  325. InOutRes:=0;
  326. End;
  327. Procedure RmDir(Const s: String);[IOCheck];
  328. Var
  329. Buffer: Array[0..255] of Char;
  330. Begin
  331. if (s = '.') then
  332. InOutRes := 16;
  333. If (s='') or (InOutRes <> 0) then
  334. exit;
  335. Move(s[1], Buffer, Length(s));
  336. Buffer[Length(s)] := #0;
  337. If Fprmdir(@buffer)<0 Then
  338. Errno2Inoutres
  339. Else
  340. InOutRes:=0;
  341. End;
  342. Procedure ChDir(Const s: String);[IOCheck];
  343. Var
  344. Buffer: Array[0..255] of Char;
  345. Begin
  346. If (s='') or (InOutRes <> 0) then
  347. exit;
  348. Move(s[1], Buffer, Length(s));
  349. Buffer[Length(s)] := #0;
  350. If Fpchdir(@buffer)<0 Then
  351. Errno2Inoutres
  352. Else
  353. InOutRes:=0;
  354. { file not exists is path not found under tp7 }
  355. if InOutRes=2 then
  356. InOutRes:=3;
  357. End;
  358. { // $define usegetcwd}
  359. procedure getdir(drivenr : byte;var dir : shortstring);
  360. var
  361. {$ifndef usegetcwd}
  362. cwdinfo : stat;
  363. rootinfo : stat;
  364. thedir,dummy : string[255];
  365. dirstream : pdir;
  366. d : pdirent;
  367. name : string[255];
  368. thisdir : stat;
  369. {$endif}
  370. tmp : string[255];
  371. begin
  372. {$ifdef usegetcwd}
  373. Fpgetcwd(@tmp[1],255);
  374. dir:=tmp;
  375. {$else}
  376. dir:='';
  377. thedir:='';
  378. dummy:='';
  379. { get root directory information }
  380. tmp := '/'+#0;
  381. if Fpstat(@tmp[1],rootinfo)<0 then
  382. Exit;
  383. repeat
  384. tmp := dummy+'.'+#0;
  385. { get current directory information }
  386. if Fpstat(@tmp[1],cwdinfo)<0 then
  387. Exit;
  388. tmp:=dummy+'..'+#0;
  389. { open directory stream }
  390. { try to find the current inode number of the cwd }
  391. dirstream:=Fpopendir(@tmp[1]);
  392. if dirstream=nil then
  393. exit;
  394. repeat
  395. name:='';
  396. d:=Fpreaddir(dirstream);
  397. { no more entries to read ... }
  398. if not assigned(d) then
  399. break;
  400. tmp:=dummy+'../'+strpas(d^.d_name) + #0;
  401. if (Fpstat(@tmp[1],thisdir)=0) then
  402. begin
  403. { found the entry for this directory name }
  404. if (cwdinfo.st_dev=thisdir.st_dev) and (cwdinfo.st_ino=thisdir.st_ino) then
  405. begin
  406. { are the filenames of type '.' or '..' ? }
  407. { then do not set the name. }
  408. if (not ((d^.d_name[0]='.') and ((d^.d_name[1]=#0) or
  409. ((d^.d_name[1]='.') and (d^.d_name[2]=#0))))) then
  410. name:='/'+strpas(d^.d_name);
  411. end;
  412. end
  413. else
  414. begin
  415. if (Errno<>ESysENOENT) then
  416. Exit;
  417. end;
  418. until (name<>'');
  419. if Fpclosedir(dirstream)<0 then
  420. Exit;
  421. thedir:=name+thedir;
  422. dummy:=dummy+'../';
  423. if ((cwdinfo.st_dev=rootinfo.st_dev) and (cwdinfo.st_ino=rootinfo.st_ino)) then
  424. begin
  425. if thedir='' then
  426. dir:='/'
  427. else
  428. dir:=thedir;
  429. exit;
  430. end;
  431. until false;
  432. {$endif}
  433. end;
  434. {*****************************************************************************
  435. SystemUnit Initialization
  436. *****************************************************************************}
  437. function reenable_signal(sig : longint) : boolean;
  438. var
  439. e,oe : TSigSet;
  440. i,j : byte;
  441. begin
  442. fillchar(e,sizeof(e),#0);
  443. fillchar(oe,sizeof(oe),#0);
  444. { set is 1 based PM }
  445. dec(sig);
  446. i:=sig mod 32;
  447. j:=sig div 32;
  448. e[j]:=1 shl i;
  449. fpsigprocmask(SIG_UNBLOCK,@e,@oe);
  450. reenable_signal:=geterrno=0;
  451. end;
  452. procedure SignalToRunerror(Sig: cint; var info : tsiginfo_t;Var SigContext:SigContextRec); cdecl;
  453. var
  454. res : word;
  455. begin
  456. res:=0;
  457. case sig of
  458. SIGFPE :
  459. begin
  460. Case Info.si_code Of
  461. FPE_INTDIV : Res:=200; {integer divide fault. Div0?}
  462. FPE_FLTOVF : Res:=205; {Overflow trap}
  463. FPE_FLTUND : Res:=206; {Stack over/underflow}
  464. FPE_FLTRES : Res:=216; {Device not available}
  465. FPE_FLTINV : Res:=216; {Invalid floating point operation}
  466. Else
  467. Res:=208; {coprocessor error}
  468. End;
  469. sysResetFPU;
  470. End;
  471. SIGILL,
  472. SIGBUS,
  473. SIGSEGV :
  474. res:=216;
  475. end;
  476. {$ifdef FPC_USE_SIGPROCMASK}
  477. reenable_signal(sig);
  478. {$endif }
  479. { give runtime error at the position where the signal was raised }
  480. if res<>0 then
  481. begin
  482. {$ifdef I386}
  483. HandleErrorAddrFrame(res,Pointer(SigContext.sc_eip),pointer(SigContext.sc_ebp));
  484. {$else}
  485. HandleError(res);
  486. {$endif}
  487. end;
  488. end;
  489. {
  490. procedure SignalToRunerror(signo: cint); cdecl;
  491. var
  492. res : word;
  493. begin
  494. res:=0;
  495. if signo = SIGFPE then
  496. begin
  497. res := 200;
  498. end
  499. else
  500. if (signo = SIGILL) or (signo = SIGBUS) or (signo = SIGSEGV) then
  501. begin
  502. res := 216;
  503. end;
  504. { give runtime error at the position where the signal was raised }
  505. if res<>0 then
  506. begin
  507. HandleError(res);
  508. end;
  509. end;
  510. }
  511. var
  512. act: SigActionRec;
  513. Procedure InstallSignals;
  514. var
  515. oldact: SigActionRec;
  516. begin
  517. { Initialize the sigaction structure }
  518. { all flags and information set to zero }
  519. FillChar(act, sizeof(SigActionRec),0);
  520. { initialize handler }
  521. act.sa_handler :=@SignalToRunError;
  522. act.sa_flags:=SA_SIGINFO;
  523. FpSigAction(SIGFPE,act,oldact);
  524. FpSigAction(SIGSEGV,act,oldact);
  525. FpSigAction(SIGBUS,act,oldact);
  526. FpSigAction(SIGILL,act,oldact);
  527. end;
  528. procedure SetupCmdLine;
  529. var
  530. bufsize,
  531. len,j,
  532. size,i : longint;
  533. found : boolean;
  534. buf : pchar;
  535. procedure AddBuf;
  536. begin
  537. reallocmem(cmdline,size+bufsize);
  538. move(buf^,cmdline[size],bufsize);
  539. inc(size,bufsize);
  540. bufsize:=0;
  541. end;
  542. begin
  543. GetMem(buf,ARG_MAX);
  544. size:=0;
  545. bufsize:=0;
  546. i:=0;
  547. while (i<argc) do
  548. begin
  549. len:=strlen(argv[i]);
  550. if len>ARG_MAX-2 then
  551. len:=ARG_MAX-2;
  552. found:=false;
  553. for j:=1 to len do
  554. if argv[i][j]=' ' then
  555. begin
  556. found:=true;
  557. break;
  558. end;
  559. if bufsize+len>=ARG_MAX-2 then
  560. AddBuf;
  561. if found then
  562. begin
  563. buf[bufsize]:='"';
  564. inc(bufsize);
  565. end;
  566. move(argv[i]^,buf[bufsize],len);
  567. inc(bufsize,len);
  568. if found then
  569. begin
  570. buf[bufsize]:='"';
  571. inc(bufsize);
  572. end;
  573. if i<argc then
  574. buf[bufsize]:=' '
  575. else
  576. buf[bufsize]:=#0;
  577. inc(bufsize);
  578. inc(i);
  579. end;
  580. AddBuf;
  581. FreeMem(buf,ARG_MAX);
  582. end;
  583. (*
  584. Begin
  585. { Set up signals handlers }
  586. InstallSignals;
  587. { Setup heap }
  588. InitHeap;
  589. InitExceptions;
  590. { Arguments }
  591. SetupCmdLine;
  592. { Setup stdin, stdout and stderr }
  593. OpenStdIO(Input,fmInput,StdInputHandle);
  594. OpenStdIO(Output,fmOutput,StdOutputHandle);
  595. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  596. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  597. { Reset IO Error }
  598. InOutRes:=0;
  599. End.
  600. *)
  601. {
  602. $Log$
  603. Revision 1.7 2003-12-14 14:47:02 marco
  604. * fix for repeating 'x' bug
  605. Revision 1.6 2003/11/18 10:12:25 marco
  606. * Small fixes for EAGAIN. bunxfunc only has comments added.
  607. Revision 1.5 2003/10/27 17:12:45 marco
  608. * fixes for signal handling.
  609. Revision 1.4 2003/10/26 17:01:04 marco
  610. * moved sigprocmask to system
  611. Revision 1.3 2003/09/27 13:04:58 peter
  612. * fpISxxx renamed
  613. Revision 1.2 2003/05/29 20:54:09 marco
  614. * progname fix.
  615. Revision 1.1 2003/01/05 19:01:28 marco
  616. * FreeBSD compiles now with baseunix mods.
  617. }