dcunix.pas 17 KB

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