sysposix.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  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. {$IFOPT S+}
  26. {$DEFINE STACKCHECK}
  27. {$ENDIF}
  28. {$S-}
  29. procedure int_stackcheck(stack_size:longint);[public,alias:'FPC_STACKCHECK'];
  30. var
  31. c: cardinal;
  32. begin
  33. c := cardinal(Sptr) - cardinal(stack_size) - STACK_MARGIN;
  34. if (c <= cardinal(StackBottom)) then
  35. HandleError(202);
  36. end;
  37. {$IFDEF STACKCHECK}
  38. {$S+}
  39. {$ENDIF}
  40. {$UNDEF STACKCHECK}
  41. {*****************************************************************************
  42. Misc. System Dependent Functions
  43. *****************************************************************************}
  44. procedure System_exit;
  45. begin
  46. sys_exit(cint(ExitCode));
  47. End;
  48. Function ParamCount: Longint;
  49. Begin
  50. Paramcount:=argc-1
  51. End;
  52. function BackPos(c:char; const s: shortstring): integer;
  53. var
  54. i: integer;
  55. Begin
  56. for i:=length(s) downto 0 do
  57. if s[i] = c then break;
  58. if i=0 then
  59. BackPos := 0
  60. else
  61. BackPos := i;
  62. end;
  63. { variable where full path and filename and executable is stored }
  64. { is setup by the startup of the system unit. }
  65. var
  66. execpathstr : shortstring;
  67. function paramstr(l: longint) : string;
  68. var
  69. s: string;
  70. s1: string;
  71. begin
  72. { stricly conforming POSIX applications }
  73. { have the executing filename as argv[0] }
  74. if l=0 then
  75. begin
  76. paramstr := execpathstr;
  77. end
  78. else
  79. paramstr:=strpas(argv[l]);
  80. end;
  81. Procedure Randomize;
  82. var
  83. t: time_t;
  84. Begin
  85. randseed:=longint(sys_time(t));
  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. Procedure Errno2Inoutres;
  113. {
  114. Convert ErrNo error to the correct Inoutres value
  115. }
  116. begin
  117. if ErrNo=0 then { Else it will go through all the cases }
  118. exit;
  119. case ErrNo 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(Errno);
  141. end;
  142. end;
  143. end;
  144. Procedure Do_Close(Handle:Longint);
  145. Begin
  146. sys_close(cint(Handle));
  147. End;
  148. Procedure Do_Erase(p:pchar);
  149. var
  150. fileinfo : stat;
  151. Begin
  152. { verify if the filename is actually a directory }
  153. { if so return error and do nothing, as defined }
  154. { by POSIX }
  155. if sys_stat(p,fileinfo)<0 then
  156. begin
  157. Errno2Inoutres;
  158. exit;
  159. end;
  160. if S_ISDIR(fileinfo.st_mode) then
  161. begin
  162. InOutRes := 2;
  163. exit;
  164. end;
  165. sys_unlink(p);
  166. Errno2Inoutres;
  167. End;
  168. { truncate at a given position }
  169. procedure do_truncate (handle,fpos:longint);
  170. begin
  171. { should be simulated in cases where it is not }
  172. { available. }
  173. sys_ftruncate(handle,fpos);
  174. Errno2Inoutres;
  175. end;
  176. Procedure Do_Rename(p1,p2:pchar);
  177. Begin
  178. sys_rename(p1,p2);
  179. Errno2Inoutres;
  180. End;
  181. Function Do_Write(Handle,Addr,Len:Longint):longint;
  182. Begin
  183. repeat
  184. Do_Write:=sys_write(Handle,pchar(addr),len);
  185. until ErrNo<>Sys_EINTR;
  186. Errno2Inoutres;
  187. if Do_Write<0 then
  188. Do_Write:=0;
  189. End;
  190. Function Do_Read(Handle,Addr,Len:Longint):Longint;
  191. Begin
  192. repeat
  193. Do_Read:=sys_read(Handle,pchar(addr),len);
  194. until ErrNo<>Sys_EINTR;
  195. Errno2Inoutres;
  196. if Do_Read<0 then
  197. Do_Read:=0;
  198. End;
  199. function Do_FilePos(Handle: Longint):longint;
  200. Begin
  201. do_FilePos:=sys_lseek(Handle, 0, SEEK_CUR);
  202. Errno2Inoutres;
  203. End;
  204. Procedure Do_Seek(Handle,Pos:Longint);
  205. Begin
  206. sys_lseek(Handle, pos, SEEK_SET);
  207. Errno2Inoutres;
  208. End;
  209. Function Do_SeekEnd(Handle:Longint): Longint;
  210. begin
  211. Do_SeekEnd:=sys_lseek(Handle,0,SEEK_END);
  212. errno2inoutres;
  213. end;
  214. Function Do_FileSize(Handle:Longint): Longint;
  215. var
  216. Info : Stat;
  217. Begin
  218. if sys_fstat(handle,info)=0 then
  219. Do_FileSize:=Info.st_size
  220. else
  221. Do_FileSize:=0;
  222. Errno2InOutRes;
  223. End;
  224. Procedure Do_Open(var f;p:pchar;flags:longint);
  225. {
  226. FileRec and textrec have both Handle and mode as the first items so
  227. they could use the same routine for opening/creating.
  228. when (flags and $100) the file will be append
  229. when (flags and $1000) the file will be truncate/rewritten
  230. when (flags and $10000) there is no check for close (needed for textfiles)
  231. }
  232. var
  233. oflags : cint;
  234. Begin
  235. { close first if opened }
  236. if ((flags and $10000)=0) then
  237. begin
  238. case FileRec(f).mode of
  239. fminput,fmoutput,fminout : Do_Close(FileRec(f).Handle);
  240. fmclosed : ;
  241. else
  242. begin
  243. inoutres:=102; {not assigned}
  244. exit;
  245. end;
  246. end;
  247. end;
  248. { reset file Handle }
  249. FileRec(f).Handle:=UnusedHandle;
  250. { We do the conversion of filemodes here, concentrated on 1 place }
  251. case (flags and 3) of
  252. 0 : begin
  253. oflags :=O_RDONLY;
  254. FileRec(f).mode:=fminput;
  255. end;
  256. 1 : begin
  257. oflags :=O_WRONLY;
  258. FileRec(f).mode:=fmoutput;
  259. end;
  260. 2 : begin
  261. oflags :=O_RDWR;
  262. FileRec(f).mode:=fminout;
  263. end;
  264. end;
  265. if (flags and $1000)=$1000 then
  266. oflags:=oflags or (O_CREAT or O_TRUNC)
  267. else
  268. if (flags and $100)=$100 then
  269. oflags:=oflags or (O_APPEND);
  270. { empty name is special }
  271. if p[0]=#0 then
  272. begin
  273. case FileRec(f).mode of
  274. fminput :
  275. FileRec(f).Handle:=StdInputHandle;
  276. fminout, { this is set by rewrite }
  277. fmoutput :
  278. FileRec(f).Handle:=StdOutputHandle;
  279. fmappend :
  280. begin
  281. FileRec(f).Handle:=StdOutputHandle;
  282. FileRec(f).mode:=fmoutput; {fool fmappend}
  283. end;
  284. end;
  285. exit;
  286. end;
  287. { real open call }
  288. FileRec(f).Handle:=sys_open(p,oflags,MODE_OPEN);
  289. if (ErrNo=Sys_EROFS) and ((OFlags and O_RDWR)<>0) then
  290. begin
  291. Oflags:=Oflags and not(O_RDWR);
  292. FileRec(f).Handle:=sys_open(p,oflags,MODE_OPEN);
  293. end;
  294. Errno2Inoutres;
  295. End;
  296. {*****************************************************************************
  297. Directory Handling
  298. *****************************************************************************}
  299. Procedure MkDir(Const s: String);[IOCheck];
  300. Var
  301. Buffer: Array[0..255] of Char;
  302. Begin
  303. If (s='') or (InOutRes <> 0) then
  304. exit;
  305. Move(s[1], Buffer, Length(s));
  306. Buffer[Length(s)] := #0;
  307. sys_mkdir(@buffer, MODE_MKDIR);
  308. Errno2Inoutres;
  309. End;
  310. Procedure RmDir(Const s: String);[IOCheck];
  311. Var
  312. Buffer: Array[0..255] of Char;
  313. Begin
  314. if (s = '.') then
  315. InOutRes := 16;
  316. If (s='') or (InOutRes <> 0) then
  317. exit;
  318. Move(s[1], Buffer, Length(s));
  319. Buffer[Length(s)] := #0;
  320. sys_rmdir(@buffer);
  321. Errno2Inoutres;
  322. End;
  323. Procedure ChDir(Const s: String);[IOCheck];
  324. Var
  325. Buffer: Array[0..255] of Char;
  326. Begin
  327. If (s='') or (InOutRes <> 0) then
  328. exit;
  329. Move(s[1], Buffer, Length(s));
  330. Buffer[Length(s)] := #0;
  331. sys_chdir(@buffer);
  332. Errno2Inoutres;
  333. { file not exists is path not found under tp7 }
  334. if InOutRes=2 then
  335. InOutRes:=3;
  336. End;
  337. procedure getdir(drivenr : byte;var dir : shortstring);
  338. var
  339. cwdinfo : stat;
  340. rootinfo : stat;
  341. thedir,dummy : string[255];
  342. dirstream : pdir;
  343. d : pdirent;
  344. name : string[255];
  345. tmp : string[255];
  346. thisdir : stat;
  347. begin
  348. dir:='';
  349. thedir:='';
  350. dummy:='';
  351. { get root directory information }
  352. tmp := '/'+#0;
  353. if sys_stat(@tmp[1],rootinfo)<0 then
  354. exit;
  355. repeat
  356. tmp := dummy+'.'+#0;
  357. { get current directory information }
  358. if sys_stat(@tmp[1],cwdinfo)<0 then
  359. exit;
  360. tmp:=dummy+'..'+#0;
  361. { open directory stream }
  362. { try to find the current inode number of the cwd }
  363. dirstream:=sys_opendir(@tmp[1]);
  364. if dirstream=nil then
  365. exit;
  366. repeat
  367. name:='';
  368. d:=sys_readdir(dirstream);
  369. { no more entries to read ... }
  370. if not assigned(d) then
  371. begin
  372. break;
  373. end;
  374. tmp:=dummy+'../'+strpas(d^.d_name) + #0;
  375. if sys_stat(@tmp[1],thisdir)<0 then
  376. begin
  377. exit;
  378. end;
  379. { found the entry for this directory name }
  380. if (cwdinfo.st_dev=thisdir.st_dev) and (cwdinfo.st_ino=thisdir.st_ino) then
  381. begin
  382. { are the filenames of type '.' or '..' ? }
  383. { then do not set the name. }
  384. if (not ((d^.d_name[0]='.') and ((d^.d_name[1]=#0) or
  385. ((d^.d_name[1]='.') and (d^.d_name[2]=#0))))) then
  386. begin
  387. name:='/'+strpas(d^.d_name);
  388. end;
  389. end
  390. until (name<>'');
  391. sys_closedir(dirstream);
  392. thedir:=name+thedir;
  393. dummy:=dummy+'../';
  394. if ((cwdinfo.st_dev=rootinfo.st_dev) and (cwdinfo.st_ino=rootinfo.st_ino)) then
  395. begin
  396. if thedir='' then
  397. dir:='/'
  398. else
  399. dir:=thedir;
  400. exit;
  401. end;
  402. until false;
  403. end;
  404. {*****************************************************************************
  405. SystemUnit Initialization
  406. *****************************************************************************}
  407. procedure SignalToRunerror(signo: cint); cdecl;
  408. var
  409. res : word;
  410. begin
  411. res:=0;
  412. if signo = SIGFPE then
  413. begin
  414. res := 200;
  415. end
  416. else
  417. if (signo = SIGILL) or (signo = SIGBUS) or (signo = SIGSEGV) then
  418. begin
  419. res := 216;
  420. end;
  421. { give runtime error at the position where the signal was raised }
  422. if res<>0 then
  423. begin
  424. HandleError(res);
  425. end;
  426. end;
  427. var
  428. act: SigActionRec;
  429. Procedure InstallSignals;
  430. var
  431. oldact: SigActionRec;
  432. begin
  433. { Initialize the sigaction structure }
  434. { all flags and information set to zero }
  435. FillChar(act, sizeof(SigActionRec),0);
  436. { initialize handler }
  437. act.sa_handler := @SignalToRunError;
  438. sys_SigAction(SIGFPE,act,oldact);
  439. sys_SigAction(SIGSEGV,act,oldact);
  440. sys_SigAction(SIGBUS,act,oldact);
  441. sys_SigAction(SIGILL,act,oldact);
  442. end;
  443. procedure SetupCmdLine;
  444. var
  445. bufsize,
  446. len,j,
  447. size,i : longint;
  448. found : boolean;
  449. buf : pchar;
  450. procedure AddBuf;
  451. begin
  452. reallocmem(cmdline,size+bufsize);
  453. move(buf^,cmdline[size],bufsize);
  454. inc(size,bufsize);
  455. bufsize:=0;
  456. end;
  457. begin
  458. GetMem(buf,ARG_MAX);
  459. size:=0;
  460. bufsize:=0;
  461. i:=0;
  462. while (i<argc) do
  463. begin
  464. len:=strlen(argv[i]);
  465. if len>ARG_MAX-2 then
  466. len:=ARG_MAX-2;
  467. found:=false;
  468. for j:=1 to len do
  469. if argv[i][j]=' ' then
  470. begin
  471. found:=true;
  472. break;
  473. end;
  474. if bufsize+len>=ARG_MAX-2 then
  475. AddBuf;
  476. if found then
  477. begin
  478. buf[bufsize]:='"';
  479. inc(bufsize);
  480. end;
  481. move(argv[i]^,buf[bufsize],len);
  482. inc(bufsize,len);
  483. if found then
  484. begin
  485. buf[bufsize]:='"';
  486. inc(bufsize);
  487. end;
  488. if i<argc then
  489. buf[bufsize]:=' '
  490. else
  491. buf[bufsize]:=#0;
  492. inc(bufsize);
  493. inc(i);
  494. end;
  495. AddBuf;
  496. FreeMem(buf,ARG_MAX);
  497. end;
  498. (*
  499. Begin
  500. { Set up signals handlers }
  501. InstallSignals;
  502. { Setup heap }
  503. InitHeap;
  504. InitExceptions;
  505. { Arguments }
  506. SetupCmdLine;
  507. { Setup stdin, stdout and stderr }
  508. OpenStdIO(Input,fmInput,StdInputHandle);
  509. OpenStdIO(Output,fmOutput,StdOutputHandle);
  510. OpenStdIO(StdOut,fmOutput,StdOutputHandle);
  511. OpenStdIO(StdErr,fmOutput,StdErrorHandle);
  512. { Reset IO Error }
  513. InOutRes:=0;
  514. End.
  515. *)
  516. {
  517. $Log$
  518. Revision 1.2 2002-08-10 13:42:36 marco
  519. * Fixes Posix dir copied to devel branch
  520. Revision 1.1.2.18 2002/03/10 11:45:02 carl
  521. * InOutRes := 16 with rmdir()
  522. * InOutRes := 5 more checking
  523. Revision 1.1.2.17 2002/03/03 15:11:51 carl
  524. * erase() bugfix (erasing a directory is done via rmdir() only!)
  525. Revision 1.1.2.16 2002/02/15 18:13:35 carl
  526. * bugfix for paramstr(0)
  527. Revision 1.1.2.15 2001/12/03 03:15:15 carl
  528. * update readdir prototype
  529. Revision 1.1.2.14 2001/09/27 02:24:43 carl
  530. * correct problem with getting paramstr(0) when in root
  531. Revision 1.1.2.13 2001/08/15 01:05:22 carl
  532. + add do_truncate()
  533. Revision 1.1.2.12 2001/08/13 09:38:12 carl
  534. * changed prototype of sys_readdir
  535. * bugfix of problems of changing signs with errno!
  536. Revision 1.1.2.11 2001/08/13 05:55:43 carl
  537. - removed some debug code
  538. Revision 1.1.2.10 2001/08/08 02:01:03 carl
  539. * bugfix of getdir() with root
  540. Revision 1.1.2.9 2001/08/03 02:00:26 carl
  541. + hack :(... for heap management.
  542. + correct I/O bug (to test) should be also updated in linux
  543. Revision 1.1.2.8 2001/07/21 19:20:52 carl
  544. + getdir() implemented
  545. + MAX_ARGS define now used
  546. Revision 1.1.2.7 2001/07/14 04:18:39 carl
  547. + started debugging getdir()
  548. Revision 1.1.2.6 2001/07/08 04:46:43 carl
  549. * correct parameter calls to sigaction
  550. Revision 1.1.2.5 2001/07/08 00:38:04 carl
  551. + updates
  552. Revision 1.1.2.3 2001/07/06 11:59:58 carl
  553. * renamed some defines
  554. * correct includes
  555. Revision 1.1.2.2 2001/07/06 11:42:28 carl
  556. * modified for more compliance
  557. Revision 1.1.2.1 2001/07/06 11:22:18 carl
  558. + add files for POSIX
  559. }