dcunix.pas 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. {
  2. Double commander
  3. -------------------------------------------------------------------------
  4. This unit contains Unix specific functions
  5. Copyright (C) 2015-2024 Alexander Koblov ([email protected])
  6. This library is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Lesser General Public
  8. License as published by the Free Software Foundation; either
  9. version 2.1 of the License, or (at your option) any later version.
  10. This library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public
  15. License along with this library; if not, write to the Free Software
  16. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. Notes:
  18. 1. TDarwinStat64 is the workaround for the bug of BaseUnix.Stat in FPC.
  19. on MacOS with x86_64, Stat64 should be used instead of Stat.
  20. and lstat64() should be called instead of lstat().
  21. }
  22. unit DCUnix;
  23. {$mode objfpc}{$H+}
  24. {$modeswitch advancedrecords}
  25. {$packrecords c}
  26. interface
  27. uses
  28. InitC, BaseUnix, UnixType, DCBasicTypes, SysUtils;
  29. const
  30. {$IF DEFINED(LINUX)}
  31. FD_CLOEXEC = 1;
  32. O_CLOEXEC = &02000000;
  33. O_PATH = &010000000;
  34. _SC_NPROCESSORS_CONF = 83;
  35. _SC_NPROCESSORS_ONLN = 84;
  36. {$ELSEIF DEFINED(FREEBSD)}
  37. O_CLOEXEC = &04000000;
  38. _SC_NPROCESSORS_CONF = 57;
  39. _SC_NPROCESSORS_ONLN = 58;
  40. CLOSE_RANGE_CLOEXEC = (1 << 2);
  41. {$ELSEIF DEFINED(NETBSD)}
  42. O_CLOEXEC = $00400000;
  43. {$ELSEIF DEFINED(HAIKU)}
  44. FD_CLOEXEC = 1;
  45. O_CLOEXEC = $00000040;
  46. {$ELSEIF DEFINED(DARWIN)}
  47. F_NOCACHE = 48;
  48. O_CLOEXEC = $1000000;
  49. _SC_NPROCESSORS_CONF = 57;
  50. _SC_NPROCESSORS_ONLN = 58;
  51. {$ELSE}
  52. O_CLOEXEC = 0;
  53. {$ENDIF}
  54. {$IF DEFINED(LINUX)}
  55. {$I dclinuxmagic.inc}
  56. {$ENDIF}
  57. type
  58. {$IF DEFINED(LINUX)}
  59. TUnixTime =
  60. {$IF DEFINED(CPUAARCH64)}
  61. Int64
  62. {$ELSEIF DEFINED(CPUMIPS)}
  63. LongInt
  64. {$ELSE}UIntPtr{$ENDIF};
  65. TUnixMode =
  66. {$IF DEFINED(CPUPOWERPC)}
  67. LongInt
  68. {$ELSE}Cardinal{$ENDIF};
  69. {$ELSE}
  70. TUnixTime = TTime;
  71. TUnixMode = TMode;
  72. {$ENDIF}
  73. type
  74. PTimeStruct = ^TTimeStruct;
  75. TTimeStruct = record
  76. tm_sec: cint; //* Seconds. [0-60] (1 leap second)
  77. tm_min: cint; //* Minutes. [0-59]
  78. tm_hour: cint; //* Hours. [0-23]
  79. tm_mday: cint; //* Day. [1-31]
  80. tm_mon: cint; //* Month. [0-11]
  81. tm_year: cint; //* Year - 1900.
  82. tm_wday: cint; //* Day of week. [0-6]
  83. tm_yday: cint; //* Days in year. [0-365]
  84. tm_isdst: cint; //* DST. [-1/0/1]
  85. tm_gmtoff: clong; //* Seconds east of UTC.
  86. tm_zone: pansichar; //* Timezone abbreviation.
  87. end;
  88. type
  89. //en Password file entry record
  90. passwd = record
  91. pw_name: PChar; //en< user name
  92. pw_passwd: PChar; //en< user password
  93. pw_uid: uid_t; //en< user ID
  94. pw_gid: gid_t; //en< group ID
  95. {$IF DEFINED(BSD)}
  96. pw_change: time_t; //en< password change time
  97. pw_class: PChar; //en< user access class
  98. {$ENDIF}
  99. {$IF NOT DEFINED(HAIKU)}
  100. pw_gecos: PChar; //en< real name
  101. {$ENDIF}
  102. pw_dir: PChar; //en< home directory
  103. pw_shell: PChar; //en< shell program
  104. {$IF DEFINED(HAIKU)}
  105. pw_gecos: PChar; //en< real name
  106. {$ENDIF}
  107. {$IF DEFINED(BSD)}
  108. pw_expire: time_t; //en< account expiration
  109. pw_fields: cint; //en< internal: fields filled in
  110. {$ENDIF}
  111. end;
  112. TPasswordRecord = passwd;
  113. PPasswordRecord = ^TPasswordRecord;
  114. //en Group file entry record
  115. group = record
  116. gr_name: PChar; //en< group name
  117. gr_passwd: PChar; //en< group password
  118. gr_gid: gid_t; //en< group ID
  119. gr_mem: ^PChar; //en< group members
  120. end;
  121. TGroupRecord = group;
  122. PGroupRecord = ^TGroupRecord;
  123. type
  124. {$IF DEFINED(DARWIN)}
  125. TDarwinStat64 = record { the types are real}
  126. st_dev : dev_t; // inode's device
  127. st_mode : mode_t; // inode protection mode
  128. st_nlink : nlink_t; // number of hard links
  129. st_ino : cuint64; // inode's number
  130. st_uid : uid_t; // user ID of the file's owner
  131. st_gid : gid_t; // group ID of the file's group
  132. st_rdev : dev_t; // device type
  133. st_atime : time_t; // time of last access
  134. st_atimensec : clong; // nsec of last access
  135. st_mtime : time_t; // time of last data modification
  136. st_mtimensec : clong; // nsec of last data modification
  137. st_ctime : time_t; // time of last file status change
  138. st_ctimensec : clong; // nsec of last file status change
  139. st_birthtime : time_t; // File creation time
  140. st_birthtimensec : clong; // nsec of file creation time
  141. st_size : off_t; // file size, in bytes
  142. st_blocks : cint64; // blocks allocated for file
  143. st_blksize : cuint32; // optimal blocksize for I/O
  144. st_flags : cuint32; // user defined flags for file
  145. st_gen : cuint32; // file generation number
  146. st_lspare : cint32;
  147. st_qspare : array[0..1] Of cint64;
  148. end;
  149. TDCStat = TDarwinStat64;
  150. {$ELSE}
  151. TDCStat = BaseUnix.Stat;
  152. {$ENDIF}
  153. PDCStat = ^TDCStat;
  154. TDCStatHelper = record Helper for TDCStat
  155. Public
  156. function birthtime: TFileTimeEx; inline;
  157. function mtime: TFileTimeEx; inline;
  158. function atime: TFileTimeEx; inline;
  159. function ctime: TFileTimeEx; inline;
  160. end;
  161. Function DC_fpLstat( const path:RawByteString; var Info:TDCStat ): cint; inline;
  162. // nanoseconds supported
  163. function DC_FileSetTime(const FileName: String;
  164. const mtime : TFileTimeEx;
  165. const birthtime: TFileTimeEx;
  166. const atime : TFileTimeEx ): Boolean;
  167. {en
  168. Set the close-on-exec flag to all
  169. }
  170. procedure FileCloseOnExecAll;
  171. {en
  172. Set the close-on-exec (FD_CLOEXEC) flag
  173. }
  174. procedure FileCloseOnExec(Handle: System.THandle); inline;
  175. {en
  176. Find mount point of file system where file is located
  177. @param(FileName File name)
  178. @returns(Mount point of file system)
  179. }
  180. function FindMountPointPath(const FileName: String): String;
  181. {en
  182. Change owner and group of a file (does not follow symbolic links)
  183. @param(path Full path to file)
  184. @param(owner User ID)
  185. @param(group Group ID)
  186. @returns(On success, zero is returned. On error, -1 is returned, and errno is set appropriately)
  187. }
  188. function fpLChown(path : String; owner : TUid; group : TGid): cInt;
  189. {en
  190. Set process group ID for job control
  191. }
  192. function setpgid(pid, pgid: pid_t): cint; cdecl; external clib;
  193. {en
  194. The getenv() function searches the environment list to find the
  195. environment variable name, and returns a pointer to the corresponding
  196. value string.
  197. }
  198. function getenv(name: PAnsiChar): PAnsiChar; cdecl; external clib;
  199. {en
  200. Change or add an environment variable
  201. @param(name Environment variable name)
  202. @param(value Environment variable value)
  203. @param(overwrite Overwrite environment variable if exist)
  204. @returns(The function returns zero on success, or -1 if there was
  205. insufficient space in the environment)
  206. }
  207. function setenv(const name, value: PAnsiChar; overwrite: cint): cint; cdecl; external clib;
  208. {en
  209. Remove an environment variable
  210. @param(name Environment variable name)
  211. @returns(The function returns zero on success, or -1 on error)
  212. }
  213. function unsetenv(const name: PAnsiChar): cint; cdecl; external clib;
  214. {en
  215. Get password file entry
  216. @param(uid User ID)
  217. @returns(The function returns a pointer to a structure containing the broken-out
  218. fields of the record in the password database that matches the user ID)
  219. }
  220. function getpwuid(uid: uid_t): PPasswordRecord; cdecl; external clib;
  221. {en
  222. Get password file entry
  223. @param(name User name)
  224. @returns(The function returns a pointer to a structure containing the broken-out
  225. fields of the record in the password database that matches the user name)
  226. }
  227. function getpwnam(const name: PChar): PPasswordRecord; cdecl; external clib;
  228. {en
  229. Get group file entry
  230. @param(gid Group ID)
  231. @returns(The function returns a pointer to a structure containing the broken-out
  232. fields of the record in the group database that matches the group ID)
  233. }
  234. function getgrgid(gid: gid_t): PGroupRecord; cdecl; external clib;
  235. {en
  236. Get group file entry
  237. @param(name Group name)
  238. @returns(The function returns a pointer to a structure containing the broken-out
  239. fields of the record in the group database that matches the group name)
  240. }
  241. function getgrnam(name: PChar): PGroupRecord; cdecl; external clib;
  242. {en
  243. Get configuration information at run time
  244. }
  245. function sysconf(name: cint): clong; cdecl; external clib;
  246. function FileLock(Handle: System.THandle; Mode: cInt): System.THandle;
  247. function fpMkTime(tm: PTimeStruct): TTime;
  248. function fpLocalTime(timer: PTime; tp: PTimeStruct): PTimeStruct;
  249. {$IF DEFINED(LINUX)}
  250. var
  251. KernVersion: UInt16;
  252. function fpFDataSync(fd: cint): cint;
  253. function fpCloneFile(src_fd, dst_fd: cint): Boolean;
  254. function fpFAllocate(fd: cint; mode: cint; offset, len: coff_t): cint;
  255. {$ENDIF}
  256. {$IF DEFINED(UNIX) AND NOT DEFINED(DARWIN)}
  257. function fnmatch(const pattern: PAnsiChar; const str: PAnsiChar; flags: cint): cint; cdecl; external clib;
  258. {$ENDIF}
  259. implementation
  260. uses
  261. Unix, DCConvertEncoding, LazUTF8
  262. {$IF DEFINED(DARWIN)}
  263. , DCDarwin
  264. {$ELSEIF DEFINED(LINUX)}
  265. , Dos, DCLinux, DCOSUtils
  266. {$ELSEIF DEFINED(FREEBSD)}
  267. , DCOSUtils
  268. {$ENDIF}
  269. ;
  270. {$IF not DEFINED(LINUX)}
  271. function TDCStatHelper.birthtime: TFileTimeEx;
  272. begin
  273. {$IF DEFINED(HAIKU)}
  274. Result.sec:= st_crtime;
  275. Result.nanosec:= st_crtimensec;
  276. {$ELSE}
  277. Result.sec:= st_birthtime;
  278. Result.nanosec:= st_birthtimensec;
  279. {$ENDIF}
  280. end;
  281. function TDCStatHelper.mtime: TFileTimeEx;
  282. begin
  283. Result.sec:= st_mtime;
  284. Result.nanosec:= st_mtimensec;
  285. end;
  286. function TDCStatHelper.atime: TFileTimeEx;
  287. begin
  288. Result.sec:= st_atime;
  289. Result.nanosec:= st_atimensec;
  290. end;
  291. function TDCStatHelper.ctime: TFileTimeEx;
  292. begin
  293. Result.sec:= st_ctime;
  294. Result.nanosec:= st_ctimensec;
  295. end;
  296. {$ELSE}
  297. function TDCStatHelper.birthtime: TFileTimeEx;
  298. begin
  299. Result:= TFileTimeExNull;
  300. end;
  301. function TDCStatHelper.mtime: TFileTimeEx;
  302. begin
  303. Result.sec:= Int64(st_mtime);
  304. Result.nanosec:= Int64(st_mtime_nsec);
  305. end;
  306. function TDCStatHelper.atime: TFileTimeEx;
  307. begin
  308. Result.sec:= Int64(st_atime);
  309. Result.nanosec:= Int64(st_atime_nsec);
  310. end;
  311. function TDCStatHelper.ctime: TFileTimeEx;
  312. begin
  313. Result.sec:= Int64(st_ctime);
  314. Result.nanosec:= Int64(st_ctime_nsec);
  315. end;
  316. {$ENDIF}
  317. {$IF DEFINED(DARWIN)}
  318. Function fpLstat64( path:pchar; Info:pstat ): cint; cdecl; external clib name 'lstat64';
  319. Function DC_fpLstat( const path:RawByteString; var Info:TDCStat ): cint; inline;
  320. var
  321. SystemPath: RawByteString;
  322. begin
  323. SystemPath:=ToSingleByteFileSystemEncodedFileName( path );
  324. Result:= fpLstat64( pchar(SystemPath), @info );
  325. end;
  326. {$ELSE}
  327. Function DC_fpLstat( const path:RawByteString; var Info:TDCStat ): cint; inline;
  328. begin
  329. Result:= fpLstat( path, info );
  330. end;
  331. {$ENDIF}
  332. function fputimes( path:pchar; times:Array of UnixType.timeval ): cint; cdecl; external clib name 'utimes';
  333. function DC_FileSetTime(const FileName: String;
  334. const mtime : TFileTimeEx;
  335. const birthtime: TFileTimeEx;
  336. const atime : TFileTimeEx ): Boolean;
  337. var
  338. timevals: Array[0..1] of UnixType.timeval;
  339. begin
  340. Result:= false;
  341. // last access time
  342. timevals[0].tv_sec:= atime.sec;
  343. timevals[0].tv_usec:= round( Extended(atime.nanosec) / 1000.0 );
  344. // last modification time
  345. timevals[1].tv_sec:= mtime.sec;
  346. timevals[1].tv_usec:= round( Extended(mtime.nanosec) / 1000.0 );
  347. if fputimes(pchar(UTF8ToSys(FileName)), timevals) <> 0 then exit;
  348. {$IF not DEFINED(DARWIN)}
  349. Result:= true;
  350. {$ELSE}
  351. Result:= MacosFileSetCreationTime( FileName, birthtime );
  352. {$ENDIF}
  353. end;
  354. {$IF DEFINED(BSD)}
  355. type rlim_t = Int64;
  356. {$ENDIF}
  357. const
  358. {$IF DEFINED(LINUX)}
  359. _SC_OPEN_MAX = 4;
  360. FICLONE = $40049409;
  361. RLIM_INFINITY = rlim_t(-1);
  362. {$ELSEIF DEFINED(BSD)}
  363. _SC_OPEN_MAX = 5;
  364. RLIM_INFINITY = rlim_t(High(QWord) shr 1);
  365. {$ELSEIF DEFINED(HAIKU)}
  366. _SC_OPEN_MAX = 20;
  367. RLIMIT_NOFILE = 4;
  368. RLIM_INFINITY = $ffffffff;
  369. {$ENDIF}
  370. procedure tzset(); cdecl; external clib;
  371. function mktime(tp: PTimeStruct): TTime; cdecl; external clib;
  372. function localtime_r(timer: PTime; tp: PTimeStruct): PTimeStruct; cdecl; external clib;
  373. function lchown(path : PChar; owner : TUid; group : TGid): cInt; cdecl; external clib;
  374. {$IF DEFINED(LINUX)}
  375. function fdatasync(fd: cint): cint; cdecl; external clib;
  376. function fallocate(fd: cint; mode: cint; offset, len: coff_t): cint; cdecl; external clib;
  377. {$ENDIF}
  378. {$IF DEFINED(LINUX) OR DEFINED(FREEBSD)}
  379. var
  380. hLibC: TLibHandle = NilHandle;
  381. procedure LoadCLibrary;
  382. begin
  383. hLibC:= mbLoadLibrary(mbGetModuleName(@tzset));
  384. end;
  385. {$ENDIF}
  386. {$IF DEFINED(LINUX) OR DEFINED(BSD)}
  387. var
  388. close_range: function(first: cuint; last: cuint; flags: cint): cint; cdecl = nil;
  389. {$ENDIF}
  390. procedure FileCloseOnExecAll;
  391. const
  392. MAX_FD = 1024;
  393. var
  394. fd: cint;
  395. p: TRLimit;
  396. fd_max: rlim_t = RLIM_INFINITY;
  397. begin
  398. {$IF DEFINED(LINUX) OR DEFINED(BSD)}
  399. if Assigned(close_range) then
  400. begin
  401. close_range(3, High(Int32), CLOSE_RANGE_CLOEXEC);
  402. Exit;
  403. end;
  404. {$ENDIF}
  405. if (FpGetRLimit(RLIMIT_NOFILE, @p) = 0) and (p.rlim_cur <> RLIM_INFINITY) then
  406. fd_max:= p.rlim_cur
  407. else begin
  408. {$IF DECLARED(_SC_OPEN_MAX)}
  409. fd_max:= sysconf(_SC_OPEN_MAX);
  410. {$ENDIF}
  411. end;
  412. if (fd_max = RLIM_INFINITY) or (fd_max > MAX_FD) then
  413. fd_max:= MAX_FD;
  414. for fd:= 3 to cint(fd_max) do
  415. FileCloseOnExec(fd);
  416. end;
  417. procedure FileCloseOnExec(Handle: System.THandle);
  418. begin
  419. {$IF DECLARED(FD_CLOEXEC)}
  420. FpFcntl(Handle, F_SETFD, FpFcntl(Handle, F_GETFD) or FD_CLOEXEC);
  421. {$ENDIF}
  422. end;
  423. function FindMountPointPath(const FileName: String): String;
  424. var
  425. I, J: LongInt;
  426. sTemp: String;
  427. recStat: Stat;
  428. st_dev: QWord;
  429. begin
  430. // Set root directory as mount point by default
  431. Result:= PathDelim;
  432. // Get stat info for original file
  433. if (fpLStat(FileName, recStat) < 0) then Exit;
  434. // Save device ID of original file
  435. st_dev:= recStat.st_dev;
  436. J:= Length(FileName);
  437. for I:= J downto 1 do
  438. begin
  439. if FileName[I] = PathDelim then
  440. begin
  441. if (I = 1) then
  442. sTemp:= PathDelim
  443. else
  444. sTemp:= Copy(FileName, 1, I - 1);
  445. // Stat for current directory
  446. if (fpLStat(sTemp, recStat) < 0) then Continue;
  447. // If it is a link then checking link destination
  448. if fpS_ISLNK(recStat.st_mode) then
  449. begin
  450. sTemp:= fpReadlink(sTemp);
  451. Result:= FindMountPointPath(sTemp);
  452. Exit;
  453. end;
  454. // Check device ID
  455. if (recStat.st_dev <> st_dev) then
  456. begin
  457. Result:= Copy(FileName, 1, J);
  458. Exit;
  459. end;
  460. J:= I;
  461. end;
  462. end;
  463. end;
  464. function fpLChown(path: String; owner: TUid; group: TGid): cInt;
  465. begin
  466. Result := lchown(PAnsiChar(CeUtf8ToSys(path)), owner, group);
  467. if Result = -1 then fpseterrno(fpgetCerrno);
  468. end;
  469. function FileLock(Handle: System.THandle; Mode: cInt): System.THandle;
  470. var
  471. lockop: cint;
  472. lockres: cint;
  473. lockerr: cint;
  474. {$IFDEF LINUX}
  475. Sbfs: TStatFS;
  476. {$ENDIF}
  477. begin
  478. Result:= Handle;
  479. case (Mode and $F0) of
  480. fmShareCompat,
  481. fmShareExclusive:
  482. lockop:= LOCK_EX or LOCK_NB;
  483. fmShareDenyWrite:
  484. lockop:= LOCK_SH or LOCK_NB;
  485. else
  486. Exit;
  487. end;
  488. {$IFDEF LINUX}
  489. if (fpFStatFS(Handle, @Sbfs) = 0) then
  490. begin
  491. case UInt32(Sbfs.fstype) of
  492. NFS_SUPER_MAGIC,
  493. SMB_SUPER_MAGIC,
  494. SMB2_MAGIC_NUMBER,
  495. CIFS_MAGIC_NUMBER: Exit;
  496. end;
  497. end;
  498. {$ENDIF}
  499. repeat
  500. lockres:= fpFlock(Handle, lockop);
  501. until (lockres = 0) or (fpgeterrno <> ESysEIntr);
  502. lockerr:= fpgeterrno;
  503. {
  504. Only return an error if locks are working and the file was already
  505. locked. Not if locks are simply unsupported (e.g., on Angstrom Linux
  506. you always get ESysNOLCK in the default configuration)
  507. }
  508. if (lockres <> 0) and ((lockerr = ESysEAGAIN) or (lockerr = ESysEDEADLK)) then
  509. begin
  510. Result:= -1;
  511. FileClose(Handle);
  512. end;
  513. end;
  514. function fpMkTime(tm: PTimeStruct): TTime;
  515. begin
  516. Result := mktime(tm);
  517. if (Result = TTime(-1)) then fpseterrno(fpgetCerrno);
  518. end;
  519. function fpLocalTime(timer: PTime; tp: PTimeStruct): PTimeStruct;
  520. begin
  521. Result := localtime_r(timer, tp);
  522. if (Result = nil) then fpseterrno(fpgetCerrno);
  523. end;
  524. {$IF DEFINED(LINUX)}
  525. function fpFDataSync(fd: cint): cint;
  526. begin
  527. Result := fdatasync(fd);
  528. if Result = -1 then fpseterrno(fpgetCerrno);
  529. end;
  530. function fpCloneFile(src_fd, dst_fd: cint): Boolean;
  531. var
  532. ASource: Pointer absolute src_fd;
  533. begin
  534. Result:= (FpIOCtl(dst_fd, FICLONE, ASource) = 0);
  535. end;
  536. function fpFAllocate(fd: cint; mode: cint; offset, len: coff_t): cint;
  537. begin
  538. Result := fallocate(fd, mode, offset, len);
  539. if Result = -1 then fpseterrno(fpgetCerrno);
  540. end;
  541. {$ENDIF}
  542. procedure Initialize;
  543. begin
  544. tzset();
  545. {$IF DEFINED(LINUX) OR DEFINED(FREEBSD)}
  546. LoadCLibrary;
  547. {$IF DEFINED(LINUX)}
  548. KernVersion:= BEtoN(DosVersion);
  549. // Linux kernel >= 5.11
  550. if KernVersion >= $50B then
  551. {$ENDIF}
  552. begin
  553. Pointer(close_range):= GetProcAddress(hLibC, 'close_range');
  554. end;
  555. {$ELSEIF DEFINED(DARWIN)}
  556. close_range:= @CloseRange;
  557. {$ENDIF}
  558. end;
  559. initialization
  560. Initialize;
  561. end.