osmain.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  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 ErrNo<>ESysEINTR;
  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 ErrNo<>ESysEINTR;
  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 (ErrNo=ESysEROFS) and ((OFlags and O_RDWR)<>0) then
  301. begin
  302. Oflags:=Oflags and not(O_RDWR);
  303. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  304. end;
  305. If Filerec(f).Handle<0 Then
  306. Errno2Inoutres
  307. else
  308. InOutRes:=0;
  309. End;
  310. {*****************************************************************************
  311. Directory Handling
  312. *****************************************************************************}
  313. Procedure MkDir(Const s: String);[IOCheck];
  314. Var
  315. Buffer: Array[0..255] of Char;
  316. Begin
  317. If (s='') or (InOutRes <> 0) then
  318. exit;
  319. Move(s[1], Buffer, Length(s));
  320. Buffer[Length(s)] := #0;
  321. If Fpmkdir(@buffer, MODE_MKDIR)<0 Then
  322. Errno2Inoutres
  323. Else
  324. InOutRes:=0;
  325. End;
  326. Procedure RmDir(Const s: String);[IOCheck];
  327. Var
  328. Buffer: Array[0..255] of Char;
  329. Begin
  330. if (s = '.') then
  331. InOutRes := 16;
  332. If (s='') or (InOutRes <> 0) then
  333. exit;
  334. Move(s[1], Buffer, Length(s));
  335. Buffer[Length(s)] := #0;
  336. If Fprmdir(@buffer)<0 Then
  337. Errno2Inoutres
  338. Else
  339. InOutRes:=0;
  340. End;
  341. Procedure ChDir(Const s: String);[IOCheck];
  342. Var
  343. Buffer: Array[0..255] of Char;
  344. Begin
  345. If (s='') or (InOutRes <> 0) then
  346. exit;
  347. Move(s[1], Buffer, Length(s));
  348. Buffer[Length(s)] := #0;
  349. If Fpchdir(@buffer)<0 Then
  350. Errno2Inoutres
  351. Else
  352. InOutRes:=0;
  353. { file not exists is path not found under tp7 }
  354. if InOutRes=2 then
  355. InOutRes:=3;
  356. End;
  357. { // $define usegetcwd}
  358. procedure getdir(drivenr : byte;var dir : shortstring);
  359. var
  360. {$ifndef usegetcwd}
  361. cwdinfo : stat;
  362. rootinfo : stat;
  363. thedir,dummy : string[255];
  364. dirstream : pdir;
  365. d : pdirent;
  366. name : string[255];
  367. thisdir : stat;
  368. {$endif}
  369. tmp : string[255];
  370. begin
  371. {$ifdef usegetcwd}
  372. Fpgetcwd(@tmp[1],255);
  373. dir:=tmp;
  374. {$else}
  375. dir:='';
  376. thedir:='';
  377. dummy:='';
  378. { get root directory information }
  379. tmp := '/'+#0;
  380. if Fpstat(@tmp[1],rootinfo)<0 then
  381. Exit;
  382. repeat
  383. tmp := dummy+'.'+#0;
  384. { get current directory information }
  385. if Fpstat(@tmp[1],cwdinfo)<0 then
  386. Exit;
  387. tmp:=dummy+'..'+#0;
  388. { open directory stream }
  389. { try to find the current inode number of the cwd }
  390. dirstream:=Fpopendir(@tmp[1]);
  391. if dirstream=nil then
  392. exit;
  393. repeat
  394. name:='';
  395. d:=Fpreaddir(dirstream);
  396. { no more entries to read ... }
  397. if not assigned(d) then
  398. break;
  399. tmp:=dummy+'../'+strpas(d^.d_name) + #0;
  400. if (Fpstat(@tmp[1],thisdir)=0) then
  401. begin
  402. { found the entry for this directory name }
  403. if (cwdinfo.st_dev=thisdir.st_dev) and (cwdinfo.st_ino=thisdir.st_ino) then
  404. begin
  405. { are the filenames of type '.' or '..' ? }
  406. { then do not set the name. }
  407. if (not ((d^.d_name[0]='.') and ((d^.d_name[1]=#0) or
  408. ((d^.d_name[1]='.') and (d^.d_name[2]=#0))))) then
  409. name:='/'+strpas(d^.d_name);
  410. end;
  411. end
  412. else
  413. begin
  414. if (Errno<>ESysENOENT) then
  415. Exit;
  416. end;
  417. until (name<>'');
  418. if Fpclosedir(dirstream)<0 then
  419. Exit;
  420. thedir:=name+thedir;
  421. dummy:=dummy+'../';
  422. if ((cwdinfo.st_dev=rootinfo.st_dev) and (cwdinfo.st_ino=rootinfo.st_ino)) then
  423. begin
  424. if thedir='' then
  425. dir:='/'
  426. else
  427. dir:=thedir;
  428. exit;
  429. end;
  430. until false;
  431. {$endif}
  432. end;
  433. {*****************************************************************************
  434. SystemUnit Initialization
  435. *****************************************************************************}
  436. function reenable_signal(sig : longint) : boolean;
  437. var
  438. e,oe : TSigSet;
  439. i,j : byte;
  440. begin
  441. fillchar(e,sizeof(e),#0);
  442. fillchar(oe,sizeof(oe),#0);
  443. { set is 1 based PM }
  444. dec(sig);
  445. i:=sig mod 32;
  446. j:=sig div 32;
  447. e[j]:=1 shl i;
  448. fpsigprocmask(SIG_UNBLOCK,@e,@oe);
  449. reenable_signal:=geterrno=0;
  450. end;
  451. procedure SignalToRunerror(Sig: cint; var info : tsiginfo_t;Var SigContext:SigContextRec); cdecl;
  452. var
  453. res : word;
  454. begin
  455. res:=0;
  456. case sig of
  457. SIGFPE :
  458. begin
  459. Case Info.si_code Of
  460. FPE_INTDIV : Res:=200; {integer divide fault. Div0?}
  461. FPE_FLTOVF : Res:=205; {Overflow trap}
  462. FPE_FLTUND : Res:=206; {Stack over/underflow}
  463. FPE_FLTRES : Res:=216; {Device not available}
  464. FPE_FLTINV : Res:=216; {Invalid floating point operation}
  465. Else
  466. Res:=208; {coprocessor error}
  467. End;
  468. sysResetFPU;
  469. End;
  470. SIGILL,
  471. SIGBUS,
  472. SIGSEGV :
  473. res:=216;
  474. end;
  475. {$ifdef FPC_USE_SIGPROCMASK}
  476. reenable_signal(sig);
  477. {$endif }
  478. { give runtime error at the position where the signal was raised }
  479. if res<>0 then
  480. begin
  481. {$ifdef I386}
  482. HandleErrorAddrFrame(res,Pointer(SigContext.sc_eip),pointer(SigContext.sc_ebp));
  483. {$else}
  484. HandleError(res);
  485. {$endif}
  486. end;
  487. end;
  488. {
  489. procedure SignalToRunerror(signo: cint); cdecl;
  490. var
  491. res : word;
  492. begin
  493. res:=0;
  494. if signo = SIGFPE then
  495. begin
  496. res := 200;
  497. end
  498. else
  499. if (signo = SIGILL) or (signo = SIGBUS) or (signo = SIGSEGV) then
  500. begin
  501. res := 216;
  502. end;
  503. { give runtime error at the position where the signal was raised }
  504. if res<>0 then
  505. begin
  506. HandleError(res);
  507. end;
  508. end;
  509. }
  510. var
  511. act: SigActionRec;
  512. Procedure InstallSignals;
  513. var
  514. oldact: SigActionRec;
  515. begin
  516. { Initialize the sigaction structure }
  517. { all flags and information set to zero }
  518. FillChar(act, sizeof(SigActionRec),0);
  519. { initialize handler }
  520. act.sa_handler :=@SignalToRunError;
  521. act.sa_flags:=SA_SIGINFO;
  522. FpSigAction(SIGFPE,act,oldact);
  523. FpSigAction(SIGSEGV,act,oldact);
  524. FpSigAction(SIGBUS,act,oldact);
  525. FpSigAction(SIGILL,act,oldact);
  526. end;
  527. procedure SetupCmdLine;
  528. var
  529. bufsize,
  530. len,j,
  531. size,i : longint;
  532. found : boolean;
  533. buf : pchar;
  534. procedure AddBuf;
  535. begin
  536. reallocmem(cmdline,size+bufsize);
  537. move(buf^,cmdline[size],bufsize);
  538. inc(size,bufsize);
  539. bufsize:=0;
  540. end;
  541. begin
  542. GetMem(buf,ARG_MAX);
  543. size:=0;
  544. bufsize:=0;
  545. i:=0;
  546. while (i<argc) do
  547. begin
  548. len:=strlen(argv[i]);
  549. if len>ARG_MAX-2 then
  550. len:=ARG_MAX-2;
  551. found:=false;
  552. for j:=1 to len do
  553. if argv[i][j]=' ' then
  554. begin
  555. found:=true;
  556. break;
  557. end;
  558. if bufsize+len>=ARG_MAX-2 then
  559. AddBuf;
  560. if found then
  561. begin
  562. buf[bufsize]:='"';
  563. inc(bufsize);
  564. end;
  565. move(argv[i]^,buf[bufsize],len);
  566. inc(bufsize,len);
  567. if found then
  568. begin
  569. buf[bufsize]:='"';
  570. inc(bufsize);
  571. end;
  572. if i<argc then
  573. buf[bufsize]:=' '
  574. else
  575. buf[bufsize]:=#0;
  576. inc(bufsize);
  577. inc(i);
  578. end;
  579. AddBuf;
  580. FreeMem(buf,ARG_MAX);
  581. end;
  582. (*
  583. Begin
  584. { Set up signals handlers }
  585. InstallSignals;
  586. { Setup heap }
  587. InitHeap;
  588. InitExceptions;
  589. { Arguments }
  590. SetupCmdLine;
  591. { Setup stdin, stdout and stderr }
  592. OpenStdIO(Input,fmInput,StdInputHandle);
  593. OpenStdIO(Output,fmOutput,StdOutputHandle);
  594. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  595. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  596. { Reset IO Error }
  597. InOutRes:=0;
  598. End.
  599. *)
  600. {
  601. $Log$
  602. Revision 1.5 2003-10-27 17:12:45 marco
  603. * fixes for signal handling.
  604. Revision 1.4 2003/10/26 17:01:04 marco
  605. * moved sigprocmask to system
  606. Revision 1.3 2003/09/27 13:04:58 peter
  607. * fpISxxx renamed
  608. Revision 1.2 2003/05/29 20:54:09 marco
  609. * progname fix.
  610. Revision 1.1 2003/01/05 19:01:28 marco
  611. * FreeBSD compiles now with baseunix mods.
  612. }