osmain.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. POSIX Interface to the system unit
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This is the core of the system unit *nix systems (now FreeBSD
  8. and Unix).
  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. const
  14. { Default creation mode for directories and files }
  15. { read/write permission for everyone }
  16. MODE_OPEN = S_IWUSR OR S_IRUSR OR
  17. S_IWGRP OR S_IRGRP OR
  18. S_IWOTH OR S_IROTH;
  19. { read/write search permission for everyone }
  20. MODE_MKDIR = MODE_OPEN OR
  21. S_IXUSR OR S_IXGRP OR S_IXOTH;
  22. {*****************************************************************************
  23. Misc. System Dependent Functions
  24. *****************************************************************************}
  25. procedure haltproc(e:longint);cdecl;external name '_haltproc';
  26. procedure System_exit;
  27. begin
  28. haltproc(ExitCode);
  29. End;
  30. Function ParamCount: Longint;
  31. Begin
  32. Paramcount:=argc-1
  33. End;
  34. function BackPos(c:char; const s: shortstring): integer;
  35. var
  36. i: integer;
  37. Begin
  38. for i:=length(s) downto 0 do
  39. if s[i] = c then break;
  40. if i=0 then
  41. BackPos := 0
  42. else
  43. BackPos := i;
  44. end;
  45. { variable where full path and filename and executable is stored }
  46. { is setup by the startup of the system unit. }
  47. var
  48. execpathstr : shortstring;
  49. function paramstr(l: longint) : string;
  50. begin
  51. { stricly conforming POSIX applications }
  52. { have the executing filename as argv[0] }
  53. if l=0 then
  54. begin
  55. paramstr := execpathstr;
  56. end
  57. else
  58. paramstr:=strpas(argv[l]);
  59. end;
  60. Procedure Randomize;
  61. Begin
  62. randseed:=longint(Fptime(nil));
  63. End;
  64. {*****************************************************************************
  65. Low Level File Routines
  66. *****************************************************************************}
  67. {
  68. The lowlevel file functions should take care of setting the InOutRes to the
  69. correct value if an error has occured, else leave it untouched
  70. }
  71. Function PosixToRunError (PosixErrno : longint) : longint;
  72. {
  73. Convert ErrNo error to the correct Inoutres value
  74. }
  75. begin
  76. if PosixErrNo=0 then { Else it will go through all the cases }
  77. exit(0);
  78. case PosixErrNo of
  79. ESysENFILE,
  80. ESysEMFILE : Inoutres:=4;
  81. ESysENOENT : Inoutres:=2;
  82. ESysEBADF : Inoutres:=6;
  83. ESysENOMEM,
  84. ESysEFAULT : Inoutres:=217;
  85. ESysEINVAL : Inoutres:=218;
  86. ESysEPIPE,
  87. ESysEINTR,
  88. ESysEIO,
  89. ESysEAGAIN,
  90. ESysENOSPC : Inoutres:=101;
  91. ESysENAMETOOLONG : Inoutres := 3;
  92. ESysEROFS,
  93. ESysEEXIST,
  94. ESysENOTEMPTY,
  95. ESysEACCES : Inoutres:=5;
  96. ESysEISDIR : InOutRes:=5;
  97. else
  98. begin
  99. InOutRes := Integer(PosixErrno);
  100. end;
  101. end;
  102. PosixToRunError:=InOutRes;
  103. end;
  104. Function Errno2InoutRes : longint;
  105. begin
  106. Errno2InoutRes:=PosixToRunError(getErrno);
  107. InoutRes:=Errno2InoutRes;
  108. end;
  109. Procedure Do_Close(Handle:thandle);
  110. Begin
  111. Fpclose(cint(Handle));
  112. End;
  113. Procedure Do_Erase(p:pchar);
  114. var
  115. fileinfo : stat;
  116. Begin
  117. { verify if the filename is actually a directory }
  118. { if so return error and do nothing, as defined }
  119. { by POSIX }
  120. if Fpstat(p,fileinfo)<0 then
  121. begin
  122. Errno2Inoutres;
  123. exit;
  124. end;
  125. if FpS_ISDIR(fileinfo.st_mode) then
  126. begin
  127. InOutRes := 2;
  128. exit;
  129. end;
  130. if Fpunlink(p)<0 then
  131. Errno2Inoutres
  132. Else
  133. InOutRes:=0;
  134. End;
  135. { truncate at a given position }
  136. procedure do_truncate (handle:thandle;fpos:longint);
  137. begin
  138. { should be simulated in cases where it is not }
  139. { available. }
  140. If Fpftruncate(handle,fpos)<0 Then
  141. Errno2Inoutres
  142. Else
  143. InOutRes:=0;
  144. end;
  145. Procedure Do_Rename(p1,p2:pchar);
  146. Begin
  147. If Fprename(p1,p2)<0 Then
  148. Errno2Inoutres
  149. Else
  150. InOutRes:=0;
  151. End;
  152. Function Do_Write(Handle:thandle;Addr:Pointer;Len:SizeInt):SizeInt;
  153. Begin
  154. repeat
  155. Do_Write:=Fpwrite(Handle,addr,len);
  156. until (Do_Write>=0) or (getErrNo<>ESysEINTR);
  157. If Do_Write<0 Then
  158. Begin
  159. Errno2InOutRes;
  160. Do_Write:=0;
  161. End
  162. else
  163. InOutRes:=0;
  164. End;
  165. Function Do_Read(Handle:thandle;Addr:Pointer;Len:SizeInt):SizeInt;
  166. Begin
  167. repeat
  168. Do_Read:=Fpread(Handle,addr,len);
  169. until (Do_Read>=0) or (getErrNo<>ESysEINTR);
  170. If Do_Read<0 Then
  171. Begin
  172. Errno2InOutRes;
  173. Do_Read:=0;
  174. End
  175. else
  176. InOutRes:=0;
  177. End;
  178. function Do_FilePos(Handle: thandle):longint;
  179. Begin
  180. do_FilePos:=Fplseek(Handle, 0, SEEK_CUR);
  181. If Do_FilePos<0 Then
  182. Errno2InOutRes
  183. else
  184. InOutRes:=0;
  185. End;
  186. Procedure Do_Seek(Handle:thandle;Pos:Longint);
  187. Begin
  188. If Fplseek(Handle, pos, SEEK_SET)<0 Then
  189. Errno2Inoutres
  190. Else
  191. InOutRes:=0;
  192. End;
  193. Function Do_SeekEnd(Handle:thandle): Longint;
  194. begin
  195. Do_SeekEnd:=Fplseek(Handle,0,SEEK_END);
  196. If Do_SeekEnd<0 Then
  197. Errno2Inoutres
  198. Else
  199. InOutRes:=0;
  200. end;
  201. Function Do_FileSize(Handle:thandle): Longint;
  202. var
  203. Info : Stat;
  204. Ret : Longint;
  205. Begin
  206. Ret:=Fpfstat(handle,info);
  207. If Ret=0 Then
  208. Do_FileSize:=Info.st_size
  209. else
  210. Do_FileSize:=0;
  211. If Ret<0 Then
  212. Errno2InOutRes
  213. Else
  214. InOutRes:=0;
  215. End;
  216. Procedure Do_Open(var f;p:pchar;flags:longint);
  217. {
  218. FileRec and textrec have both Handle and mode as the first items so
  219. they could use the same routine for opening/creating.
  220. when (flags and $100) the file will be append
  221. when (flags and $1000) the file will be truncate/rewritten
  222. when (flags and $10000) there is no check for close (needed for textfiles)
  223. }
  224. var
  225. oflags : cint;
  226. Begin
  227. { close first if opened }
  228. if ((flags and $10000)=0) then
  229. begin
  230. case FileRec(f).mode of
  231. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  232. fmclosed : ;
  233. else
  234. begin
  235. inoutres:=102; {not assigned}
  236. exit;
  237. end;
  238. end;
  239. end;
  240. { reset file Handle }
  241. FileRec(f).Handle:=UnusedHandle;
  242. { We do the conversion of filemodes here, concentrated on 1 place }
  243. case (flags and 3) of
  244. 0 : begin
  245. oflags :=O_RDONLY;
  246. FileRec(f).mode:=fminput;
  247. end;
  248. 1 : begin
  249. oflags :=O_WRONLY;
  250. FileRec(f).mode:=fmoutput;
  251. end;
  252. 2 : begin
  253. oflags :=O_RDWR;
  254. FileRec(f).mode:=fminout;
  255. end;
  256. end;
  257. if (flags and $1000)=$1000 then
  258. oflags:=oflags or (O_CREAT or O_TRUNC)
  259. else
  260. if (flags and $100)=$100 then
  261. oflags:=oflags or (O_APPEND);
  262. { empty name is special }
  263. if p[0]=#0 then
  264. begin
  265. case FileRec(f).mode of
  266. fminput :
  267. FileRec(f).Handle:=StdInputHandle;
  268. fminout, { this is set by rewrite }
  269. fmoutput :
  270. FileRec(f).Handle:=StdOutputHandle;
  271. fmappend :
  272. begin
  273. FileRec(f).Handle:=StdOutputHandle;
  274. FileRec(f).mode:=fmoutput; {fool fmappend}
  275. end;
  276. end;
  277. exit;
  278. end;
  279. { real open call }
  280. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  281. if (FileRec(f).Handle<0) and
  282. (getErrNo=ESysEROFS) and
  283. ((OFlags and O_RDWR)<>0) then
  284. begin
  285. Oflags:=Oflags and not(O_RDWR);
  286. FileRec(f).Handle:=Fpopen(p,oflags,MODE_OPEN);
  287. end;
  288. If Filerec(f).Handle<0 Then
  289. Errno2Inoutres
  290. else
  291. InOutRes:=0;
  292. End;
  293. {*****************************************************************************
  294. Directory Handling
  295. *****************************************************************************}
  296. Procedure MkDir(Const s: String);[IOCheck];
  297. Var
  298. Buffer: Array[0..255] of Char;
  299. Begin
  300. If (s='') or (InOutRes <> 0) then
  301. exit;
  302. Move(s[1], Buffer, Length(s));
  303. Buffer[Length(s)] := #0;
  304. If Fpmkdir(@buffer, MODE_MKDIR)<0 Then
  305. Errno2Inoutres
  306. Else
  307. InOutRes:=0;
  308. End;
  309. Procedure RmDir(Const s: String);[IOCheck];
  310. Var
  311. Buffer: Array[0..255] of Char;
  312. Begin
  313. if (s = '.') then
  314. InOutRes := 16;
  315. If (s='') or (InOutRes <> 0) then
  316. exit;
  317. Move(s[1], Buffer, Length(s));
  318. Buffer[Length(s)] := #0;
  319. If Fprmdir(@buffer)<0 Then
  320. Errno2Inoutres
  321. Else
  322. InOutRes:=0;
  323. End;
  324. Procedure ChDir(Const s: String);[IOCheck];
  325. Var
  326. Buffer: Array[0..255] of Char;
  327. Begin
  328. If (s='') or (InOutRes <> 0) then
  329. exit;
  330. Move(s[1], Buffer, Length(s));
  331. Buffer[Length(s)] := #0;
  332. If Fpchdir(@buffer)<0 Then
  333. Errno2Inoutres
  334. Else
  335. InOutRes:=0;
  336. { file not exists is path not found under tp7 }
  337. if InOutRes=2 then
  338. InOutRes:=3;
  339. End;
  340. procedure getdir(drivenr : byte;var dir : shortstring);
  341. var
  342. {$ifndef usegetcwd}
  343. cwdinfo : stat;
  344. rootinfo : stat;
  345. thedir,dummy : string[255];
  346. dirstream : pdir;
  347. d : pdirent;
  348. name : string[255];
  349. thisdir : stat;
  350. tmp : string[255];
  351. {$else}
  352. tmp : array[0..4095] of char;
  353. {$endif}
  354. begin
  355. {$ifdef usegetcwd}
  356. if Fpgetcwd(@tmp,10240+512)<>NIL then
  357. dir:=pchar(@tmp)
  358. else
  359. begin
  360. dir:='';
  361. writeln(geterrno);
  362. end;
  363. {$else}
  364. dir:='';
  365. thedir:='';
  366. dummy:='';
  367. { get root directory information }
  368. tmp := '/'+#0;
  369. if Fpstat(@tmp[1],rootinfo)<0 then
  370. Exit;
  371. repeat
  372. tmp := dummy+'.'+#0;
  373. { get current directory information }
  374. if Fpstat(@tmp[1],cwdinfo)<0 then
  375. Exit;
  376. tmp:=dummy+'..'+#0;
  377. { open directory stream }
  378. { try to find the current inode number of the cwd }
  379. dirstream:=Fpopendir(@tmp[1]);
  380. if dirstream=nil then
  381. exit;
  382. repeat
  383. name:='';
  384. d:=Fpreaddir(dirstream);
  385. { no more entries to read ... }
  386. if not assigned(d) then
  387. break;
  388. tmp:=dummy+'../'+strpas(d^.d_name) + #0;
  389. if (Fpstat(@tmp[1],thisdir)=0) then
  390. begin
  391. { found the entry for this directory name }
  392. if (cwdinfo.st_dev=thisdir.st_dev) and (cwdinfo.st_ino=thisdir.st_ino) then
  393. begin
  394. { are the filenames of type '.' or '..' ? }
  395. { then do not set the name. }
  396. if (not ((d^.d_name[0]='.') and ((d^.d_name[1]=#0) or
  397. ((d^.d_name[1]='.') and (d^.d_name[2]=#0))))) then
  398. name:='/'+strpas(d^.d_name);
  399. end;
  400. end;
  401. until (name<>'');
  402. If Fpclosedir(dirstream)<0 THen
  403. Exit;
  404. thedir:=name+thedir;
  405. dummy:=dummy+'../';
  406. if ((cwdinfo.st_dev=rootinfo.st_dev) and (cwdinfo.st_ino=rootinfo.st_ino)) then
  407. begin
  408. if thedir='' then
  409. dir:='/'
  410. else
  411. dir:=thedir;
  412. exit;
  413. end;
  414. until false;
  415. {$endif}
  416. end;
  417. {*****************************************************************************
  418. SystemUnit Initialization
  419. *****************************************************************************}
  420. // signal handler is arch dependant due to processorexception to language
  421. // exception translation
  422. {$i sighnd.inc}
  423. var
  424. act: SigActionRec;
  425. Procedure InstallSignals;
  426. begin
  427. { Initialize the sigaction structure }
  428. { all flags and information set to zero }
  429. FillChar(act, sizeof(SigActionRec),0);
  430. { initialize handler }
  431. act.sa_handler := signalhandler(@SignalToRunError);
  432. {$ifdef RTSIGACTION}
  433. act.sa_flags:=SA_SIGINFO
  434. {$ifdef cpux86_64}
  435. or $4000000
  436. {$endif cpux86_64}
  437. ;
  438. {$endif RTSIGACTION}
  439. FpSigAction(SIGFPE,@act,nil);
  440. FpSigAction(SIGSEGV,@act,nil);
  441. FpSigAction(SIGBUS,@act,nil);
  442. FpSigAction(SIGILL,@act,nil);
  443. end;
  444. procedure SetupCmdLine;
  445. var
  446. bufsize,
  447. len,j,
  448. size,i : longint;
  449. found : boolean;
  450. buf : pchar;
  451. procedure AddBuf;
  452. begin
  453. reallocmem(cmdline,size+bufsize);
  454. move(buf^,cmdline[size],bufsize);
  455. inc(size,bufsize);
  456. bufsize:=0;
  457. end;
  458. begin
  459. GetMem(buf,ARG_MAX);
  460. size:=0;
  461. bufsize:=0;
  462. i:=0;
  463. while (i<argc) do
  464. begin
  465. len:=strlen(argv[i]);
  466. if len>ARG_MAX-2 then
  467. len:=ARG_MAX-2;
  468. found:=false;
  469. for j:=1 to len do
  470. if argv[i][j]=' ' then
  471. begin
  472. found:=true;
  473. break;
  474. end;
  475. if bufsize+len>=ARG_MAX-2 then
  476. AddBuf;
  477. if found then
  478. begin
  479. buf[bufsize]:='"';
  480. inc(bufsize);
  481. end;
  482. move(argv[i]^,buf[bufsize],len);
  483. inc(bufsize,len);
  484. if found then
  485. begin
  486. buf[bufsize]:='"';
  487. inc(bufsize);
  488. end;
  489. if i<argc then
  490. buf[bufsize]:=' '
  491. else
  492. buf[bufsize]:=#0;
  493. inc(bufsize);
  494. inc(i);
  495. end;
  496. AddBuf;
  497. FreeMem(buf,ARG_MAX);
  498. end;
  499. {
  500. $Log$
  501. Revision 1.22 2004-11-02 14:49:48 florian
  502. * fixed baseunix.signal for CPU using rt_sigaction
  503. * fixed it for x86_64 too
  504. Revision 1.21 2004/10/25 15:38:59 peter
  505. * compiler defined HEAP and HEAPSIZE removed
  506. Revision 1.20 2004/08/04 19:27:09 florian
  507. * fixed floating point and integer exception handling on sparc/linux
  508. Revision 1.19 2004/05/31 20:25:04 peter
  509. * removed warnings
  510. Revision 1.18 2004/05/16 18:51:20 peter
  511. * use thandle in do_*
  512. Revision 1.17 2004/05/01 15:59:17 florian
  513. * x86_64 exception handling fixed
  514. Revision 1.16 2004/04/27 20:47:00 florian
  515. * tried to fix x86-64 signal handling
  516. Revision 1.15 2004/04/22 21:16:35 peter
  517. * do_write/do_read fix
  518. Revision 1.14 2004/03/27 14:33:45 florian
  519. * tell sigaction to pass siginfo on arm
  520. Revision 1.13 2004/03/10 20:35:33 peter
  521. * call _haltproc instead of exit(). This is required for libc linking
  522. Revision 1.12 2004/01/01 14:19:55 marco
  523. * use_getcwd updates because FPC_USE_LIBC uses that
  524. Revision 1.11 2003/12/30 16:26:10 marco
  525. * some more fixes. Testing on idefix
  526. Revision 1.10 2003/12/21 20:30:49 peter
  527. * don't exit in getdir when fpstat gives a failure
  528. Revision 1.9 2003/12/14 14:28:36 peter
  529. * only check errno if the syscall failed
  530. Revision 1.8 2003/11/01 01:58:11 marco
  531. * more small fixes.
  532. Revision 1.7 2003/10/31 20:36:01 marco
  533. * i386 specific fixes that hopefully fix texception4.
  534. Only the "generic" signal handler was ported to the unix rtl.
  535. Revision 1.6 2003/09/27 12:51:33 peter
  536. * fpISxxx macros renamed to C compliant fpS_ISxxx
  537. Revision 1.5 2003/05/01 08:05:23 florian
  538. * started to make the rtl 64 bit save by introducing SizeInt and SizeUInt (similar to size_t of C)
  539. Revision 1.4 2002/12/24 19:45:40 peter
  540. * Fix do_erase which was wrong with inoutres setting
  541. Revision 1.3 2002/12/23 22:23:43 peter
  542. * fixed Getdir to not set Inoutres
  543. * broken symlinks are now ignored in getdir instead of aborting
  544. the search
  545. Revision 1.2 2002/12/18 20:43:27 peter
  546. * removed stackcheck, the generic stackcheck is used
  547. * fixed return value for error conversion when no error was passed
  548. Revision 1.1 2002/12/18 16:43:26 marco
  549. * new unix rtl, linux part.....
  550. Revision 1.7 2002/11/14 12:18:03 marco
  551. * fixed Fptime call to (NIL)
  552. Revision 1.6 2002/10/27 17:21:29 marco
  553. * Only "difficult" functions + execvp + termios + rewinddir left to do
  554. Revision 1.5 2002/10/26 18:27:52 marco
  555. * First series POSIX calls commits. Including getcwd.
  556. Revision 1.4 2002/09/07 16:01:26 peter
  557. * old logs removed and tabs fixed
  558. Revision 1.3 2002/08/20 12:50:22 marco
  559. * New errno handling. Should be libc compatible.
  560. Revision 1.2 2002/08/10 13:42:36 marco
  561. * Fixes Posix dir copied to devel branch
  562. Revision 1.1.2.18 2002/03/10 11:45:02 carl
  563. * InOutRes := 16 with rmdir()
  564. * InOutRes := 5 more checking
  565. Revision 1.1.2.17 2002/03/03 15:11:51 carl
  566. * erase() bugfix (erasing a directory is done via rmdir() only!)
  567. Revision 1.1.2.16 2002/02/15 18:13:35 carl
  568. * bugfix for paramstr(0)
  569. }