unixutils.pp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191
  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;
  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 globfree(__pglob: PGlobData);cdecl;external 'libc.so.6' name 'globfree';
  184. Procedure Stat(Const FileName : String; Var StatInfo : TStatBuf);
  185. begin
  186. CheckUnixError(Libc.Stat(Pchar(FileName),StatInfo));
  187. end;
  188. Procedure LStat(Const FileName : String; Var StatInfo : TStatBuf);
  189. begin
  190. CheckUnixError(Libc.LStat(Pchar(FileName),StatInfo));
  191. end;
  192. Procedure StatFS (Const FileName : String; Var StatInfo : TStatFS);
  193. begin
  194. CheckUnixError(Libc.statfs(PChar(FileName),STatinfo));
  195. end;
  196. Procedure UnLink(const FileName: String);
  197. begin
  198. CheckUnixError(Libc.unlink(PChar(FileName)));
  199. end;
  200. Procedure Link (Const FromName, ToName: String);
  201. begin
  202. CheckUnixError(Libc.Link(PChar(FromName),Pchar(ToName)));
  203. end;
  204. Procedure SymLink (Const FromName, ToName: String);
  205. begin
  206. CheckUnixError(Libc.SymLink(PChar(FromName),Pchar(ToName)));
  207. end;
  208. Function ReadLink (Const FileName : String) : String;
  209. Const
  210. NameBufSize = 1024;
  211. begin
  212. SetLength(Result,NameBufSize);
  213. Try
  214. SetLength(Result,CheckUnixError(Libc.readlink(pchar(FileName),PChar(Result),NameBufSize)));
  215. except
  216. SetLength(Result,0);
  217. raise
  218. end;
  219. end;
  220. Function FilePermString (Const Mode : __mode_t) : TPermissionString;
  221. Var
  222. i : longint;
  223. Function ModeToSUIBit (C,RC : Char) : Char;
  224. begin
  225. If C='x' then
  226. Result:=RC
  227. else
  228. Result:=Upcase(RC);
  229. end;
  230. begin
  231. Result:=StringOfChar('-',9);
  232. For I:=1 to 9 do
  233. If ((Mode and PermissionBits[i])=PermissionBits[i]) then
  234. Result[i]:=PermissionChars[i];
  235. For I:=1 to 3 do
  236. If ((Mode and SuidBits[i])=SuidBits[i]) then
  237. If Result[I*3]='x' then
  238. Result[i*3]:=SuidChars[i]
  239. else
  240. Result[i*3]:=UpCase(SuidChars[i]);
  241. end;
  242. Function PermStringToMask (Const Perm : TPermissionstring) : __mode_t;
  243. Var
  244. I : integer;
  245. begin
  246. Result := 0;
  247. For I:=1 to 9 do
  248. If Perm[i]=PermissionChars[i] Then
  249. Result:=Result or PermissionBits[i]
  250. else
  251. If (I mod 3)=0 then
  252. If Perm[i]=suidchars[i] then
  253. Result:=(Result or PermissionBits[I]) or (SuidBits[I div 3])
  254. else if (Perm[i]=upcase(SuidChars[I])) then
  255. Result:=(Result or SuidBits[I div 3])
  256. end;
  257. Procedure ChMod(Const FileName : String; Mode : __mode_t);
  258. begin
  259. CheckUnixError(Libc.Chmod(PChar(FileName),Mode));
  260. end;
  261. Procedure ReName(Const OldName,NewName : String);
  262. begin
  263. CheckUnixError(Libc.__rename(Pchar(OldName),Pchar(NewName)));
  264. end;
  265. Function Access(Const FileName : String; Mode :Integer) : Boolean;
  266. begin
  267. Result:=Libc.Access(Pchar(FileName),Mode)=0;
  268. end;
  269. Procedure Glob(Const Pattern : String; Flags : TGlobFlags; List : TStrings);
  270. Const
  271. // Append and offset are masked to 0, since they're useless.
  272. GF : Array[TGlobFlag] of Integer
  273. = (GLOB_ERR,GLOB_MARK,GLOB_NOSORT,GLOB_NOCHECK,0,
  274. GLOB_NOESCAPE,GLOB_PERIOD,GLOB_BRACE,GLOB_NOMAGIC,
  275. GLOB_TILDE,GLOB_ONLYDIR, GLOB_TILDE_CHECK);
  276. Type
  277. TPCharArray = Array[Word] of PChar;
  278. PPCharArray = ^TPcharArray;
  279. Var
  280. gd : TGlobData;
  281. i : TGlobFlag;
  282. f : Integer;
  283. begin
  284. FillChar(gd,SizeOf(TGlobData),#0);
  285. f:=0;
  286. For i:=gfErr to gfTildeCheck do
  287. If i in Flags then
  288. F:=F or GF[i];
  289. Try
  290. CheckUnixError(Libc.Glob(Pchar(Pattern),F,Nil,@gd));
  291. If Not (gfAppend in Flags) then
  292. List.Clear;
  293. for f:=0 to gd.gl_pathc-1 do
  294. List.add(Strpas(PPCharArray(gd.gl_pathv)^[f]));
  295. finally
  296. globFree(@gd);
  297. end;
  298. end;
  299. Function OpenDir(Const Dir : String) : PDirectoryStream;
  300. begin
  301. Result:=Libc.OpenDir(Pchar(Dir));
  302. If (Result=Nil) then
  303. Raise EUnixOperationFailed.CreateFmt(SErrOpeningDir,[Dir]);
  304. end;
  305. Procedure GetDirectoryListing(Const Dir : String; List : TStrings);overload;
  306. Var
  307. P : PDirent;
  308. D : PDirectoryStream;
  309. begin
  310. D:=OpenDir(Dir);
  311. Try
  312. P:=ReadDir(D);
  313. List.Clear;
  314. While P<>Nil do
  315. begin
  316. List.Add(StrPas(@p^.d_name[0]));
  317. P:=ReadDir(D);
  318. end;
  319. Finally
  320. CloseDir(D);
  321. end;
  322. end;
  323. Function FNtoFNFlags(Flags :TFnmFlags) : Integer;
  324. Const
  325. FV : Array[TFnmFlag] of integer =
  326. (FNM_NOESCAPE,FNM_PATHNAME,FNM_PERIOD,FNM_LEADING_DIR,FNM_CASEFOLD);
  327. Var i : TFnmFlag;
  328. begin
  329. Result:=0;
  330. For I:=fnmNoEscape to fnmCaseFold do
  331. If i in Flags then
  332. Result:=Result or FV[i];
  333. end;
  334. Function FNMatch(Const Pattern,Name : String; Flags : TFnmFlags) : Boolean;
  335. begin
  336. Result:=Libc.FNMatch(PChar(Pattern),PChar(Name),FNtoFNFlags(Flags))=0;
  337. end;
  338. Procedure GetDirectoryListing(Const Dir,Pattern : String; Flags : TFnmFlags; List : TStrings);overload;
  339. Var
  340. P : PDirent;
  341. D : PDirectoryStream;
  342. PP,PF : PChar;
  343. F : Integer;
  344. begin
  345. D:=OpenDir(Dir);
  346. PP:=PChar(Pattern);
  347. F:=FNtoFNFlags(Flags);
  348. Try
  349. P:=ReadDir(D);
  350. List.Clear;
  351. While P<>Nil do
  352. begin
  353. PF:=@p^.d_name[0];
  354. If Libc.FNMatch(PP,PF,F)=0 then
  355. List.Add(StrPas(PF));
  356. P:=ReadDir(D);
  357. end;
  358. Finally
  359. CloseDir(D);
  360. end;
  361. end;
  362. Procedure GetSubdirectories(Const Dir : String; List : TStrings);
  363. Var
  364. P : PDirent;
  365. D : PDirectoryStream;
  366. S : String;
  367. StatInfo : TStatBuf;
  368. begin
  369. D:=OpenDir(Dir);
  370. Try
  371. P:=ReadDir(D);
  372. List.Clear;
  373. While P<>Nil do
  374. begin
  375. S:=StrPas(@p^.d_name[0]);
  376. LStat(Dir+'/'+S,StatInfo);
  377. If S_ISDIR(StatInfo.st_mode) then
  378. List.Add(S);
  379. P:=ReadDir(D);
  380. end;
  381. Finally
  382. CloseDir(D);
  383. end;
  384. end;
  385. Function StripTrailingSeparator(Const Dir : String) : String;
  386. Var
  387. L : Integer;
  388. begin
  389. Result:=Dir;
  390. L:=Length(result);
  391. If (L>1) and (Result[l]=PathSeparator) then
  392. SetLength(Result,L-1);
  393. end;
  394. Function AddTraiLingSeparator(Const Dir : String) : String;
  395. Var
  396. L : Integer;
  397. begin
  398. Result:=Dir;
  399. L:=Length(Result);
  400. If (L>0) and (Result[l]<>PathSeparator) then
  401. Result:=Result+PathSeparator;
  402. end;
  403. Function FileSizeToString(Size: Int64) : String;
  404. Const
  405. Sizes : Array [0..4] of String =
  406. ('Bytes','Kb','Mb','Gb','Tb');
  407. Var
  408. F : Double;
  409. I : longint;
  410. begin
  411. If Size>1024 Then
  412. begin
  413. F:=Size;
  414. I:=0;
  415. While (F>1024) and (I<4) do
  416. begin
  417. F:=F / 1024;
  418. Inc(i);
  419. end;
  420. Result:=Format('%4.2f %s',[F,Sizes[i]]);
  421. end
  422. else
  423. Result:=Format('%d %s',[Size,Sizes[0]]);
  424. end;
  425. Function SetMntEnt(FileName,Mode : String) : PIOFile;
  426. begin
  427. Result:=Libc.setmntent(PChar(FileName),Pchar(Mode));
  428. end;
  429. Procedure Mount(Const Device,Directory,FileSystemType : String; Flags : Cardinal; Data: Pointer);
  430. begin
  431. If Libc.Mount(PChar(Device),PChar(Directory),PChar(FileSystemType),Flags,Data)<>0 then
  432. CheckUnixError(Libc.errno);
  433. end;
  434. Procedure Umount(Const FileName);
  435. begin
  436. If Libc.umount(PChar(FileName))<>0 then
  437. CheckUnixError(Libc.Errno);
  438. end;
  439. Function FSTypeToString(FSType : Integer) : String;
  440. begin
  441. Case FStype of
  442. $ADFF : Result:='affs';
  443. $137D : Result:='ext';
  444. $EF51,$EF53 : Result:='ext2';
  445. $F995E849 : Result := 'hpfs';
  446. $9660 : Result:='iso9660';
  447. $137F,$138F,$2468,$2478 : Result:='minix';
  448. $4d44 : Result:='msdos';
  449. $564c : Result:='ncp';
  450. $6969 : Result:='nfs';
  451. $9fa0 : Result:='proc';
  452. $517B : Result:='smb';
  453. $012FF7B4,$012FFB5,$012FFB6,$012FFB7 : Result:='xenix';
  454. $00011954 : Result:='ufs';
  455. $012FD16D : Result:='xia';
  456. $1CD1 : Result:='devpts';
  457. $5346544E : Result:='ntfs';
  458. else
  459. Result:=Format(SUnknownFileSystemType,[FStype]);
  460. end;
  461. end;
  462. Procedure fcntl(Handle: Integer; Command: Integer; Var Lock: TFlock);
  463. begin
  464. CheckUnixError(Libc.fcntl(Handle,Command,Lock));
  465. end;
  466. Procedure Dup2(Stream1,Stream2 : THandleStream);
  467. begin
  468. CheckUnixError(Libc.Dup2(Stream1.Handle,Stream2.Handle));
  469. end;
  470. Function Dup(Stream : THandleStream) : THandleStream;
  471. begin
  472. Result:=ThandleStream.Create(CheckUnixError(Libc.Dup(Stream.Handle)));
  473. end;
  474. { ---------------------------------------------------------------------
  475. TUnixFileStream implementation
  476. ---------------------------------------------------------------------}
  477. Procedure TUnixFileStream.GetInfo(Var StatInfo: TStatBuf);
  478. begin
  479. CheckUnixError(FStat(Handle,StatInfo));
  480. end;
  481. procedure TUnixFileStream.LockRegion(Cmd, LockType, Whence: Integer;
  482. Offset, Len: __off_t);
  483. Var
  484. Lock : TFlock;
  485. begin
  486. With Lock do
  487. begin
  488. L_type:=LockType;
  489. L_start:=Offset;
  490. L_Len:=Len;
  491. L_whence:=Whence;
  492. end;
  493. fcntl(Handle,cmd,Lock);
  494. end;
  495. procedure TUnixFileStream.ReadLock(Whence: Integer; Offset, Len: __off_t;
  496. Wait: Boolean);
  497. begin
  498. If Wait then
  499. LockRegion(F_SETLKW,F_RDLCK,whence,offset,len)
  500. else
  501. LockRegion(F_SETLK,F_RDLCK,whence,offset,len)
  502. end;
  503. procedure TUnixFileStream.UnLock(Whence: Integer; Offset, Len: __off_t);
  504. begin
  505. LockRegion(F_SETLK,F_UNLCK,whence,offset,len)
  506. end;
  507. procedure TUnixFileStream.WriteLock(Whence: Integer; Offset, Len: __off_t;
  508. Wait: Boolean);
  509. begin
  510. If Wait then
  511. LockRegion(F_SETLKW,F_WRLCK,whence,offset,len)
  512. else
  513. LockRegion(F_SETLK,F_WRLCK,whence,offset,len)
  514. end;
  515. { ---------------------------------------------------------------------
  516. Process utilities
  517. ---------------------------------------------------------------------}
  518. function SetUID(UID: __uid_t):Boolean;
  519. begin
  520. Result:=LibC.setuid(UID)=0;
  521. end;
  522. function SetEUID(UID: __uid_t):Boolean;
  523. begin
  524. Result:=LibC.seteuid(UID)=0;
  525. end;
  526. function SetGID(GroupID: __gid_t):Boolean;
  527. begin
  528. Result:=LibC.setgid(GroupID)=0;
  529. end;
  530. function SetEGID(GroupID: __gid_t):Boolean;
  531. begin
  532. Result:=LibC.setegid(GroupID)=0;
  533. end;
  534. function SetREUID(RUID: __uid_t; EUID: __uid_t):Boolean;
  535. begin
  536. Result:=LibC.setreuid(RUID,EUID)=0;
  537. end;
  538. function SetREGID(RGID: __gid_t; EGID: __gid_t):Boolean;
  539. begin
  540. Result:=LibC.setregid(RGID,EGID)=0;
  541. end;
  542. Function GetGroups(var A : Array of __gid_t) : Integer;
  543. begin
  544. Result:=LibC.GetGroups(High(A)+1,A);
  545. end;
  546. Function Group_member(GroupID : __gid_t) : Boolean;
  547. begin
  548. Result:=LibC.group_member(GroupID)<>0;
  549. end;
  550. Function Fork : __pid_t;
  551. begin
  552. Result:=CheckUnixError(LibC.Fork);
  553. end;
  554. Function wait(var Status : Integer) : pid_t;
  555. begin
  556. Result:=Libc.wait(@Status);
  557. end;
  558. Function waitpid(PID : pid_t;var Status : Integer;options : Integer) : pid_t;
  559. begin
  560. Result:=Libc.WaitPid(Pid,@Status,Options);
  561. end;
  562. Function ConvertStatusToString(Status : Integer) : String;
  563. begin
  564. If WIfExited(Status) then
  565. If WExitStatus(Status)=0 then
  566. Result:=SNormalExit
  567. else
  568. Result:=Format(SNormalExitWithErrCode,[WExitStatus(Status)])
  569. else If WIfSIgnaled(Status) then
  570. Result:=Format(SSignalExit,[WTermSig(Status)])
  571. else if WIfStopped(Status) then
  572. Result:=Format(SStopped,[WStopSig(Status)])
  573. else
  574. Result:=Format(SErrUnknowStatusCode,[Status])
  575. end;
  576. Type
  577. TPCharArray = Array[Word] of pchar;
  578. PPCharArray = ^TPcharArray;
  579. Function StringsToPCharList(Arg0 : String;List : TStrings) : PPChar;
  580. Var
  581. I,Org : Integer;
  582. S : String;
  583. begin
  584. I:=(List.Count)+1;
  585. If Arg0<>'' Then
  586. begin
  587. Inc(i);
  588. Org:=1;
  589. end
  590. else
  591. org:=0;
  592. GetMem(Result,I*sizeOf(PChar));
  593. PPCharArray(Result)^[List.Count+org]:=Nil;
  594. If Arg0<>'' Then
  595. PPCharArray(Result)^[0]:=StrNew(PChar(Arg0));
  596. For I:=0 to List.Count-1 do
  597. begin
  598. S:=List[i];
  599. PPCharArray(Result)^[i+org]:=StrNew(PChar(S));
  600. end;
  601. end;
  602. Procedure FreePCharList(List : PPChar);
  603. Var
  604. I : integer;
  605. begin
  606. I:=0;
  607. While List[i]<>Nil do
  608. begin
  609. StrDispose(List[i]);
  610. Inc(I);
  611. end;
  612. FreeMem(List);
  613. end;
  614. Procedure Execve(ProgName : String; Args,Env : TStrings);
  615. Var
  616. ArgP,EnvP : PPChar;
  617. begin
  618. ArgP:=StringsToPCharList(ExtractFileName(ProgName),Args);
  619. try
  620. EnvP:=StringsToPCharList('',Env);
  621. try
  622. CheckUnixError(Libc.execve(PChar(ProgName),ArgP,EnvP));
  623. finally
  624. FreePCharList(EnvP);
  625. end;
  626. finally
  627. FreePCharList(ArgP);
  628. end;
  629. end;
  630. Procedure Execv(ProgName : String; Args : TStrings);
  631. Var
  632. ArgP : PPChar;
  633. begin
  634. ArgP:=StringsToPCharList(ExtractFileName(ProgName),Args);
  635. try
  636. CheckUnixError(Libc.execv(PChar(ProgName),ArgP));
  637. finally
  638. FreePCharList(ArgP);
  639. end;
  640. end;
  641. Procedure Execvp(ProgName : String; Args : TStrings);
  642. Var
  643. ArgP : PPChar;
  644. begin
  645. ArgP:=StringsToPCharList(ExtractFileName(ProgName),Args);
  646. try
  647. CheckUnixError(Libc.execvp(PChar(ProgName),ArgP));
  648. finally
  649. FreePCharList(ArgP);
  650. end;
  651. end;
  652. Function CommandArgsToPCharList(Arg0 :String;Args : Array of string) : PPChar;
  653. Var
  654. I,Org : Integer;
  655. begin
  656. I:=High(Args)+2;
  657. If Arg0<>'' Then
  658. begin
  659. Inc(i);
  660. Org:=1;
  661. end
  662. else
  663. org:=0;
  664. GetMem(Result,I*sizeOf(PChar));
  665. PPCharArray(Result)^[i-1]:=Nil;
  666. If Arg0<>'' Then
  667. PPCharArray(Result)^[0]:=StrNew(PChar(Arg0));
  668. For I:=0 to High(Args) do
  669. PPCharArray(Result)^[i+org]:=StrNew(PChar(Args[i]));
  670. end;
  671. Procedure Execle(ProgName : String; Args : Array of string;Env : TStrings);
  672. Var
  673. ArgP,EnvP : PPChar;
  674. begin
  675. ArgP:=CommandArgsToPCharList(ExtractFileName(ProgName),Args);
  676. try
  677. EnvP:=StringsToPCharList('',Env);
  678. try
  679. CheckUnixError(Libc.execve(PChar(ProgName),ArgP,EnvP));
  680. finally
  681. FreePCharList(EnvP);
  682. end;
  683. finally
  684. FreePCharList(ArgP);
  685. end;
  686. end;
  687. Procedure Execl(ProgName : String; Args : Array of string);
  688. Var
  689. ArgP : PPChar;
  690. begin
  691. ArgP:=CommandArgsToPCharList(ExtractFileName(ProgName),Args);
  692. try
  693. CheckUnixError(Libc.execv(PChar(ProgName),ArgP));
  694. finally
  695. FreePCharList(ArgP);
  696. end;
  697. end;
  698. Procedure Execlp(ProgName : String; Args : Array of string);
  699. Var
  700. ArgP : PPChar;
  701. begin
  702. ArgP:=CommandArgsToPCharList(ExtractFileName(ProgName),Args);
  703. try
  704. CheckUnixError(Libc.execvp(PChar(ProgName),ArgP));
  705. finally
  706. FreePCharList(ArgP);
  707. end;
  708. end;
  709. { ---------------------------------------------------------------------
  710. User/Group management routines.
  711. ---------------------------------------------------------------------}
  712. Function getpwnam(Const UserName: String) : PPasswordRecord;
  713. begin
  714. Result:=libc.getpwnam(Pchar(UserName));
  715. end;
  716. Procedure GetUserData(Const UserName : String; Var Data : TPasswordRecord);
  717. Var P : PPasswordRecord;
  718. begin
  719. P:=Getpwnam(UserName);
  720. If P<>Nil then
  721. Data:=P^
  722. else
  723. Raise EUserLookupError.CreateFmt(ENoSuchUserName,[UserName]);
  724. end;
  725. Procedure GetUserData(Uid : Integer; Var Data : TPasswordRecord);
  726. Var P : PPasswordRecord;
  727. begin
  728. P:=Getpwuid(Uid);
  729. If P<>Nil then
  730. Data:=P^
  731. else
  732. Raise EUserLookupError.CreateFmt(ENoSuchUserID,[Uid]);
  733. end;
  734. function GetUserName(UID : Integer) : String;
  735. Var
  736. UserData : TPasswordRecord;
  737. begin
  738. GetuserData(UID,UserData);
  739. Result:=strpas(UserData.pw_Name);
  740. end;
  741. function GetUserId(Const UserName : String) : Integer;
  742. Var
  743. UserData : TPasswordRecord;
  744. begin
  745. GetUserData(UserName,UserData);
  746. Result:=UserData.pw_uid;
  747. end;
  748. function GetUserGId(Const UserName : String) : Integer;
  749. Var
  750. UserData : TPasswordRecord;
  751. begin
  752. GetUserData(UserName,UserData);
  753. Result:=UserData.pw_gid;
  754. end;
  755. function GetUserDir(Const UserName : String): String;
  756. Var
  757. UserData : TPasswordRecord;
  758. begin
  759. GetUserData(UserName,UserData);
  760. Result:=strpas(UserData.pw_dir);
  761. end;
  762. function GetUserDescription(Const UserName : String): String;
  763. Var
  764. UserData : TPasswordRecord;
  765. begin
  766. GetUserData(UserName,UserData);
  767. Result:=strpas(UserData.pw_gecos);
  768. end;
  769. Procedure GetUserList(List : Tstrings);
  770. begin
  771. GetUserList(List,False);
  772. end;
  773. Procedure GetUserList(List : TStrings; WithIDs : Boolean);
  774. Var
  775. P : PPasswordRecord;
  776. begin
  777. List.Clear;
  778. setpwent;
  779. try
  780. Repeat
  781. P:=getpwent;
  782. If P<>Nil then
  783. begin
  784. If WithIDs then
  785. List.Add(Format('%d=%s',[P^.pw_uid,strpas(p^.pw_name)]))
  786. else
  787. List.Add(strpas(p^.pw_name));
  788. end;
  789. until (P=Nil);
  790. finally
  791. endpwent;
  792. end;
  793. end;
  794. { ---------------------------------------------------------------------
  795. Group Functions
  796. ---------------------------------------------------------------------}
  797. Function getgrnam(Const GroupName: String) : PGroup;
  798. begin
  799. Result:=libc.getgrnam(Pchar(GroupName));
  800. end;
  801. Procedure GetGroupData(Const GroupName : String; Var Data : TGroup); overload;
  802. Var P : PGroup;
  803. begin
  804. P:=Getgrnam(GroupName);
  805. If P<>Nil then
  806. Data:=P^
  807. else
  808. Raise EGroupLookupError.CreateFmt(ENoSuchGroupName,[GroupName]);
  809. end;
  810. Procedure GetGroupData(Gid : Integer; Var Data : TGroup); overload;
  811. Var P : PGroup;
  812. begin
  813. P:=Getgrgid(gid);
  814. If P<>Nil then
  815. Data:=P^
  816. else
  817. Raise EGroupLookupError.CreateFmt(ENoSuchGroupID,[Gid]);
  818. end;
  819. function GetGroupName(GID : Integer) : String;
  820. Var
  821. G : TGroup;
  822. begin
  823. GetGroupData(Gid,G);
  824. Result:=StrPas(G.gr_name);
  825. end;
  826. function GetGroupId(Const GroupName : String) : Integer;
  827. Var
  828. G : TGroup;
  829. begin
  830. GetGroupData(GroupName,G);
  831. Result:=G.gr_gid;
  832. end;
  833. Procedure GetGroupList(List : Tstrings);overload;
  834. begin
  835. GetGroupList(List,False);
  836. end;
  837. Procedure GetGroupList(List : TStrings; WithIDs : Boolean);overload;
  838. Var
  839. G : PGroup;
  840. begin
  841. List.Clear;
  842. setgrent;
  843. try
  844. Repeat
  845. G:=getgrent;
  846. If G<>Nil then
  847. begin
  848. If WithIDs then
  849. List.Add(Format('%d=%s',[G^.gr_gid,strpas(G^.gr_name)]))
  850. else
  851. List.Add(strpas(G^.gr_name));
  852. end;
  853. until (G=Nil);
  854. finally
  855. endgrent;
  856. end;
  857. end;
  858. Function PCharListToStrings(P : PPChar; List : TStrings) : Integer;
  859. begin
  860. List.Clear;
  861. While P^<>Nil do
  862. begin
  863. List.Add(StrPas(P^));
  864. P:=PPChar(PChar(P)+SizeOf(PChar));
  865. end;
  866. Result:=List.Count;
  867. end;
  868. Procedure GetGroupMembers(GID : Integer;List : TStrings);
  869. Var
  870. G : TGroup;
  871. begin
  872. GetGroupData(GID,G);
  873. PCharListToStrings(G.gr_mem,List);
  874. end;
  875. Procedure GetGroupMembers(Const GroupName : String;List : TStrings);
  876. Var
  877. G : TGroup;
  878. begin
  879. GetGroupData(GroupName,G);
  880. PCharListToStrings(g.gr_mem,List);
  881. end;
  882. { Shadow password functions }
  883. function getspnam(UserName : String): PPasswordFileEntry;
  884. begin
  885. result:=Libc.getspnam(Pchar(UserName));
  886. end;
  887. function sgetspent(Line : String): PPasswordFileEntry;
  888. begin
  889. Result:=libc.sgetspent(Pchar(Line));
  890. end;
  891. Procedure GetUserShadowData(Const UserName : String; Var Data : TPasswordFileEntry);
  892. Var
  893. P : PPasswordFileEntry;
  894. begin
  895. P:=getspnam(UserName);
  896. If P=Nil then
  897. If (GetUID<>0) and (GetEUID<>0) then
  898. Raise EShadowLookupError.Create(EShadowNotPermitted)
  899. else
  900. Raise EShadowLookupError.CreateFmt(ENoShadowEntry,[UserName])
  901. else
  902. Data:=P^;
  903. end;
  904. Procedure GetUserShadowData(UID : Integer; Var Data : TPasswordFileEntry);
  905. begin
  906. GetUserShadowData(GetUserName(UID),Data);
  907. end;
  908. { Extra functions }
  909. Function GetUserGroup(Const UserName : String) : String;
  910. begin
  911. GetGroupName(GetUserGid(UserName));
  912. end;
  913. end.