sysposix.inc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. Stack check code
  24. *****************************************************************************}
  25. {
  26. {$IFOPT S+}
  27. {$DEFINE STACKCHECK}
  28. {$ENDIF}
  29. {$S-}
  30. procedure int_stackcheck(stack_size:longint);[public,alias:'FPC_STACKCHECK'];
  31. var
  32. c: cardinal;
  33. begin
  34. c := cardinal(Sptr) - cardinal(stack_size) - STACK_MARGIN;
  35. if (c <= cardinal(StackBottom)) then
  36. HandleError(202);
  37. end;
  38. {$IFDEF STACKCHECK}
  39. {$S+}
  40. {$ENDIF}
  41. {$UNDEF STACKCHECK}
  42. }
  43. {*****************************************************************************
  44. Misc. System Dependent Functions
  45. *****************************************************************************}
  46. procedure System_exit;
  47. begin
  48. sys_exit(cint(ExitCode));
  49. End;
  50. Function ParamCount: Longint;
  51. Begin
  52. Paramcount:=argc-1
  53. End;
  54. function BackPos(c:char; const s: shortstring): integer;
  55. var
  56. i: integer;
  57. Begin
  58. for i:=length(s) downto 0 do
  59. if s[i] = c then break;
  60. if i=0 then
  61. BackPos := 0
  62. else
  63. BackPos := i;
  64. end;
  65. { variable where full path and filename and executable is stored }
  66. { is setup by the startup of the system unit. }
  67. var
  68. execpathstr : shortstring;
  69. function paramstr(l: longint) : string;
  70. var
  71. s: string;
  72. s1: string;
  73. begin
  74. { stricly conforming POSIX applications }
  75. { have the executing filename as argv[0] }
  76. if l=0 then
  77. begin
  78. paramstr := execpathstr;
  79. end
  80. else
  81. paramstr:=strpas(argv[l]);
  82. end;
  83. Procedure Randomize;
  84. Begin
  85. randseed:=longint(sys_time(nil));
  86. End;
  87. {*****************************************************************************
  88. Heap Management
  89. *****************************************************************************}
  90. var
  91. _HEAP : longint;external name 'HEAP';
  92. _HEAPSIZE : longint;external name 'HEAPSIZE';
  93. {$ifndef SYSTEM_HAS_GETHEAPSTART}
  94. function getheapstart:pointer;
  95. begin
  96. getheapstart := @_HEAP;
  97. end;
  98. {$endif}
  99. {$ifndef SYSTEM_HAS_GETHEAPSIZE}
  100. function getheapsize:longint;
  101. begin
  102. getheapsize := _HEAPSIZE;
  103. end;
  104. {$endif}
  105. {*****************************************************************************
  106. Low Level File Routines
  107. *****************************************************************************}
  108. {
  109. The lowlevel file functions should take care of setting the InOutRes to the
  110. correct value if an error has occured, else leave it untouched
  111. }
  112. Function PosixToRunError (PosixErrno : longint) : longint;
  113. {
  114. Convert ErrNo error to the correct Inoutres value
  115. }
  116. begin
  117. if PosixErrNo=0 then { Else it will go through all the cases }
  118. exit;
  119. case PosixErrNo of
  120. Sys_ENFILE,
  121. Sys_EMFILE : Inoutres:=4;
  122. Sys_ENOENT : Inoutres:=2;
  123. Sys_EBADF : Inoutres:=6;
  124. Sys_ENOMEM,
  125. Sys_EFAULT : Inoutres:=217;
  126. Sys_EINVAL : Inoutres:=218;
  127. Sys_EPIPE,
  128. Sys_EINTR,
  129. Sys_EIO,
  130. Sys_EAGAIN,
  131. Sys_ENOSPC : Inoutres:=101;
  132. Sys_ENAMETOOLONG : Inoutres := 3;
  133. Sys_EROFS,
  134. Sys_EEXIST,
  135. Sys_ENOTEMPTY,
  136. Sys_EACCES : Inoutres:=5;
  137. Sys_EISDIR : InOutRes:=5;
  138. else
  139. begin
  140. InOutRes := Integer(PosixErrno);
  141. end;
  142. end;
  143. end;
  144. Function Errno2InoutRes : longint;
  145. begin
  146. Errno2InoutRes:=PosixToRunError(Errno);
  147. InoutRes:=Errno2InoutRes;
  148. end;
  149. Procedure Do_Close(Handle:Longint);
  150. Begin
  151. sys_close(cint(Handle));
  152. End;
  153. Procedure Do_Erase(p:pchar);
  154. var
  155. fileinfo : stat;
  156. Begin
  157. { verify if the filename is actually a directory }
  158. { if so return error and do nothing, as defined }
  159. { by POSIX }
  160. if sys_stat(p,fileinfo)<0 then
  161. begin
  162. Errno2Inoutres;
  163. exit;
  164. end;
  165. if S_ISDIR(fileinfo.st_mode) then
  166. begin
  167. InOutRes := 2;
  168. exit;
  169. end;
  170. sys_unlink(p);
  171. Errno2Inoutres;
  172. End;
  173. { truncate at a given position }
  174. procedure do_truncate (handle,fpos:longint);
  175. begin
  176. { should be simulated in cases where it is not }
  177. { available. }
  178. If sys_ftruncate(handle,fpos)<0 Then
  179. Errno2Inoutres
  180. Else
  181. InOutRes:=0;
  182. end;
  183. Procedure Do_Rename(p1,p2:pchar);
  184. Begin
  185. If sys_rename(p1,p2)<0 Then
  186. Errno2Inoutres
  187. Else
  188. InOutRes:=0;
  189. End;
  190. Function Do_Write(Handle,Addr,Len:Longint):longint;
  191. Begin
  192. repeat
  193. Do_Write:=sys_write(Handle,pchar(addr),len);
  194. until ErrNo<>Sys_EINTR;
  195. If Do_Write<0 Then
  196. Begin
  197. Errno2InOutRes;
  198. Do_Write:=0;
  199. End
  200. else
  201. InOutRes:=0;
  202. End;
  203. Function Do_Read(Handle,Addr,Len:Longint):Longint;
  204. Begin
  205. repeat
  206. Do_Read:=sys_read(Handle,pchar(addr),len);
  207. until ErrNo<>Sys_EINTR;
  208. If Do_Read<0 Then
  209. Begin
  210. Errno2InOutRes;
  211. Do_Read:=0;
  212. End
  213. else
  214. InOutRes:=0;
  215. End;
  216. function Do_FilePos(Handle: Longint):longint;
  217. Begin
  218. do_FilePos:=sys_lseek(Handle, 0, SEEK_CUR);
  219. If Do_FilePos<0 Then
  220. Errno2InOutRes
  221. else
  222. InOutRes:=0;
  223. End;
  224. Procedure Do_Seek(Handle,Pos:Longint);
  225. Begin
  226. If sys_lseek(Handle, pos, SEEK_SET)<0 Then
  227. Errno2Inoutres
  228. Else
  229. InOutRes:=0;
  230. End;
  231. Function Do_SeekEnd(Handle:Longint): Longint;
  232. begin
  233. Do_SeekEnd:=sys_lseek(Handle,0,SEEK_END);
  234. If Do_SeekEnd<0 Then
  235. Errno2Inoutres
  236. Else
  237. InOutRes:=0;
  238. end;
  239. Function Do_FileSize(Handle:Longint): Longint;
  240. var
  241. Info : Stat;
  242. Ret : Longint;
  243. Begin
  244. Ret:=sys_fstat(handle,info);
  245. If Ret=0 Then
  246. Do_FileSize:=Info.st_size
  247. else
  248. Do_FileSize:=0;
  249. If Ret<0 Then
  250. Errno2InOutRes
  251. Else
  252. InOutRes:=0;
  253. End;
  254. Procedure Do_Open(var f;p:pchar;flags:longint);
  255. {
  256. FileRec and textrec have both Handle and mode as the first items so
  257. they could use the same routine for opening/creating.
  258. when (flags and $100) the file will be append
  259. when (flags and $1000) the file will be truncate/rewritten
  260. when (flags and $10000) there is no check for close (needed for textfiles)
  261. }
  262. var
  263. oflags : cint;
  264. Begin
  265. { close first if opened }
  266. if ((flags and $10000)=0) then
  267. begin
  268. case FileRec(f).mode of
  269. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  270. fmclosed : ;
  271. else
  272. begin
  273. inoutres:=102; {not assigned}
  274. exit;
  275. end;
  276. end;
  277. end;
  278. { reset file Handle }
  279. FileRec(f).Handle:=UnusedHandle;
  280. { We do the conversion of filemodes here, concentrated on 1 place }
  281. case (flags and 3) of
  282. 0 : begin
  283. oflags :=O_RDONLY;
  284. FileRec(f).mode:=fminput;
  285. end;
  286. 1 : begin
  287. oflags :=O_WRONLY;
  288. FileRec(f).mode:=fmoutput;
  289. end;
  290. 2 : begin
  291. oflags :=O_RDWR;
  292. FileRec(f).mode:=fminout;
  293. end;
  294. end;
  295. if (flags and $1000)=$1000 then
  296. oflags:=oflags or (O_CREAT or O_TRUNC)
  297. else
  298. if (flags and $100)=$100 then
  299. oflags:=oflags or (O_APPEND);
  300. { empty name is special }
  301. if p[0]=#0 then
  302. begin
  303. case FileRec(f).mode of
  304. fminput :
  305. FileRec(f).Handle:=StdInputHandle;
  306. fminout, { this is set by rewrite }
  307. fmoutput :
  308. FileRec(f).Handle:=StdOutputHandle;
  309. fmappend :
  310. begin
  311. FileRec(f).Handle:=StdOutputHandle;
  312. FileRec(f).mode:=fmoutput; {fool fmappend}
  313. end;
  314. end;
  315. exit;
  316. end;
  317. { real open call }
  318. FileRec(f).Handle:=sys_open(p,oflags,MODE_OPEN);
  319. if (ErrNo=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  320. begin
  321. Oflags:=Oflags and not(O_RDWR);
  322. FileRec(f).Handle:=sys_open(p,oflags,MODE_OPEN);
  323. end;
  324. If Filerec(f).Handle<0 Then
  325. Errno2Inoutres
  326. else
  327. InOutRes:=0;
  328. End;
  329. {*****************************************************************************
  330. Directory Handling
  331. *****************************************************************************}
  332. Procedure MkDir(Const s: String);[IOCheck];
  333. Var
  334. Buffer: Array[0..255] of Char;
  335. Begin
  336. If (s='') or (InOutRes <> 0) then
  337. exit;
  338. Move(s[1], Buffer, Length(s));
  339. Buffer[Length(s)] := #0;
  340. If sys_mkdir(@buffer, MODE_MKDIR)<0 Then
  341. Errno2Inoutres
  342. Else
  343. InOutRes:=0;
  344. End;
  345. Procedure RmDir(Const s: String);[IOCheck];
  346. Var
  347. Buffer: Array[0..255] of Char;
  348. Begin
  349. if (s = '.') then
  350. InOutRes := 16;
  351. If (s='') or (InOutRes <> 0) then
  352. exit;
  353. Move(s[1], Buffer, Length(s));
  354. Buffer[Length(s)] := #0;
  355. If sys_rmdir(@buffer)<0 Then
  356. Errno2Inoutres
  357. Else
  358. InOutRes:=0;
  359. End;
  360. Procedure ChDir(Const s: String);[IOCheck];
  361. Var
  362. Buffer: Array[0..255] of Char;
  363. Begin
  364. If (s='') or (InOutRes <> 0) then
  365. exit;
  366. Move(s[1], Buffer, Length(s));
  367. Buffer[Length(s)] := #0;
  368. If sys_chdir(@buffer)<0 Then
  369. Errno2Inoutres
  370. Else
  371. InOutRes:=0;
  372. { file not exists is path not found under tp7 }
  373. if InOutRes=2 then
  374. InOutRes:=3;
  375. End;
  376. { // $define usegetcwd}
  377. procedure getdir(drivenr : byte;var dir : shortstring);
  378. var
  379. {$ifndef usegetcwd}
  380. cwdinfo : stat;
  381. rootinfo : stat;
  382. thedir,dummy : string[255];
  383. dirstream : pdir;
  384. d : pdirent;
  385. name : string[255];
  386. thisdir : stat;
  387. {$endif}
  388. tmp : string[255];
  389. begin
  390. {$ifdef usegetcwd}
  391. sys_getcwd(@tmp[1],255);
  392. dir:=tmp;
  393. {$else}
  394. dir:='';
  395. thedir:='';
  396. dummy:='';
  397. { get root directory information }
  398. tmp := '/'+#0;
  399. if sys_stat(@tmp[1],rootinfo)<0 then
  400. Begin
  401. Errno2Inoutres;
  402. Exit
  403. End
  404. Else
  405. InOutRes:=0;
  406. repeat
  407. tmp := dummy+'.'+#0;
  408. { get current directory information }
  409. if sys_stat(@tmp[1],cwdinfo)<0 then
  410. Begin
  411. Errno2Inoutres;
  412. Exit
  413. End
  414. Else
  415. InOutRes:=0;
  416. tmp:=dummy+'..'+#0;
  417. { open directory stream }
  418. { try to find the current inode number of the cwd }
  419. dirstream:=sys_opendir(@tmp[1]);
  420. if dirstream=nil then
  421. exit;
  422. repeat
  423. name:='';
  424. d:=sys_readdir(dirstream);
  425. { no more entries to read ... }
  426. if not assigned(d) then
  427. begin
  428. break;
  429. end;
  430. tmp:=dummy+'../'+strpas(d^.d_name) + #0;
  431. if sys_stat(@tmp[1],thisdir)<0 then
  432. begin
  433. Errno2Inoutres;
  434. Exit
  435. End
  436. Else
  437. InOutRes:=0;
  438. { found the entry for this directory name }
  439. if (cwdinfo.st_dev=thisdir.st_dev) and (cwdinfo.st_ino=thisdir.st_ino) then
  440. begin
  441. { are the filenames of type '.' or '..' ? }
  442. { then do not set the name. }
  443. if (not ((d^.d_name[0]='.') and ((d^.d_name[1]=#0) or
  444. ((d^.d_name[1]='.') and (d^.d_name[2]=#0))))) then
  445. begin
  446. name:='/'+strpas(d^.d_name);
  447. end;
  448. end
  449. until (name<>'');
  450. If sys_closedir(dirstream)<0 THen
  451. Begin
  452. Errno2Inoutres;
  453. Exit
  454. End
  455. Else
  456. InOutRes:=0;
  457. thedir:=name+thedir;
  458. dummy:=dummy+'../';
  459. if ((cwdinfo.st_dev=rootinfo.st_dev) and (cwdinfo.st_ino=rootinfo.st_ino)) then
  460. begin
  461. if thedir='' then
  462. dir:='/'
  463. else
  464. dir:=thedir;
  465. exit;
  466. end;
  467. until false;
  468. {$endif}
  469. end;
  470. {*****************************************************************************
  471. SystemUnit Initialization
  472. *****************************************************************************}
  473. procedure SignalToRunerror(signo: cint); cdecl;
  474. var
  475. res : word;
  476. begin
  477. res:=0;
  478. if signo = SIGFPE then
  479. begin
  480. res := 200;
  481. end
  482. else
  483. if (signo = SIGILL) or (signo = SIGBUS) or (signo = SIGSEGV) then
  484. begin
  485. res := 216;
  486. end;
  487. { give runtime error at the position where the signal was raised }
  488. if res<>0 then
  489. begin
  490. HandleError(res);
  491. end;
  492. end;
  493. var
  494. act: SigActionRec;
  495. Procedure InstallSignals;
  496. var
  497. oldact: SigActionRec;
  498. begin
  499. { Initialize the sigaction structure }
  500. { all flags and information set to zero }
  501. FillChar(act, sizeof(SigActionRec),0);
  502. { initialize handler }
  503. act.sa_handler := @SignalToRunError;
  504. sys_SigAction(SIGFPE,act,oldact);
  505. sys_SigAction(SIGSEGV,act,oldact);
  506. sys_SigAction(SIGBUS,act,oldact);
  507. sys_SigAction(SIGILL,act,oldact);
  508. end;
  509. procedure SetupCmdLine;
  510. var
  511. bufsize,
  512. len,j,
  513. size,i : longint;
  514. found : boolean;
  515. buf : pchar;
  516. procedure AddBuf;
  517. begin
  518. reallocmem(cmdline,size+bufsize);
  519. move(buf^,cmdline[size],bufsize);
  520. inc(size,bufsize);
  521. bufsize:=0;
  522. end;
  523. begin
  524. GetMem(buf,ARG_MAX);
  525. size:=0;
  526. bufsize:=0;
  527. i:=0;
  528. while (i<argc) do
  529. begin
  530. len:=strlen(argv[i]);
  531. if len>ARG_MAX-2 then
  532. len:=ARG_MAX-2;
  533. found:=false;
  534. for j:=1 to len do
  535. if argv[i][j]=' ' then
  536. begin
  537. found:=true;
  538. break;
  539. end;
  540. if bufsize+len>=ARG_MAX-2 then
  541. AddBuf;
  542. if found then
  543. begin
  544. buf[bufsize]:='"';
  545. inc(bufsize);
  546. end;
  547. move(argv[i]^,buf[bufsize],len);
  548. inc(bufsize,len);
  549. if found then
  550. begin
  551. buf[bufsize]:='"';
  552. inc(bufsize);
  553. end;
  554. if i<argc then
  555. buf[bufsize]:=' '
  556. else
  557. buf[bufsize]:=#0;
  558. inc(bufsize);
  559. inc(i);
  560. end;
  561. AddBuf;
  562. FreeMem(buf,ARG_MAX);
  563. end;
  564. (*
  565. Begin
  566. { Set up signals handlers }
  567. InstallSignals;
  568. { Setup heap }
  569. InitHeap;
  570. InitExceptions;
  571. { Arguments }
  572. SetupCmdLine;
  573. { Setup stdin, stdout and stderr }
  574. OpenStdIO(Input,fmInput,StdInputHandle);
  575. OpenStdIO(Output,fmOutput,StdOutputHandle);
  576. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  577. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  578. { Reset IO Error }
  579. InOutRes:=0;
  580. End.
  581. *)
  582. {
  583. $Log$
  584. Revision 1.7 2002-11-14 12:18:03 marco
  585. * fixed sys_time call to (NIL)
  586. Revision 1.6 2002/10/27 17:21:29 marco
  587. * Only "difficult" functions + execvp + termios + rewinddir left to do
  588. Revision 1.5 2002/10/26 18:27:52 marco
  589. * First series POSIX calls commits. Including getcwd.
  590. Revision 1.4 2002/09/07 16:01:26 peter
  591. * old logs removed and tabs fixed
  592. Revision 1.3 2002/08/20 12:50:22 marco
  593. * New errno handling. Should be libc compatible.
  594. Revision 1.2 2002/08/10 13:42:36 marco
  595. * Fixes Posix dir copied to devel branch
  596. Revision 1.1.2.18 2002/03/10 11:45:02 carl
  597. * InOutRes := 16 with rmdir()
  598. * InOutRes := 5 more checking
  599. Revision 1.1.2.17 2002/03/03 15:11:51 carl
  600. * erase() bugfix (erasing a directory is done via rmdir() only!)
  601. Revision 1.1.2.16 2002/02/15 18:13:35 carl
  602. * bugfix for paramstr(0)
  603. }