unixutils.pp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY;without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. Unit UnixUtils;
  14. Interface
  15. uses
  16. SysUtils,Libc,Classes;
  17. { ---------------------------------------------------------------------
  18. Error handling
  19. ---------------------------------------------------------------------}
  20. Type
  21. EUnixOperationFailed = Class(Exception)
  22. Private
  23. FErrorCode : Integer;
  24. Public
  25. Constructor Create (AnErrorCode : Longint);
  26. Property ErrorCode: Integer Read FErrorCode;
  27. end;
  28. Function StrError(Error:longint):string;
  29. Function CheckUnixError (Error : Integer) : Integer;
  30. { ---------------------------------------------------------------------
  31. File handling
  32. ---------------------------------------------------------------------}
  33. Const
  34. PathSeparator = '/';
  35. Type
  36. TUnixFileStream = Class(TFileStream)
  37. Procedure GetInfo(Var StatInfo: TStatBuf);
  38. Procedure LockRegion(Cmd,LockType,Whence : Integer;
  39. Offset,Len : __off_t);
  40. Procedure ReadLock(Whence : Integer;Offset,Len : __off_t; Wait : Boolean);
  41. Procedure WriteLock(Whence : Integer;Offset,Len : __off_t; Wait : Boolean);
  42. Procedure UnLock(Whence : Integer;Offset,Len : __off_t);
  43. end;
  44. { Useful constants and structures }
  45. Const
  46. PermissionBits : Array [1..9] of Integer =
  47. (S_IRUSR,S_IWUSR,S_IXUSR,
  48. S_IRGRP,S_IWGRP,S_IXGRP,
  49. S_IROTH,S_IWOTH,S_IXOTH);
  50. PermissionChars : Array[1..9] of char =
  51. ('r','w','x','r','w','x','r','w','x');
  52. SuidBits : array[1..3] of Integer = (S_ISUID,S_ISGID,S_ISVTX);
  53. SuidChars : Array[1..3] of char = ('s','s','t') ;
  54. { Utility functions }
  55. Type
  56. TPermissionString = String[9];
  57. Type
  58. TGlobFlag = (gfErr,gfMark,gfNoSort,gfNoCheck,gfAppend,gfNoEscape,
  59. gfPeriod,gfBrace,gfNoMagic,gfTilde,gfOnlyDir,gfTildeCheck);
  60. TGlobFlags = Set of TGlobFlag;
  61. TFnmFlag = (fnmNoEscape,fnmPathName,fnmPeriod,fnmLeadingDir,fnmCaseFold);
  62. TFnmFlags = Set of TFnmFlag;
  63. Procedure Stat (Const FileName : String; Var StatInfo : TStatBuf);
  64. Procedure LStat (Const FileName : String; Var StatInfo : TStatBuf);
  65. Procedure StatFS (Const FileName : String; Var StatInfo : TStatFS);
  66. Procedure UnLink(Const FileName: String);
  67. Procedure Link (Const FromName, ToName: String);
  68. Procedure SymLink (Const FromName, ToName: String);
  69. Function ReadLink (Const FileName : String) : String;
  70. Function FilePermString (Const Mode : __mode_t) : TPermissionString;
  71. Function PermStringToMask (Const Perm : TPermissionstring) : __mode_t;
  72. Procedure ChMod(Const FileName : String; Mode : __mode_t);
  73. Procedure ReName(Const OldName,NewName : String);
  74. Function Access(Const FileName : String; Mode :Integer) : Boolean;
  75. Procedure Glob(Const Pattern : String; Flags : TGlobFlags; List : TStrings);
  76. // Globfree call with correct calling conventions.
  77. Procedure globfree(__pglob: PGlobData);cdecl;external 'libc.so.6' name 'globfree';
  78. Function OpenDir(Const Dir : String) : PDirectoryStream;
  79. Function FNMatch(Const Pattern,Name : String; Flags : TFnmFlags) : Boolean;
  80. Procedure GetDirectoryListing(Const Dir : String; List : TStrings);overload;
  81. Procedure GetDirectoryListing(Const Dir,Pattern : String;
  82. Flags : TFnmFlags; List : TStrings);overload;
  83. Procedure GetSubdirectories(Const Dir : String; List : TStrings);
  84. Function StripTrailingSeparator(Const Dir : String) : String;
  85. Function AddTraiLingSeparator(Const Dir : String) : String;
  86. Function FileSizeToString(Size: Int64) : String;
  87. Function SetMntEnt(FileName,Mode : String) : PIOFile;
  88. Procedure Mount(Const Device,Directory,FileSystemType : String; Flags : Cardinal; Data: Pointer);
  89. Procedure Umount(Const FileName);
  90. Function FSTypeToString(FSType : Integer) : String;
  91. Procedure fcntl(Handle: Integer; Command: Integer; Var Lock: TFlock);
  92. Procedure Dup2(Stream1,Stream2 : THandleStream);
  93. Function Dup(Stream : THandleStream) : THandleStream;
  94. { ---------------------------------------------------------------------
  95. Process management routines.
  96. ---------------------------------------------------------------------}
  97. function SetUID(UID: __uid_t):Boolean;
  98. function SetEUID(UID: __uid_t):Boolean;
  99. function SetGID(GroupID: __gid_t):Boolean;
  100. function SetEGID(GroupID: __gid_t):Boolean;
  101. function SetREUID(RUID: __uid_t; EUID: __uid_t):Boolean;
  102. function SetREGID(RGID: __gid_t; EGID: __gid_t):Boolean;
  103. Function GetGroups(Var A : Array of __gid_t) : Integer;
  104. Function Group_member(GroupID : __gid_t) : Boolean;
  105. Function Fork : __pid_t;
  106. Function wait(var Status : Integer) : pid_t;
  107. Function waitpid(PID : pid_t;var Status : Integer;options : Integer) : pid_t;
  108. Function ConvertStatusToString(Status : Integer) : String;
  109. Procedure Execve(ProgName : String; Args,Env : TStrings);
  110. Procedure Execv(ProgName : String; Args : TStrings);
  111. Procedure Execvp(ProgName : String; Args : TStrings);
  112. Procedure Execle(ProgName : String; Args : Array of string;Env : TStrings);
  113. Procedure Execl(ProgName : String; Args : Array of string);
  114. Procedure Execlp(ProgName : String; Args : Array of string);
  115. { ---------------------------------------------------------------------
  116. User/group management routines
  117. ---------------------------------------------------------------------}
  118. Type
  119. EUserLookupError = Class(Exception);
  120. EGroupLookupError = Class(Exception);
  121. EShadowLookupError = Class(Exception);
  122. { User functions }
  123. Function getpwnam(Const UserName: String) : PPasswordRecord;
  124. Procedure GetUserData(Const UserName : String; Var Data : TPasswordRecord); overload;
  125. Procedure GetUserData(Uid : Integer; Var Data : TPasswordRecord); overload;
  126. function GetUserName(UID : Integer) : String;
  127. function GetUserId(Const UserName : String) : Integer;
  128. function GetUserGid(Const UserName : String) : Integer;
  129. function GetUserDir(Const UserName : String): String;
  130. function GetUserDescription(Const UserName : String): String;
  131. Procedure GetUserList(List : Tstrings);overload;
  132. Procedure GetUserList(List : TStrings; WithIDs : Boolean);overload;
  133. { Group functions }
  134. Function getgrnam(Const GroupName: String) : PGroup;
  135. Procedure GetGroupData(Const GroupName : String; Var Data : TGroup); overload;
  136. Procedure GetGroupData(Gid : Integer; Var Data : TGroup); overload;
  137. function GetGroupName(GID : Integer) : String;
  138. function GetGroupId(Const GroupName : String) : Integer;
  139. Procedure GetGroupList(List : Tstrings);overload;
  140. Procedure GetGroupList(List : TStrings; WithIDs : Boolean);overload;
  141. Procedure GetGroupMembers(GID : Integer;List : TStrings);overload;
  142. Procedure GetGroupMembers(Const GroupName : String;List : TStrings);overload;
  143. { Shadow password functions }
  144. function getspnam(UserName : String): PPasswordFileEntry;
  145. function sgetspent(Line : String): PPasswordFileEntry;
  146. Procedure GetUserShadowData(Const UserName : String; Var Data : TPasswordFileEntry);overload;
  147. Procedure GetUserShadowData(UID : Integer; Var Data : TPasswordFileEntry);overload;
  148. { Extra functions }
  149. Function GetUserGroup(Const UserName : String) : String;
  150. Implementation
  151. ResourceString
  152. SErrOpeningDir = 'Could not open directory "%s" for reading';
  153. SUnknownFileSystemType = 'Unknown filesystem (%x)';
  154. SNormalExitWithErrCode = 'Child exited with error code %d';
  155. SNormalExit = 'Child exited normally';
  156. SSignalExit = 'Child exited abnormally due to signal %d';
  157. SStopped = 'Child stopped due to signal %d';
  158. SErrUnknowStatusCode = 'Unknown exit status : %d';
  159. EnoSuchUserName = 'Unknown username: "%s"';
  160. EnoSuchUserID = 'Unknown user ID: %d';
  161. EnoSuchGroupName = 'Unknown groupname: "%s"';
  162. EnoSuchGroupID = 'Unknown group ID: %d';
  163. ENoShadowEntry = 'No shadow file entry for "%s"';
  164. EShadowNotPermitted = 'Not enough permissions to access shadow password file';
  165. { ---------------------------------------------------------------------
  166. Error handling
  167. ---------------------------------------------------------------------}
  168. Function StrError(Error:longint):string;
  169. begin
  170. StrError:=strpas(libc.strerror(Error));
  171. end;
  172. Constructor EUnixOperationFailed.Create(AnErrorCode : Longint);
  173. begin
  174. FErrorCode:=AnErrorCode;
  175. Inherited Create(StrError(Abs(AnErrorCode)));
  176. end;
  177. Function CheckUnixError (Error : Integer) : Integer;
  178. begin
  179. If (Error<0) then
  180. Raise EUnixOperationFailed.Create(Error);
  181. Result:=Error;
  182. end;
  183. Procedure Stat(Const FileName : String; Var StatInfo : TStatBuf);
  184. begin
  185. CheckUnixError(Libc.Stat(Pchar(FileName),StatInfo));
  186. end;
  187. Procedure LStat(Const FileName : String; Var StatInfo : TStatBuf);
  188. begin
  189. CheckUnixError(Libc.LStat(Pchar(FileName),StatInfo));
  190. end;
  191. Procedure StatFS (Const FileName : String; Var StatInfo : TStatFS);
  192. begin
  193. CheckUnixError(Libc.statfs(PChar(FileName),STatinfo));
  194. end;
  195. Procedure UnLink(const FileName: String);
  196. begin
  197. CheckUnixError(Libc.unlink(PChar(FileName)));
  198. end;
  199. Procedure Link (Const FromName, ToName: String);
  200. begin
  201. CheckUnixError(Libc.Link(PChar(FromName),Pchar(ToName)));
  202. end;
  203. Procedure SymLink (Const FromName, ToName: String);
  204. begin
  205. CheckUnixError(Libc.SymLink(PChar(FromName),Pchar(ToName)));
  206. end;
  207. Function ReadLink (Const FileName : String) : String;
  208. Const
  209. NameBufSize = 1024;
  210. begin
  211. SetLength(Result,NameBufSize);
  212. Try
  213. SetLength(Result,CheckUnixError(Libc.readlink(pchar(FileName),PChar(Result),NameBufSize)));
  214. except
  215. SetLength(Result,0);
  216. raise
  217. end;
  218. end;
  219. Function FilePermString (Const Mode : __mode_t) : TPermissionString;
  220. Var
  221. i : longint;
  222. Function ModeToSUIBit (C,RC : Char) : Char;
  223. begin
  224. If C='x' then
  225. Result:=RC
  226. else
  227. Result:=Upcase(RC);
  228. end;
  229. begin
  230. Result:=StringOfChar('-',9);
  231. For I:=1 to 9 do
  232. If ((Mode and PermissionBits[i])=PermissionBits[i]) then
  233. Result[i]:=PermissionChars[i];
  234. For I:=1 to 3 do
  235. If ((Mode and SuidBits[i])=SuidBits[i]) then
  236. If Result[I*3]='x' then
  237. Result[i*3]:=SuidChars[i]
  238. else
  239. Result[i*3]:=UpCase(SuidChars[i]);
  240. end;
  241. Function PermStringToMask (Const Perm : TPermissionstring) : __mode_t;
  242. Var
  243. I : integer;
  244. begin
  245. Result := 0;
  246. For I:=1 to 9 do
  247. If Perm[i]=PermissionChars[i] Then
  248. Result:=Result or PermissionBits[i]
  249. else
  250. If (I mod 3)=0 then
  251. If Perm[i]=suidchars[i] then
  252. Result:=(Result or PermissionBits[I]) or (SuidBits[I div 3])
  253. else if (Perm[i]=upcase(SuidChars[I])) then
  254. Result:=(Result or SuidBits[I div 3])
  255. end;
  256. Procedure ChMod(Const FileName : String; Mode : __mode_t);
  257. begin
  258. CheckUnixError(Libc.Chmod(PChar(FileName),Mode));
  259. end;
  260. Procedure ReName(Const OldName,NewName : String);
  261. begin
  262. CheckUnixError(Libc.__rename(Pchar(OldName),Pchar(NewName)));
  263. end;
  264. Function Access(Const FileName : String; Mode :Integer) : Boolean;
  265. begin
  266. Result:=Libc.Access(Pchar(FileName),Mode)=0;
  267. end;
  268. Procedure Glob(Const Pattern : String; Flags : TGlobFlags; List : TStrings);
  269. Const
  270. // Append and offset are masked to 0, since they're useless.
  271. GF : Array[TGlobFlag] of Integer
  272. = (GLOB_ERR,GLOB_MARK,GLOB_NOSORT,GLOB_NOCHECK,0,
  273. GLOB_NOESCAPE,GLOB_PERIOD,GLOB_BRACE,GLOB_NOMAGIC,
  274. GLOB_TILDE,GLOB_ONLYDIR, GLOB_TILDE_CHECK);
  275. Type
  276. TPCharArray = Array[Word] of PChar;
  277. PPCharArray = ^TPcharArray;
  278. Var
  279. gd : TGlobData;
  280. i : TGlobFlag;
  281. f : Integer;
  282. begin
  283. FillChar(gd,SizeOf(TGlobData),#0);
  284. f:=0;
  285. For i:=gfErr to gfTildeCheck do
  286. If i in Flags then
  287. F:=F or GF[i];
  288. Try
  289. CheckUnixError(Libc.Glob(Pchar(Pattern),F,Nil,@gd));
  290. If Not (gfAppend in Flags) then
  291. List.Clear;
  292. for f:=0 to gd.gl_pathc-1 do
  293. List.add(Strpas(PPCharArray(gd.gl_pathv)^[f]));
  294. finally
  295. globFree(@gd);
  296. end;
  297. end;
  298. Function OpenDir(Const Dir : String) : PDirectoryStream;
  299. begin
  300. Result:=Libc.OpenDir(Pchar(Dir));
  301. If (Result=Nil) then
  302. Raise EUnixOperationFailed.CreateFmt(SErrOpeningDir,[Dir]);
  303. end;
  304. Procedure GetDirectoryListing(Const Dir : String; List : TStrings);overload;
  305. Var
  306. P : PDirent;
  307. D : PDirectoryStream;
  308. begin
  309. D:=OpenDir(Dir);
  310. Try
  311. P:=ReadDir(D);
  312. List.Clear;
  313. While P<>Nil do
  314. begin
  315. List.Add(StrPas(@p^.d_name[0]));
  316. P:=ReadDir(D);
  317. end;
  318. Finally
  319. CloseDir(D);
  320. end;
  321. end;
  322. Function FNtoFNFlags(Flags :TFnmFlags) : Integer;
  323. Const
  324. FV : Array[TFnmFlag] of integer =
  325. (FNM_NOESCAPE,FNM_PATHNAME,FNM_PERIOD,FNM_LEADING_DIR,FNM_CASEFOLD);
  326. Var i : TFnmFlag;
  327. begin
  328. Result:=0;
  329. For I:=fnmNoEscape to fnmCaseFold do
  330. If i in Flags then
  331. Result:=Result or FV[i];
  332. end;
  333. Function FNMatch(Const Pattern,Name : String; Flags : TFnmFlags) : Boolean;
  334. begin
  335. Result:=Libc.FNMatch(PChar(Pattern),PChar(Name),FNtoFNFlags(Flags))=0;
  336. end;
  337. Procedure GetDirectoryListing(Const Dir,Pattern : String; Flags : TFnmFlags; List : TStrings);overload;
  338. Var
  339. P : PDirent;
  340. D : PDirectoryStream;
  341. PP,PF : PChar;
  342. F : Integer;
  343. begin
  344. D:=OpenDir(Dir);
  345. PP:=PChar(Pattern);
  346. F:=FNtoFNFlags(Flags);
  347. Try
  348. P:=ReadDir(D);
  349. List.Clear;
  350. While P<>Nil do
  351. begin
  352. PF:=@p^.d_name[0];
  353. If Libc.FNMatch(PP,PF,F)=0 then
  354. List.Add(StrPas(PF));
  355. P:=ReadDir(D);
  356. end;
  357. Finally
  358. CloseDir(D);
  359. end;
  360. end;
  361. Procedure GetSubdirectories(Const Dir : String; List : TStrings);
  362. Var
  363. P : PDirent;
  364. D : PDirectoryStream;
  365. S : String;
  366. StatInfo : TStatBuf;
  367. begin
  368. D:=OpenDir(Dir);
  369. Try
  370. P:=ReadDir(D);
  371. List.Clear;
  372. While P<>Nil do
  373. begin
  374. S:=StrPas(@p^.d_name[0]);
  375. LStat(Dir+'/'+S,StatInfo);
  376. If S_ISDIR(StatInfo.st_mode) then
  377. List.Add(S);
  378. P:=ReadDir(D);
  379. end;
  380. Finally
  381. CloseDir(D);
  382. end;
  383. end;
  384. Function StripTrailingSeparator(Const Dir : String) : String;
  385. Var
  386. L : Integer;
  387. begin
  388. Result:=Dir;
  389. L:=Length(result);
  390. If (L>1) and (Result[l]=PathSeparator) then
  391. SetLength(Result,L-1);
  392. end;
  393. Function AddTraiLingSeparator(Const Dir : String) : String;
  394. Var
  395. L : Integer;
  396. begin
  397. Result:=Dir;
  398. L:=Length(Result);
  399. If (L>0) and (Result[l]<>PathSeparator) then
  400. Result:=Result+PathSeparator;
  401. end;
  402. Function FileSizeToString(Size: Int64) : String;
  403. Const
  404. Sizes : Array [0..4] of String =
  405. ('Bytes','Kb','Mb','Gb','Tb');
  406. Var
  407. F : Double;
  408. I : longint;
  409. begin
  410. If Size>1024 Then
  411. begin
  412. F:=Size;
  413. I:=0;
  414. While (F>1024) and (I<4) do
  415. begin
  416. F:=F / 1024;
  417. Inc(i);
  418. end;
  419. Result:=Format('%4.2f %s',[F,Sizes[i]]);
  420. end
  421. else
  422. Result:=Format('%d %s',[Size,Sizes[0]]);
  423. end;
  424. Function SetMntEnt(FileName,Mode : String) : PIOFile;
  425. begin
  426. Result:=Libc.setmntent(PChar(FileName),Pchar(Mode));
  427. end;
  428. Procedure Mount(Const Device,Directory,FileSystemType : String; Flags : Cardinal; Data: Pointer);
  429. begin
  430. If Libc.Mount(PChar(Device),PChar(Directory),PChar(FileSystemType),Flags,Data)<>0 then
  431. CheckUnixError(Libc.errno);
  432. end;
  433. Procedure Umount(Const FileName);
  434. begin
  435. If Libc.umount(PChar(FileName))<>0 then
  436. CheckUnixError(Libc.Errno);
  437. end;
  438. Function FSTypeToString(FSType : Integer) : String;
  439. begin
  440. Case LongWord(FStype) of
  441. $ADFF : Result:='affs';
  442. $137D : Result:='ext';
  443. $EF51,$EF53 : Result:='ext2';
  444. $F995E849 : Result := 'hpfs';
  445. $9660 : Result:='iso9660';
  446. $137F,$138F,$2468,$2478 : Result:='minix';
  447. $4d44 : Result:='msdos';
  448. $564c : Result:='ncp';
  449. $6969 : Result:='nfs';
  450. $9fa0 : Result:='proc';
  451. $517B : Result:='smb';
  452. $012FF7B4,$012FFB5,$012FFB6,$012FFB7 : Result:='xenix';
  453. $00011954 : Result:='ufs';
  454. $012FD16D : Result:='xia';
  455. $1CD1 : Result:='devpts';
  456. $5346544E : Result:='ntfs';
  457. else
  458. Result:=Format(SUnknownFileSystemType,[FStype]);
  459. end;
  460. end;
  461. Procedure fcntl(Handle: Integer; Command: Integer; Var Lock: TFlock);
  462. begin
  463. CheckUnixError(Libc.fcntl(Handle,Command,Lock));
  464. end;
  465. Procedure Dup2(Stream1,Stream2 : THandleStream);
  466. begin
  467. CheckUnixError(Libc.Dup2(Stream1.Handle,Stream2.Handle));
  468. end;
  469. Function Dup(Stream : THandleStream) : THandleStream;
  470. begin
  471. Result:=ThandleStream.Create(CheckUnixError(Libc.Dup(Stream.Handle)));
  472. end;
  473. { ---------------------------------------------------------------------
  474. TUnixFileStream implementation
  475. ---------------------------------------------------------------------}
  476. Procedure TUnixFileStream.GetInfo(Var StatInfo: TStatBuf);
  477. begin
  478. CheckUnixError(FStat(Handle,StatInfo));
  479. end;
  480. procedure TUnixFileStream.LockRegion(Cmd, LockType, Whence: Integer;
  481. Offset, Len: __off_t);
  482. Var
  483. Lock : TFlock;
  484. begin
  485. With Lock do
  486. begin
  487. L_type:=LockType;
  488. L_start:=Offset;
  489. L_Len:=Len;
  490. L_whence:=Whence;
  491. end;
  492. fcntl(Handle,cmd,Lock);
  493. end;
  494. procedure TUnixFileStream.ReadLock(Whence: Integer; Offset, Len: __off_t;
  495. Wait: Boolean);
  496. begin
  497. If Wait then
  498. LockRegion(F_SETLKW,F_RDLCK,whence,offset,len)
  499. else
  500. LockRegion(F_SETLK,F_RDLCK,whence,offset,len)
  501. end;
  502. procedure TUnixFileStream.UnLock(Whence: Integer; Offset, Len: __off_t);
  503. begin
  504. LockRegion(F_SETLK,F_UNLCK,whence,offset,len)
  505. end;
  506. procedure TUnixFileStream.WriteLock(Whence: Integer; Offset, Len: __off_t;
  507. Wait: Boolean);
  508. begin
  509. If Wait then
  510. LockRegion(F_SETLKW,F_WRLCK,whence,offset,len)
  511. else
  512. LockRegion(F_SETLK,F_WRLCK,whence,offset,len)
  513. end;
  514. { ---------------------------------------------------------------------
  515. Process utilities
  516. ---------------------------------------------------------------------}
  517. function SetUID(UID: __uid_t):Boolean;
  518. begin
  519. Result:=LibC.setuid(UID)=0;
  520. end;
  521. function SetEUID(UID: __uid_t):Boolean;
  522. begin
  523. Result:=LibC.seteuid(UID)=0;
  524. end;
  525. function SetGID(GroupID: __gid_t):Boolean;
  526. begin
  527. Result:=LibC.setgid(GroupID)=0;
  528. end;
  529. function SetEGID(GroupID: __gid_t):Boolean;
  530. begin
  531. Result:=LibC.setegid(GroupID)=0;
  532. end;
  533. function SetREUID(RUID: __uid_t; EUID: __uid_t):Boolean;
  534. begin
  535. Result:=LibC.setreuid(RUID,EUID)=0;
  536. end;
  537. function SetREGID(RGID: __gid_t; EGID: __gid_t):Boolean;
  538. begin
  539. Result:=LibC.setregid(RGID,EGID)=0;
  540. end;
  541. Function GetGroups(var A : Array of __gid_t) : Integer;
  542. begin
  543. Result:=LibC.GetGroups(High(A)+1,A);
  544. end;
  545. Function Group_member(GroupID : __gid_t) : Boolean;
  546. begin
  547. Result:=LibC.group_member(GroupID)<>0;
  548. end;
  549. Function Fork : __pid_t;
  550. begin
  551. Result:=CheckUnixError(LibC.Fork);
  552. end;
  553. Function wait(var Status : Integer) : pid_t;
  554. begin
  555. Result:=Libc.wait(@Status);
  556. end;
  557. Function waitpid(PID : pid_t;var Status : Integer;options : Integer) : pid_t;
  558. begin
  559. Result:=Libc.WaitPid(Pid,@Status,Options);
  560. end;
  561. Function ConvertStatusToString(Status : Integer) : String;
  562. begin
  563. If WIfExited(Status) then
  564. If WExitStatus(Status)=0 then
  565. Result:=SNormalExit
  566. else
  567. Result:=Format(SNormalExitWithErrCode,[WExitStatus(Status)])
  568. else If WIfSIgnaled(Status) then
  569. Result:=Format(SSignalExit,[WTermSig(Status)])
  570. else if WIfStopped(Status) then
  571. Result:=Format(SStopped,[WStopSig(Status)])
  572. else
  573. Result:=Format(SErrUnknowStatusCode,[Status])
  574. end;
  575. Type
  576. TPCharArray = Array[Word] of pchar;
  577. PPCharArray = ^TPcharArray;
  578. Function StringsToPCharList(Arg0 : String;List : TStrings) : PPChar;
  579. Var
  580. I,Org : Integer;
  581. S : String;
  582. begin
  583. I:=(List.Count)+1;
  584. If Arg0<>'' Then
  585. begin
  586. Inc(i);
  587. Org:=1;
  588. end
  589. else
  590. org:=0;
  591. GetMem(Result,I*sizeOf(PChar));
  592. PPCharArray(Result)^[List.Count+org]:=Nil;
  593. If Arg0<>'' Then
  594. PPCharArray(Result)^[0]:=StrNew(PChar(Arg0));
  595. For I:=0 to List.Count-1 do
  596. begin
  597. S:=List[i];
  598. PPCharArray(Result)^[i+org]:=StrNew(PChar(S));
  599. end;
  600. end;
  601. Procedure FreePCharList(List : PPChar);
  602. Var
  603. I : integer;
  604. begin
  605. I:=0;
  606. While List[i]<>Nil do
  607. begin
  608. StrDispose(List[i]);
  609. Inc(I);
  610. end;
  611. FreeMem(List);
  612. end;
  613. Procedure Execve(ProgName : String; Args,Env : TStrings);
  614. Var
  615. ArgP,EnvP : PPChar;
  616. begin
  617. ArgP:=StringsToPCharList(ExtractFileName(ProgName),Args);
  618. try
  619. EnvP:=StringsToPCharList('',Env);
  620. try
  621. CheckUnixError(Libc.execve(PChar(ProgName),ArgP,EnvP));
  622. finally
  623. FreePCharList(EnvP);
  624. end;
  625. finally
  626. FreePCharList(ArgP);
  627. end;
  628. end;
  629. Procedure Execv(ProgName : String; Args : TStrings);
  630. Var
  631. ArgP : PPChar;
  632. begin
  633. ArgP:=StringsToPCharList(ExtractFileName(ProgName),Args);
  634. try
  635. CheckUnixError(Libc.execv(PChar(ProgName),ArgP));
  636. finally
  637. FreePCharList(ArgP);
  638. end;
  639. end;
  640. Procedure Execvp(ProgName : String; Args : TStrings);
  641. Var
  642. ArgP : PPChar;
  643. begin
  644. ArgP:=StringsToPCharList(ExtractFileName(ProgName),Args);
  645. try
  646. CheckUnixError(Libc.execvp(PChar(ProgName),ArgP));
  647. finally
  648. FreePCharList(ArgP);
  649. end;
  650. end;
  651. Function CommandArgsToPCharList(Arg0 :String;Args : Array of string) : PPChar;
  652. Var
  653. I,Org : Integer;
  654. begin
  655. I:=High(Args)+2;
  656. If Arg0<>'' Then
  657. begin
  658. Inc(i);
  659. Org:=1;
  660. end
  661. else
  662. org:=0;
  663. GetMem(Result,I*sizeOf(PChar));
  664. PPCharArray(Result)^[i-1]:=Nil;
  665. If Arg0<>'' Then
  666. PPCharArray(Result)^[0]:=StrNew(PChar(Arg0));
  667. For I:=0 to High(Args) do
  668. PPCharArray(Result)^[i+org]:=StrNew(PChar(Args[i]));
  669. end;
  670. Procedure Execle(ProgName : String; Args : Array of string;Env : TStrings);
  671. Var
  672. ArgP,EnvP : PPChar;
  673. begin
  674. ArgP:=CommandArgsToPCharList(ExtractFileName(ProgName),Args);
  675. try
  676. EnvP:=StringsToPCharList('',Env);
  677. try
  678. CheckUnixError(Libc.execve(PChar(ProgName),ArgP,EnvP));
  679. finally
  680. FreePCharList(EnvP);
  681. end;
  682. finally
  683. FreePCharList(ArgP);
  684. end;
  685. end;
  686. Procedure Execl(ProgName : String; Args : Array of string);
  687. Var
  688. ArgP : PPChar;
  689. begin
  690. ArgP:=CommandArgsToPCharList(ExtractFileName(ProgName),Args);
  691. try
  692. CheckUnixError(Libc.execv(PChar(ProgName),ArgP));
  693. finally
  694. FreePCharList(ArgP);
  695. end;
  696. end;
  697. Procedure Execlp(ProgName : String; Args : Array of string);
  698. Var
  699. ArgP : PPChar;
  700. begin
  701. ArgP:=CommandArgsToPCharList(ExtractFileName(ProgName),Args);
  702. try
  703. CheckUnixError(Libc.execvp(PChar(ProgName),ArgP));
  704. finally
  705. FreePCharList(ArgP);
  706. end;
  707. end;
  708. { ---------------------------------------------------------------------
  709. User/Group management routines.
  710. ---------------------------------------------------------------------}
  711. Function getpwnam(Const UserName: String) : PPasswordRecord;
  712. begin
  713. Result:=libc.getpwnam(Pchar(UserName));
  714. end;
  715. Procedure GetUserData(Const UserName : String; Var Data : TPasswordRecord);
  716. Var P : PPasswordRecord;
  717. begin
  718. P:=Getpwnam(UserName);
  719. If P<>Nil then
  720. Data:=P^
  721. else
  722. Raise EUserLookupError.CreateFmt(ENoSuchUserName,[UserName]);
  723. end;
  724. Procedure GetUserData(Uid : Integer; Var Data : TPasswordRecord);
  725. Var P : PPasswordRecord;
  726. begin
  727. P:=Getpwuid(Uid);
  728. If P<>Nil then
  729. Data:=P^
  730. else
  731. Raise EUserLookupError.CreateFmt(ENoSuchUserID,[Uid]);
  732. end;
  733. function GetUserName(UID : Integer) : String;
  734. Var
  735. UserData : TPasswordRecord;
  736. begin
  737. GetuserData(UID,UserData);
  738. Result:=strpas(UserData.pw_Name);
  739. end;
  740. function GetUserId(Const UserName : String) : Integer;
  741. Var
  742. UserData : TPasswordRecord;
  743. begin
  744. GetUserData(UserName,UserData);
  745. Result:=UserData.pw_uid;
  746. end;
  747. function GetUserGId(Const UserName : String) : Integer;
  748. Var
  749. UserData : TPasswordRecord;
  750. begin
  751. GetUserData(UserName,UserData);
  752. Result:=UserData.pw_gid;
  753. end;
  754. function GetUserDir(Const UserName : String): String;
  755. Var
  756. UserData : TPasswordRecord;
  757. begin
  758. GetUserData(UserName,UserData);
  759. Result:=strpas(UserData.pw_dir);
  760. end;
  761. function GetUserDescription(Const UserName : String): String;
  762. Var
  763. UserData : TPasswordRecord;
  764. begin
  765. GetUserData(UserName,UserData);
  766. Result:=strpas(UserData.pw_gecos);
  767. end;
  768. Procedure GetUserList(List : Tstrings);
  769. begin
  770. GetUserList(List,False);
  771. end;
  772. Procedure GetUserList(List : TStrings; WithIDs : Boolean);
  773. Var
  774. P : PPasswordRecord;
  775. begin
  776. List.Clear;
  777. setpwent;
  778. try
  779. Repeat
  780. P:=getpwent;
  781. If P<>Nil then
  782. begin
  783. If WithIDs then
  784. List.Add(Format('%d=%s',[P^.pw_uid,strpas(p^.pw_name)]))
  785. else
  786. List.Add(strpas(p^.pw_name));
  787. end;
  788. until (P=Nil);
  789. finally
  790. endpwent;
  791. end;
  792. end;
  793. { ---------------------------------------------------------------------
  794. Group Functions
  795. ---------------------------------------------------------------------}
  796. Function getgrnam(Const GroupName: String) : PGroup;
  797. begin
  798. Result:=libc.getgrnam(Pchar(GroupName));
  799. end;
  800. Procedure GetGroupData(Const GroupName : String; Var Data : TGroup); overload;
  801. Var P : PGroup;
  802. begin
  803. P:=Getgrnam(GroupName);
  804. If P<>Nil then
  805. Data:=P^
  806. else
  807. Raise EGroupLookupError.CreateFmt(ENoSuchGroupName,[GroupName]);
  808. end;
  809. Procedure GetGroupData(Gid : Integer; Var Data : TGroup); overload;
  810. Var P : PGroup;
  811. begin
  812. P:=Getgrgid(gid);
  813. If P<>Nil then
  814. Data:=P^
  815. else
  816. Raise EGroupLookupError.CreateFmt(ENoSuchGroupID,[Gid]);
  817. end;
  818. function GetGroupName(GID : Integer) : String;
  819. Var
  820. G : TGroup;
  821. begin
  822. GetGroupData(Gid,G);
  823. Result:=StrPas(G.gr_name);
  824. end;
  825. function GetGroupId(Const GroupName : String) : Integer;
  826. Var
  827. G : TGroup;
  828. begin
  829. GetGroupData(GroupName,G);
  830. Result:=G.gr_gid;
  831. end;
  832. Procedure GetGroupList(List : Tstrings);overload;
  833. begin
  834. GetGroupList(List,False);
  835. end;
  836. Procedure GetGroupList(List : TStrings; WithIDs : Boolean);overload;
  837. Var
  838. G : PGroup;
  839. begin
  840. List.Clear;
  841. setgrent;
  842. try
  843. Repeat
  844. G:=getgrent;
  845. If G<>Nil then
  846. begin
  847. If WithIDs then
  848. List.Add(Format('%d=%s',[G^.gr_gid,strpas(G^.gr_name)]))
  849. else
  850. List.Add(strpas(G^.gr_name));
  851. end;
  852. until (G=Nil);
  853. finally
  854. endgrent;
  855. end;
  856. end;
  857. Function PCharListToStrings(P : PPChar; List : TStrings) : Integer;
  858. begin
  859. List.Clear;
  860. While P^<>Nil do
  861. begin
  862. List.Add(StrPas(P^));
  863. P:=PPChar(PChar(P)+SizeOf(PChar));
  864. end;
  865. Result:=List.Count;
  866. end;
  867. Procedure GetGroupMembers(GID : Integer;List : TStrings);
  868. Var
  869. G : TGroup;
  870. begin
  871. GetGroupData(GID,G);
  872. PCharListToStrings(G.gr_mem,List);
  873. end;
  874. Procedure GetGroupMembers(Const GroupName : String;List : TStrings);
  875. Var
  876. G : TGroup;
  877. begin
  878. GetGroupData(GroupName,G);
  879. PCharListToStrings(g.gr_mem,List);
  880. end;
  881. { Shadow password functions }
  882. function getspnam(UserName : String): PPasswordFileEntry;
  883. begin
  884. result:=Libc.getspnam(Pchar(UserName));
  885. end;
  886. function sgetspent(Line : String): PPasswordFileEntry;
  887. begin
  888. Result:=libc.sgetspent(Pchar(Line));
  889. end;
  890. Procedure GetUserShadowData(Const UserName : String; Var Data : TPasswordFileEntry);
  891. Var
  892. P : PPasswordFileEntry;
  893. begin
  894. P:=getspnam(UserName);
  895. If P=Nil then
  896. If (GetUID<>0) and (GetEUID<>0) then
  897. Raise EShadowLookupError.Create(EShadowNotPermitted)
  898. else
  899. Raise EShadowLookupError.CreateFmt(ENoShadowEntry,[UserName])
  900. else
  901. Data:=P^;
  902. end;
  903. Procedure GetUserShadowData(UID : Integer; Var Data : TPasswordFileEntry);
  904. begin
  905. GetUserShadowData(GetUserName(UID),Data);
  906. end;
  907. { Extra functions }
  908. Function GetUserGroup(Const UserName : String) : String;
  909. begin
  910. GetGroupName(GetUserGid(UserName));
  911. end;
  912. end.