unixutils.pp 27 KB

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