utmpx.c 22 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082
  1. /*++
  2. Copyright (c) 2015 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. utmpx.c
  9. Abstract:
  10. This module implements support for the user accounting database, which
  11. tracks user logins and other activity.
  12. Author:
  13. Evan Green 30-Jan-2015
  14. Environment:
  15. User Mode C Library
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "libcp.h"
  21. #include <assert.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <sys/param.h>
  27. #include <sys/stat.h>
  28. #include <utmp.h>
  29. #include <utmpx.h>
  30. //
  31. // ---------------------------------------------------------------- Definitions
  32. //
  33. //
  34. // ------------------------------------------------------ Data Type Definitions
  35. //
  36. //
  37. // ----------------------------------------------- Internal Function Prototypes
  38. //
  39. INT
  40. ClpOpenUserAccountingDatabase (
  41. PSTR DatabaseFile
  42. );
  43. INT
  44. ClpReadWriteUserAccountingEntry (
  45. struct utmpx *Entry,
  46. INT Type
  47. );
  48. //
  49. // -------------------------------------------------------------------- Globals
  50. //
  51. //
  52. // Store the file pointer to the user accounting database.
  53. //
  54. char *ClUserAccountingFilePath = NULL;
  55. int ClUserAccountingFile = -1;
  56. struct utmpx *ClUserAccountingEntry = NULL;
  57. //
  58. // ------------------------------------------------------------------ Functions
  59. //
  60. LIBC_API
  61. void
  62. setutent (
  63. void
  64. )
  65. /*++
  66. Routine Description:
  67. This routine resets the current pointer into the user database back to the
  68. beginning. This function is neither thread-safe nor reentrant. This
  69. function is equivalent to setutxent, and new applications should use that
  70. function.
  71. Arguments:
  72. None.
  73. Return Value:
  74. None.
  75. --*/
  76. {
  77. setutxent();
  78. return;
  79. }
  80. LIBC_API
  81. void
  82. endutent (
  83. void
  84. )
  85. /*++
  86. Routine Description:
  87. This routine closes the user accounting database. This function is neither
  88. thread-safe nor reentrant. This function is equivalent to endutxent, and
  89. new applications should use that function.
  90. Arguments:
  91. None.
  92. Return Value:
  93. None.
  94. --*/
  95. {
  96. endutxent();
  97. return;
  98. }
  99. LIBC_API
  100. struct utmp *
  101. getutent (
  102. void
  103. )
  104. /*++
  105. Routine Description:
  106. This routine returns the next entry in the user accounting database. If
  107. the database is not already open, it will open it. If it reaches the end
  108. of the database, it fails. This function is neither thread-safe nor
  109. reentrant. Since utmp and utmpx structures are the same, this function is
  110. equivalent to getutxent, and new applications should use that function.
  111. Arguments:
  112. None.
  113. Return Value:
  114. Returns a pointer to a copy of the user accounting information on success.
  115. NULL on failure, and errno may be set on error.
  116. --*/
  117. {
  118. return (struct utmp *)getutxent();
  119. }
  120. LIBC_API
  121. struct utmp *
  122. getutid (
  123. const struct utmp *Id
  124. )
  125. /*++
  126. Routine Description:
  127. This routine searches forward from the current point in the user accounting
  128. database. If the ut_type value of the supplied utmp structure is
  129. BOOT_TIME, OLD_TIME, or NEW_TIME, then it stops when it finds an entry with
  130. a matching ut_type value. If the ut_type is INIT_PROCESS, USER_PROCESS, or
  131. DEAD_PROCESS, it stops when it finds an entry whose type is one of these
  132. four and whose ut_id matches the one in the given structure. If the end of
  133. the database is reached without a match, the routine shall fail. This
  134. function is neither thread-safe nor reentrant. Since utmp and utmpx
  135. structures are the same, this function is equivalent to getutxent, and new
  136. applications should use that function.
  137. Arguments:
  138. Id - Supplies a pointer to a structure containing the type and possibly
  139. user ID to match on.
  140. Return Value:
  141. Returns a pointer to a copy of the user accounting information on success.
  142. NULL on failure, and errno may be set on error.
  143. --*/
  144. {
  145. return (struct utmp *)getutxid((struct utmpx *)Id);
  146. }
  147. LIBC_API
  148. struct utmp *
  149. getutline (
  150. const struct utmp *Line
  151. )
  152. /*++
  153. Routine Description:
  154. This routine searches forward from the current point in the user accounting
  155. database, looking for an entry of type LOGIN_PROCESS or USER_PROCESS which
  156. also matches the ut_line value in the given structure. If the end of the
  157. database is reached without a match, the routine shall fail. This function
  158. is neither thread-safe nor reentrant.
  159. This function may cache data, so to search for multiple occurrences it is
  160. important to zero out the static data (the return value from the previous
  161. result). Otherwise, the same result may be returned infinitely.
  162. Since utmp and utmpx structures are the same, this function is equivalent
  163. to getutxline, and new applications should use that function.
  164. Arguments:
  165. Line - Supplies a pointer to a structure containing the line to match.
  166. Return Value:
  167. Returns a pointer to a copy of the user accounting information on success.
  168. NULL on failure, and errno may be set on error.
  169. --*/
  170. {
  171. return (struct utmp *)getutxline((struct utmpx *)Line);
  172. }
  173. LIBC_API
  174. struct utmp *
  175. pututline (
  176. const struct utmp *Value
  177. )
  178. /*++
  179. Routine Description:
  180. This routine writes out the structure to the user accounting database. It
  181. shall use getutxid to search for a record that satisfies the request. If
  182. the search succeeds, then the entry will be replaced. Otherwise, a new
  183. entry is made at the end of the user accounting database. The caller must
  184. have sufficient privileges. The implicit read done by this function if it
  185. finds it is not already at the correct place shall not modify the static
  186. structure passed as a return of the other utx functions (so the application
  187. may use that space to write back a modified value). This function is
  188. neither thread-safe nor reentrant. Since utmp and utmpx structures are the
  189. same, this function is equivalent to getutxline, and new applications
  190. should use that function.
  191. Arguments:
  192. Value - Supplies a pointer to a structure containing the new data.
  193. Return Value:
  194. Returns a pointer to a copy of the written user accounting information on
  195. success.
  196. NULL on failure, and errno may be set on error.
  197. --*/
  198. {
  199. return (struct utmp *)pututxline((struct utmpx *)Value);
  200. }
  201. LIBC_API
  202. int
  203. utmpname (
  204. const char *FilePath
  205. )
  206. /*++
  207. Routine Description:
  208. This routine updates the file path that utmp* functions open and access.
  209. This must be called before those routines open the file. This routine does
  210. not check to ensure the file exists. This routine is neither thread-safe
  211. nor reentrant. This routine is equivalent to utmpxname, and new
  212. applications should call that function.
  213. Arguments:
  214. FilePath - Supplies a pointer to the new file path. A copy of this string
  215. will be made.
  216. Return Value:
  217. 0 on success.
  218. -1 on failure, and errno will be set to contain more information.
  219. --*/
  220. {
  221. return utmpxname(FilePath);
  222. }
  223. LIBC_API
  224. void
  225. logwtmp (
  226. const char *Terminal,
  227. const char *User,
  228. const char *Host
  229. )
  230. /*++
  231. Routine Description:
  232. This routine creates a new utmp entry with the given terminal line, user
  233. name, host name, the current process ID, and current time. It appends the
  234. new record using updwtmp to the wtmp file.
  235. Arguments:
  236. Terminal - Supplies an optional pointer to the terminal.
  237. User - Supplies an optional pointer to the user.
  238. Host - Supplies a pointer to the host.
  239. Return Value:
  240. None.
  241. --*/
  242. {
  243. struct utmp Record;
  244. memset(&Record, 0, sizeof(Record));
  245. Record.ut_pid = getpid();
  246. if ((User != NULL) && (User[0] != '\0')) {
  247. Record.ut_type = USER_PROCESS;
  248. strncpy(Record.ut_user, User, sizeof(Record.ut_user));
  249. } else {
  250. Record.ut_type = DEAD_PROCESS;
  251. }
  252. if (Terminal != NULL) {
  253. strncpy(Record.ut_line, Terminal, sizeof(Record.ut_line));
  254. }
  255. strncpy(Record.ut_host, Host, sizeof(Record.ut_host));
  256. gettimeofday(&(Record.ut_tv), NULL);
  257. updwtmp(_PATH_WTMP, (struct utmp *)&Record);
  258. return;
  259. }
  260. LIBC_API
  261. void
  262. updwtmp (
  263. const char *FileName,
  264. const struct utmp *Record
  265. )
  266. /*++
  267. Routine Description:
  268. This routine adds an entry into the wtmp user database.
  269. Arguments:
  270. FileName - Supplies a pointer to path of the wtmp file to open. Set this to
  271. WTMP_FILE by default.
  272. Record - Supplies a pointer to the record to append.
  273. Return Value:
  274. None.
  275. --*/
  276. {
  277. updwtmpx(FileName, (struct utmpx *)Record);
  278. return;
  279. }
  280. LIBC_API
  281. void
  282. setutxent (
  283. void
  284. )
  285. /*++
  286. Routine Description:
  287. This routine resets the current pointer into the user database back to the
  288. beginning. This function is neither thread-safe nor reentrant.
  289. Arguments:
  290. None.
  291. Return Value:
  292. None.
  293. --*/
  294. {
  295. //
  296. // Allocate the static space if necessary.
  297. //
  298. if (ClUserAccountingEntry == NULL) {
  299. ClUserAccountingEntry = malloc(sizeof(struct utmpx));
  300. if (ClUserAccountingEntry == NULL) {
  301. errno = ENOMEM;
  302. return;
  303. }
  304. }
  305. ClpOpenUserAccountingDatabase(ClUserAccountingFilePath);
  306. return;
  307. }
  308. LIBC_API
  309. void
  310. endutxent (
  311. void
  312. )
  313. /*++
  314. Routine Description:
  315. This routine closes the user accounting database. This function is neither
  316. thread-safe nor reentrant.
  317. Arguments:
  318. None.
  319. Return Value:
  320. None.
  321. --*/
  322. {
  323. if (ClUserAccountingFile >= 0) {
  324. close(ClUserAccountingFile);
  325. ClUserAccountingFile = -1;
  326. }
  327. return;
  328. }
  329. LIBC_API
  330. struct utmpx *
  331. getutxent (
  332. void
  333. )
  334. /*++
  335. Routine Description:
  336. This routine returns the next entry in the user accounting database. If
  337. the database is not already open, it will open it. If it reaches the end
  338. of the database, it fails. This function is neither thread-safe nor
  339. reentrant.
  340. Arguments:
  341. None.
  342. Return Value:
  343. Returns a pointer to a copy of the user accounting information on success.
  344. NULL on failure, and errno may be set on error.
  345. --*/
  346. {
  347. INT Result;
  348. Result = ClpReadWriteUserAccountingEntry(NULL, F_RDLCK);
  349. if (Result < 0) {
  350. return NULL;
  351. }
  352. return ClUserAccountingEntry;
  353. }
  354. LIBC_API
  355. struct utmpx *
  356. getutxid (
  357. const struct utmpx *Id
  358. )
  359. /*++
  360. Routine Description:
  361. This routine searches forward from the current point in the user accounting
  362. database. If the ut_type value of the supplied utmpx structure is
  363. BOOT_TIME, OLD_TIME, or NEW_TIME, then it stops when it finds an entry with
  364. a matching ut_type value. If the ut_type is INIT_PROCESS, USER_PROCESS, or
  365. DEAD_PROCESS, it stops when it finds an entry whose type is one of these
  366. four and whose ut_id matches the one in the given structure. If the end of
  367. the database is reached without a match, the routine shall fail. This
  368. function is neither thread-safe nor reentrant.
  369. Arguments:
  370. Id - Supplies a pointer to a structure containing the type and possibly
  371. user ID to match on.
  372. Return Value:
  373. Returns a pointer to a copy of the user accounting information on success.
  374. NULL on failure, and errno may be set on error.
  375. --*/
  376. {
  377. BOOL Match;
  378. struct utmpx Value;
  379. Match = FALSE;
  380. while (TRUE) {
  381. if (ClpReadWriteUserAccountingEntry(&Value, F_RDLCK) < 0) {
  382. return NULL;
  383. }
  384. //
  385. // If it's any of the one-time entries (RUN_LVL, BOOT_TIME, NEW_TIME,
  386. // or OLD_TIME) just match on the type.
  387. //
  388. if ((Id->ut_type != EMPTY) && (Id->ut_type <= OLD_TIME)) {
  389. if (Id->ut_type == Value.ut_type) {
  390. Match = TRUE;
  391. break;
  392. }
  393. //
  394. // If it's a process entry (INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS,
  395. // or DEAD_PROCESS) then find one that matches the ID.
  396. //
  397. } else if (Id->ut_type <= DEAD_PROCESS) {
  398. if (strncmp(Id->ut_id, Value.ut_id, sizeof(Value.ut_id)) == 0) {
  399. Match = TRUE;
  400. break;
  401. }
  402. }
  403. }
  404. if (Match == FALSE) {
  405. return NULL;
  406. }
  407. memcpy(ClUserAccountingEntry, &Value, sizeof(struct utmpx));
  408. return ClUserAccountingEntry;
  409. }
  410. LIBC_API
  411. struct utmpx *
  412. getutxline (
  413. const struct utmpx *Line
  414. )
  415. /*++
  416. Routine Description:
  417. This routine searches forward from the current point in the user accounting
  418. database, looking for an entry of type LOGIN_PROCESS or USER_PROCESS which
  419. also matches the ut_line value in the given structure. If the end of the
  420. database is reached without a match, the routine shall fail. This function
  421. is neither thread-safe nor reentrant.
  422. This function may cache data, so to search for multiple occurrences it is
  423. important to zero out the static data (the return value from the previous
  424. result). Otherwise, the same result may be returned infinitely.
  425. Arguments:
  426. Line - Supplies a pointer to a structure containing the line to match.
  427. Return Value:
  428. Returns a pointer to a copy of the user accounting information on success.
  429. NULL on failure, and errno may be set on error.
  430. --*/
  431. {
  432. struct utmpx Value;
  433. while (TRUE) {
  434. if (ClpReadWriteUserAccountingEntry(&Value, F_RDLCK) < 0) {
  435. return NULL;
  436. }
  437. if ((Value.ut_type == USER_PROCESS) ||
  438. (Value.ut_type == LOGIN_PROCESS)) {
  439. if (strncmp(Value.ut_line, Line->ut_line, sizeof(Value.ut_line)) ==
  440. 0) {
  441. goto getutxlineEnd;
  442. }
  443. }
  444. }
  445. getutxlineEnd:
  446. memcpy(ClUserAccountingEntry, &Value, sizeof(struct utmpx));
  447. return ClUserAccountingEntry;
  448. }
  449. LIBC_API
  450. struct utmpx *
  451. getutxuser (
  452. const struct utmpx *User
  453. )
  454. /*++
  455. Routine Description:
  456. This routine searches forward from the current point in the user accounting
  457. database, looking for an entry of type USER_PROCESS which also matches the
  458. ut_user value in the given structure. If the end of the database is reached
  459. without a match, the routine shall fail. This function is neither
  460. thread-safe nor reentrant.
  461. This function may cache data, so to search for multiple occurrences it is
  462. important to zero out the static data (the return value from the previous
  463. result). Otherwise, the same result may be returned infinitely.
  464. Arguments:
  465. User - Supplies a pointer to a structure containing the userto match.
  466. Return Value:
  467. Returns a pointer to a copy of the user accounting information on success.
  468. NULL on failure, and errno may be set on error.
  469. --*/
  470. {
  471. struct utmpx Value;
  472. while (TRUE) {
  473. if (ClpReadWriteUserAccountingEntry(&Value, F_RDLCK) < 0) {
  474. return NULL;
  475. }
  476. if (Value.ut_type == LOGIN_PROCESS) {
  477. if (strncmp(Value.ut_user, User->ut_user, sizeof(Value.ut_user)) ==
  478. 0) {
  479. goto getutxuserEnd;
  480. }
  481. }
  482. }
  483. getutxuserEnd:
  484. memcpy(ClUserAccountingEntry, &Value, sizeof(struct utmpx));
  485. return ClUserAccountingEntry;
  486. }
  487. LIBC_API
  488. struct utmpx *
  489. pututxline (
  490. const struct utmpx *Value
  491. )
  492. /*++
  493. Routine Description:
  494. This routine writes out the structure to the user accounting database. It
  495. shall use getutxid to search for a record that satisfies the request. If
  496. the search succeeds, then the entry will be replaced. Otherwise, a new
  497. entry is made at the end of the user accounting database. The caller must
  498. have sufficient privileges. The implicit read done by this function if it
  499. finds it is not already at the correct place shall not modify the static
  500. structure passed as a return of the other utx functions (so the application
  501. may use that space to write back a modified value). This function is
  502. neither thread-safe nor reentrant.
  503. Arguments:
  504. Value - Supplies a pointer to a structure containing the new data.
  505. Return Value:
  506. Returns a pointer to a copy of the written user accounting information on
  507. success.
  508. NULL on failure, and errno may be set on error.
  509. --*/
  510. {
  511. struct utmpx Copy;
  512. struct utmpx *Found;
  513. INT Result;
  514. //
  515. // Copy the passed in value in case it is the static storage.
  516. //
  517. memcpy(&Copy, Value, sizeof(struct utmpx));
  518. //
  519. // Find the entry.
  520. //
  521. Found = getutxid(&Copy);
  522. if (Found != NULL) {
  523. lseek(ClUserAccountingFile, -(off_t)sizeof(struct utmpx), SEEK_CUR);
  524. } else {
  525. lseek(ClUserAccountingFile, 0, SEEK_END);
  526. }
  527. Result = ClpReadWriteUserAccountingEntry(&Copy, F_WRLCK);
  528. if (Result < 0) {
  529. return NULL;
  530. }
  531. memcpy(ClUserAccountingEntry, &Copy, sizeof(struct utmpx));
  532. return (struct utmpx *)Value;
  533. }
  534. LIBC_API
  535. int
  536. utmpxname (
  537. const char *FilePath
  538. )
  539. /*++
  540. Routine Description:
  541. This routine updates the file path that utmpx* functions open and access.
  542. This must be called before those routines open the file. This routine does
  543. not check to ensure the file exists. This routine is neither thread-safe
  544. nor reentrant.
  545. Arguments:
  546. FilePath - Supplies a pointer to the new file path. A copy of this string
  547. will be made.
  548. Return Value:
  549. 0 on success.
  550. -1 on failure, and errno will be set to contain more information.
  551. --*/
  552. {
  553. if (ClUserAccountingFilePath != NULL) {
  554. free(ClUserAccountingFilePath);
  555. ClUserAccountingFilePath = NULL;
  556. }
  557. if (FilePath == NULL) {
  558. return 0;
  559. }
  560. ClUserAccountingFilePath = strdup(FilePath);
  561. if (ClUserAccountingFilePath != NULL) {
  562. return 0;
  563. }
  564. return -1;
  565. }
  566. LIBC_API
  567. void
  568. updwtmpx (
  569. const char *FileName,
  570. const struct utmpx *Record
  571. )
  572. /*++
  573. Routine Description:
  574. This routine adds an entry into the wtmp user database.
  575. Arguments:
  576. FileName - Supplies a pointer to path of the wtmp file to open. Set this to
  577. WTMP_FILE by default.
  578. Record - Supplies a pointer to the record to append.
  579. Return Value:
  580. None.
  581. --*/
  582. {
  583. int Descriptor;
  584. ssize_t Written;
  585. Descriptor = open(FileName, O_WRONLY | O_APPEND, 0);
  586. if (Descriptor < 0) {
  587. return;
  588. }
  589. do {
  590. Written = write(Descriptor, Record, sizeof(struct utmpx));
  591. } while ((Written <= 0) && (errno == EINTR));
  592. close(Descriptor);
  593. return;
  594. }
  595. LIBC_API
  596. void
  597. getutmpx (
  598. const struct utmp *ValueToConvert,
  599. struct utmpx *ConvertedValue
  600. )
  601. /*++
  602. Routine Description:
  603. This routine converts a utmp structure into a utmpx structure. Since the
  604. structures are exactly the same, this is just a straight copy.
  605. Arguments:
  606. ValueToConvert - Supplies a pointer to the utmp structure to convert.
  607. ConvertedValue - Supplies a pointer where the converted utmpx strucutre
  608. will be returned.
  609. Return Value:
  610. None.
  611. --*/
  612. {
  613. assert(sizeof(struct utmp) == sizeof(struct utmpx));
  614. memcpy(ConvertedValue, ValueToConvert, sizeof(struct utmpx));
  615. return;
  616. }
  617. LIBC_API
  618. void
  619. getutmp (
  620. const struct utmpx *ValueToConvert,
  621. struct utmp *ConvertedValue
  622. )
  623. /*++
  624. Routine Description:
  625. This routine converts a utmpx structure into a utmp structure. Since the
  626. structures are exactly the same, this is just a straight copy.
  627. Arguments:
  628. ValueToConvert - Supplies a pointer to the utmpx structure to convert.
  629. ConvertedValue - Supplies a pointer where the converted utmp strucutre
  630. will be returned.
  631. Return Value:
  632. None.
  633. --*/
  634. {
  635. assert(sizeof(struct utmp) == sizeof(struct utmpx));
  636. memcpy(ConvertedValue, ValueToConvert, sizeof(struct utmp));
  637. return;
  638. }
  639. //
  640. // --------------------------------------------------------- Internal Functions
  641. //
  642. INT
  643. ClpOpenUserAccountingDatabase (
  644. PSTR DatabaseFile
  645. )
  646. /*++
  647. Routine Description:
  648. This routine opens the user accounting database file.
  649. Arguments:
  650. DatabaseFile - Supplies an optional pointer to a string containing the
  651. path to open.
  652. Return Value:
  653. 0 on success.
  654. -1 on failure, and errno is set to contain more information.
  655. --*/
  656. {
  657. if (DatabaseFile == NULL) {
  658. DatabaseFile = UTMPX_FILE;
  659. }
  660. if (ClUserAccountingFile >= 0) {
  661. endutxent();
  662. }
  663. assert(ClUserAccountingFile == -1);
  664. ClUserAccountingFile = open(DatabaseFile, O_RDWR);
  665. if (ClUserAccountingFile < 0) {
  666. ClUserAccountingFile = open(DatabaseFile, O_RDONLY);
  667. }
  668. if (ClUserAccountingFile < 0) {
  669. return -1;
  670. }
  671. return 0;
  672. }
  673. INT
  674. ClpReadWriteUserAccountingEntry (
  675. struct utmpx *Entry,
  676. INT Type
  677. )
  678. /*++
  679. Routine Description:
  680. This routine reads from or writes to a user accounting database. It uses
  681. voluntary file locking to achieve synchronization.
  682. Arguments:
  683. Entry - Supplies a pointer to the entry to read or write.
  684. Type - Supplies the file locking operation to perform. Valid values are
  685. F_WRLCK or F_RDLCK.
  686. Return Value:
  687. 0 on success.
  688. -1 on failure, and errno is set to contain more information.
  689. --*/
  690. {
  691. ssize_t BytesDone;
  692. struct flock Lock;
  693. off_t Offset;
  694. if (Entry == NULL) {
  695. Entry = ClUserAccountingEntry;
  696. }
  697. //
  698. // Save the previous offset in case it has to be restored due to a partial
  699. // read or write.
  700. //
  701. Offset = lseek(ClUserAccountingFile, 0, SEEK_CUR);
  702. //
  703. // Lock the region of interest in the file.
  704. //
  705. Lock.l_start = Offset;
  706. Lock.l_len = sizeof(struct utmpx);
  707. Lock.l_pid = 0;
  708. Lock.l_type = Type;
  709. Lock.l_whence = SEEK_SET;
  710. if (fcntl(ClUserAccountingFile, F_SETLKW, &Lock) != 0) {
  711. return -1;
  712. }
  713. do {
  714. if (Type == F_WRLCK) {
  715. BytesDone = write(ClUserAccountingFile,
  716. Entry,
  717. sizeof(struct utmpx));
  718. } else {
  719. assert(Type == F_RDLCK);
  720. BytesDone = read(ClUserAccountingFile, Entry, sizeof(struct utmpx));
  721. }
  722. } while ((BytesDone < 0) && (errno == EINTR));
  723. //
  724. // Unlock the file.
  725. //
  726. Lock.l_type = F_UNLCK;
  727. fcntl(ClUserAccountingFile, F_SETLK, &Lock);
  728. if (BytesDone != sizeof(struct utmpx)) {
  729. lseek(ClUserAccountingFile, Offset, SEEK_SET);
  730. return -1;
  731. }
  732. return 0;
  733. }