osmain.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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(getErrno);
  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:Longint;Addr:Pointer;Len:Longint):longint;
  172. var j : cint;
  173. Begin
  174. repeat
  175. Do_Write:=Fpwrite(Handle,addr,len);
  176. j:=geterrno;
  177. until (do_write<>-1) or ((j<>ESysEINTR) and (j<>ESysEAgain));
  178. If Do_Write<0 Then
  179. Begin
  180. Errno2InOutRes;
  181. Do_Write:=0;
  182. End
  183. else
  184. InOutRes:=0;
  185. End;
  186. Function Do_Read(Handle:Longint;Addr:Pointer;Len:Longint):Longint;
  187. var j:cint;
  188. Begin
  189. repeat
  190. Do_Read:=Fpread(Handle,addr,len);
  191. j:=geterrno;
  192. until (do_read<>-1) or ((j<>ESysEINTR) and (j<>ESysEAgain));
  193. If Do_Read<0 Then
  194. Begin
  195. Errno2InOutRes;
  196. Do_Read:=0;
  197. End
  198. else
  199. InOutRes:=0;
  200. End;
  201. function Do_FilePos(Handle: Longint):longint;
  202. Begin
  203. do_FilePos:=Fplseek(Handle, 0, SEEK_CUR);
  204. If Do_FilePos<0 Then
  205. Errno2InOutRes
  206. else
  207. InOutRes:=0;
  208. End;
  209. Procedure Do_Seek(Handle,Pos:Longint);
  210. Begin
  211. If Fplseek(Handle, pos, SEEK_SET)<0 Then
  212. Errno2Inoutres
  213. Else
  214. InOutRes:=0;
  215. End;
  216. Function Do_SeekEnd(Handle:Longint): Longint;
  217. begin
  218. Do_SeekEnd:=Fplseek(Handle,0,SEEK_END);
  219. If Do_SeekEnd<0 Then
  220. Errno2Inoutres
  221. Else
  222. InOutRes:=0;
  223. end;
  224. Function Do_FileSize(Handle:Longint): Longint;
  225. var
  226. Info : Stat;
  227. Ret : Longint;
  228. Begin
  229. Ret:=Fpfstat(handle,info);
  230. If Ret=0 Then
  231. Do_FileSize:=Info.st_size
  232. else
  233. Do_FileSize:=0;
  234. If Ret<0 Then
  235. Errno2InOutRes
  236. Else
  237. InOutRes:=0;
  238. End;
  239. Procedure Do_Open(var f;p:pchar;flags:longint);
  240. {
  241. FileRec and textrec have both Handle and mode as the first items so
  242. they could use the same routine for opening/creating.
  243. when (flags and $100) the file will be append
  244. when (flags and $1000) the file will be truncate/rewritten
  245. when (flags and $10000) there is no check for close (needed for textfiles)
  246. }
  247. var
  248. oflags : cint;
  249. Begin
  250. { close first if opened }
  251. if ((flags and $10000)=0) then
  252. begin
  253. case FileRec(f).mode of
  254. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  255. fmclosed : ;
  256. else
  257. begin
  258. inoutres:=102; {not assigned}
  259. exit;
  260. end;
  261. end;
  262. end;
  263. { reset file Handle }
  264. FileRec(f).Handle:=UnusedHandle;
  265. { We do the conversion of filemodes here, concentrated on 1 place }
  266. case (flags and 3) of
  267. 0 : begin
  268. oflags :=O_RDONLY;
  269. FileRec(f).mode:=fminput;
  270. end;
  271. 1 : begin
  272. oflags :=O_WRONLY;
  273. FileRec(f).mode:=fmoutput;
  274. end;
  275. 2 : begin
  276. oflags :=O_RDWR;
  277. FileRec(f).mode:=fminout;
  278. end;
  279. end;
  280. if (flags and $1000)=$1000 then
  281. oflags:=oflags or (O_CREAT or O_TRUNC)
  282. else
  283. if (flags and $100)=$100 then
  284. oflags:=oflags or (O_APPEND or O_CREAT);
  285. { empty name is special }
  286. if p[0]=#0 then
  287. begin
  288. case FileRec(f).mode of
  289. fminput :
  290. FileRec(f).Handle:=StdInputHandle;
  291. fminout, { this is set by rewrite }
  292. fmoutput :
  293. FileRec(f).Handle:=StdOutputHandle;
  294. fmappend :
  295. begin
  296. FileRec(f).Handle:=StdOutputHandle;
  297. FileRec(f).mode:=fmoutput; {fool fmappend}
  298. end;
  299. end;
  300. exit;
  301. end;
  302. { real open call }
  303. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  304. if (FileRec(f).Handle<0) and
  305. (getErrNo=ESysEROFS) and ((OFlags and O_RDWR)<>0) then
  306. begin
  307. Oflags:=Oflags and not(O_RDWR);
  308. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  309. end;
  310. If Filerec(f).Handle<0 Then
  311. Errno2Inoutres
  312. else
  313. InOutRes:=0;
  314. End;
  315. {*****************************************************************************
  316. Directory Handling
  317. *****************************************************************************}
  318. Procedure MkDir(Const s: String);[IOCheck];
  319. Var
  320. Buffer: Array[0..255] of Char;
  321. Begin
  322. If (s='') or (InOutRes <> 0) then
  323. exit;
  324. Move(s[1], Buffer, Length(s));
  325. Buffer[Length(s)] := #0;
  326. If Fpmkdir(@buffer, MODE_MKDIR)<0 Then
  327. Errno2Inoutres
  328. Else
  329. InOutRes:=0;
  330. End;
  331. Procedure RmDir(Const s: String);[IOCheck];
  332. Var
  333. Buffer: Array[0..255] of Char;
  334. Begin
  335. if (s = '.') then
  336. InOutRes := 16;
  337. If (s='') or (InOutRes <> 0) then
  338. exit;
  339. Move(s[1], Buffer, Length(s));
  340. Buffer[Length(s)] := #0;
  341. If Fprmdir(@buffer)<0 Then
  342. Errno2Inoutres
  343. Else
  344. InOutRes:=0;
  345. End;
  346. Procedure ChDir(Const s: String);[IOCheck];
  347. Var
  348. Buffer: Array[0..255] of Char;
  349. Begin
  350. If (s='') or (InOutRes <> 0) then
  351. exit;
  352. Move(s[1], Buffer, Length(s));
  353. Buffer[Length(s)] := #0;
  354. If Fpchdir(@buffer)<0 Then
  355. Errno2Inoutres
  356. Else
  357. InOutRes:=0;
  358. { file not exists is path not found under tp7 }
  359. if InOutRes=2 then
  360. InOutRes:=3;
  361. End;
  362. { // $define usegetcwd}
  363. procedure getdir(drivenr : byte;var dir : shortstring);
  364. var
  365. {$ifndef usegetcwd}
  366. cwdinfo : stat;
  367. rootinfo : stat;
  368. thedir,dummy : string[255];
  369. dirstream : pdir;
  370. d : pdirent;
  371. name : string[255];
  372. thisdir : stat;
  373. {$endif}
  374. tmp : string[255];
  375. begin
  376. {$ifdef usegetcwd}
  377. Fpgetcwd(@tmp[1],4096);
  378. dir:=tmp;
  379. {$else}
  380. dir:='';
  381. thedir:='';
  382. dummy:='';
  383. { get root directory information }
  384. tmp := '/'+#0;
  385. if Fpstat(@tmp[1],rootinfo)<0 then
  386. Exit;
  387. repeat
  388. tmp := dummy+'.'+#0;
  389. { get current directory information }
  390. if Fpstat(@tmp[1],cwdinfo)<0 then
  391. Exit;
  392. tmp:=dummy+'..'+#0;
  393. { open directory stream }
  394. { try to find the current inode number of the cwd }
  395. dirstream:=Fpopendir(@tmp[1]);
  396. if dirstream=nil then
  397. exit;
  398. repeat
  399. name:='';
  400. d:=Fpreaddir(dirstream);
  401. { no more entries to read ... }
  402. if not assigned(d) then
  403. break;
  404. tmp:=dummy+'../'+strpas(d^.d_name) + #0;
  405. if (Fpstat(@tmp[1],thisdir)=0) then
  406. begin
  407. { found the entry for this directory name }
  408. if (cwdinfo.st_dev=thisdir.st_dev) and (cwdinfo.st_ino=thisdir.st_ino) then
  409. begin
  410. { are the filenames of type '.' or '..' ? }
  411. { then do not set the name. }
  412. if (not ((d^.d_name[0]='.') and ((d^.d_name[1]=#0) or
  413. ((d^.d_name[1]='.') and (d^.d_name[2]=#0))))) then
  414. name:='/'+strpas(d^.d_name);
  415. end;
  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. {$i sighnd.inc}
  452. var
  453. act: SigActionRec;
  454. Procedure InstallSignals;
  455. var
  456. oldact: SigActionRec;
  457. begin
  458. { Initialize the sigaction structure }
  459. { all flags and information set to zero }
  460. FillChar(act, sizeof(SigActionRec),0);
  461. { initialize handler }
  462. act.sa_handler :=@SignalToRunError;
  463. act.sa_flags:=SA_SIGINFO;
  464. FpSigAction(SIGFPE,act,oldact);
  465. FpSigAction(SIGSEGV,act,oldact);
  466. FpSigAction(SIGBUS,act,oldact);
  467. FpSigAction(SIGILL,act,oldact);
  468. end;
  469. procedure SetupCmdLine;
  470. var
  471. bufsize,
  472. len,j,
  473. size,i : longint;
  474. found : boolean;
  475. buf : pchar;
  476. procedure AddBuf;
  477. begin
  478. reallocmem(cmdline,size+bufsize);
  479. move(buf^,cmdline[size],bufsize);
  480. inc(size,bufsize);
  481. bufsize:=0;
  482. end;
  483. begin
  484. GetMem(buf,ARG_MAX);
  485. size:=0;
  486. bufsize:=0;
  487. i:=0;
  488. while (i<argc) do
  489. begin
  490. len:=strlen(argv[i]);
  491. if len>ARG_MAX-2 then
  492. len:=ARG_MAX-2;
  493. found:=false;
  494. for j:=1 to len do
  495. if argv[i][j]=' ' then
  496. begin
  497. found:=true;
  498. break;
  499. end;
  500. if bufsize+len>=ARG_MAX-2 then
  501. AddBuf;
  502. if found then
  503. begin
  504. buf[bufsize]:='"';
  505. inc(bufsize);
  506. end;
  507. move(argv[i]^,buf[bufsize],len);
  508. inc(bufsize,len);
  509. if found then
  510. begin
  511. buf[bufsize]:='"';
  512. inc(bufsize);
  513. end;
  514. if i<argc then
  515. buf[bufsize]:=' '
  516. else
  517. buf[bufsize]:=#0;
  518. inc(bufsize);
  519. inc(i);
  520. end;
  521. AddBuf;
  522. FreeMem(buf,ARG_MAX);
  523. end;
  524. {
  525. $Log$
  526. Revision 1.13 2004-04-22 21:10:56 peter
  527. * do_read/do_write addr argument changed to pointer
  528. Revision 1.12 2004/01/06 15:42:05 marco
  529. * o_creat added when o_append
  530. Revision 1.11 2004/01/03 14:56:10 marco
  531. * typo fix
  532. Revision 1.10 2004/01/03 12:35:39 marco
  533. * sighnd to separate file, like linux. Some comments removed
  534. Revision 1.9 2003/12/30 12:26:21 marco
  535. * FPC_USE_LIBC
  536. Revision 1.8 2003/12/21 20:31:50 peter
  537. * fix getdir when directory contains files that give EACCESS
  538. Revision 1.7 2003/12/14 14:47:02 marco
  539. * fix for repeating 'x' bug
  540. Revision 1.6 2003/11/18 10:12:25 marco
  541. * Small fixes for EAGAIN. bunxfunc only has comments added.
  542. Revision 1.5 2003/10/27 17:12:45 marco
  543. * fixes for signal handling.
  544. Revision 1.4 2003/10/26 17:01:04 marco
  545. * moved sigprocmask to system
  546. Revision 1.3 2003/09/27 13:04:58 peter
  547. * fpISxxx renamed
  548. Revision 1.2 2003/05/29 20:54:09 marco
  549. * progname fix.
  550. Revision 1.1 2003/01/05 19:01:28 marco
  551. * FreeBSD compiles now with baseunix mods.
  552. }