home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume28 / freeks-1.33 / part01 next >
Text File  |  1994-07-10  |  36KB  |  1,384 lines

  1. Newsgroups: comp.sources.unix
  2. From: lytras@avalon.unizh.ch (Apostolos Lytras)
  3. Subject: v28i083: freeks-1.33 - extended login accounting, V1.33, Part01/01
  4. Message-id: <1.773910551.9561@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: lytras@avalon.unizh.ch (Apostolos Lytras)
  9. Posting-Number: Volume 28, Issue 83
  10. Archive-Name: freeks-1.33/part01
  11.  
  12.     Here's a revised version of 'freeks'.
  13.  
  14.     I have received some patches for NetBSD and BSD/386 as well as a fix
  15.     for a bug in gecos.c.
  16.  
  17.     This time even the shar and the Makefile should work correctly ;-).
  18.  
  19.     - Apostolos
  20.  
  21. # This is a shell archive.  Save it in a file, remove anything before
  22. # this line, and then unpack it by entering "sh file".  Note, it may
  23. # create directories; files and directories will be owned by you and
  24. # have default permissions.
  25. #
  26. # This archive contains:
  27. #
  28. #    ./freeks-1.33
  29. #    ./freeks-1.33/Makefile
  30. #    ./freeks-1.33/README
  31. #    ./freeks-1.33/configfile-example
  32. #    ./freeks-1.33/freeks.6
  33. #    ./freeks-1.33/freeks.c
  34. #    ./freeks-1.33/freeks.cat
  35. #    ./freeks-1.33/freeks.h
  36. #    ./freeks-1.33/gecos.c
  37. #
  38. echo c - ./freeks-1.33
  39. mkdir ./freeks-1.33 > /dev/null 2>&1
  40. echo x - ./freeks-1.33/Makefile
  41. sed 's/^X//' >./freeks-1.33/Makefile << 'END-of-./freeks-1.33/Makefile'
  42. X# Makefile for freeks 1.33
  43. X
  44. X# Configure this for your system (default is {SunOS,Ultrix} with gcc)
  45. X# 
  46. X# NOTE: if your system has far more (or far less) users than 1021, you
  47. X#       may wish to change the value for HASHTABLESIZE. That value must
  48. X#       be prime. You can change it in freeks.c, or here by adding
  49. X#       -DHASHTABLESIZE=2003 (for about 2000 users for example) to CFLAGS.
  50. X#       If you have a lot of users and you want to improve performance a bit,
  51. X#       it's probably best to test a prime number around (1.5*number_of_users)
  52. X#       which should cause less searching for free positions in the hash
  53. X#       table (the searching is linear!) when the table gets full.
  54. X#
  55. X# NOTE FOR SYSTEM V: System V doesn't log shutdowns by default. If you
  56. X#       want accurate information about system uptime then create a
  57. X#       shutdown user whose login will indicate that the system was shut 
  58. X#       down. Then define CONFIGFILE in freeks.c (or call the account
  59. X#       "shutdown") and create the configfile in the appropriate
  60. X#       place.
  61. X
  62. X# Some general Variables
  63. X#
  64. Xprefix = /usr/local
  65. Xpostfix = 6
  66. XMANPATH = ${prefix}/man/man${postfix}
  67. XCP = install -c -m
  68. XMODE1 = 755
  69. XMODE2 = 644
  70. XOBJS = freeks.o gecos.o
  71. X
  72. X# BSD/386 1.0 with gcc
  73. X#
  74. X#CC = cc
  75. X#CFLAGS = -O 
  76. X
  77. X# SunOS 4.1.3  / Ultrix 4.0 with gcc
  78. X#
  79. XCC = gcc
  80. XCFLAGS = -Wall -W -Wno-implicit -O 
  81. X
  82. X# SunOS 4.1.3 with Sun C compiler
  83. X#
  84. X#CC = cc
  85. X#CFLAGS = -O
  86. X
  87. X# Slowaris 2.3 with gcc
  88. X#
  89. X#CC = gcc
  90. X#CFLAGS = -Wall -W -O -DSYSV
  91. X
  92. X# HP/UX 9.0x.
  93. X#
  94. X# CC = cc
  95. X# CFLAGS = -Aa -O
  96. X
  97. X# Nextstep 3.x with NeXT's (g)cc
  98. X#
  99. X# CC = cc
  100. X# CFLAGS = -Wall -W -Dnextstep3 -O
  101. X
  102. X# more flags
  103. X# DEBUGFLAGS = -DDEBUG -g -ansi -pedantic -DWANTGECOS
  104. XDEBUGFLAGS = 
  105. X# LDFLAGS = -s
  106. XLDFLAGS =
  107. X
  108. X# -------- from here on you shouldn't need to change anything ---
  109. X
  110. Xall:     freeks  
  111. X
  112. Xfreeks: ${OBJS}
  113. X    ${CC} ${CFLAGS} ${DEBUGFLAGS} ${LDFLAGS} -o $@ ${OBJS}
  114. X
  115. Xfreeks.o:
  116. X    ${CC} ${CFLAGS} ${DEBUGFLAGS} -c $*.c
  117. X
  118. Xgecos.o:
  119. X     ${CC} ${CFLAGS} ${DEBUGFLAGS} -c $*.c
  120. X
  121. Xinstall: all
  122. X    ${CP} ${MODE1} freeks ${prefix}/bin; \
  123. X    ${CP} ${MODE2} freeks.6 ${MANPATH}/freeks.${postfix}
  124. X
  125. Xclean:
  126. X    rm -f freeks *~ core *.o
  127. END-of-./freeks-1.33/Makefile
  128. echo x - ./freeks-1.33/README
  129. sed 's/^X//' >./freeks-1.33/README << 'END-of-./freeks-1.33/README'
  130. XFirst of all read the manual page... 
  131. X(e.g. with 'nroff -man freeks.6 | more')
  132. X
  133. XINSTALLATION:
  134. X
  135. X1) Edit the Makefile to match your system.
  136. X2) Check if you have to change anything in 'freeks.h'
  137. X
  138. X########### NOTE : #############
  139. X
  140. XIf your system has _more_ than HASHTABLESIZE users then you _must_ set 
  141. XHASHTABLESIZE to a higher value (preferably a prime) in freeks.h, or
  142. Xyou will get an error (Hash table full) when you run freeks.
  143. X
  144. X################################
  145. X
  146. X3) 'make'
  147. X4) Test-run freeks.
  148. X5) 'make install'
  149. X6) 'make clean'
  150. X
  151. XPORTABILITY:
  152. X
  153. XThis has been run on the following systems, I say ;-):
  154. XMachine Type     Operating System        Compiler
  155. XDecsystem 5200   Ultrix 4.0              gcc 2.2.2
  156. XNextstation m68k Nextstep 3.2            cc (Next's Version of gcc 2.2.2)
  157. XSparcstation 1   SunOS 4.1.3             gcc 2.5.8
  158. XSparcClassic     SunOS 5.3 (Solaris 2.3) gcc 2.5.8
  159. XIntel 486        NetBSD 0.9B             gcc 2.4.5
  160. XIntel x86        BSD/386                 ??
  161. X
  162. XTHANKS:
  163. X
  164. Xbruce@slc.com (Bruce Schuchardt) sent me some patches to make freeks
  165. Xrun on HP/UX 9.0x with HP's cc. I've built them into the source. He said
  166. Xthat there are a couple of minor compilation warnings which could be 
  167. Xignored.
  168. X
  169. XWietse Venema for his feedback on SysV peculiarities...
  170. X
  171. XTerry Kennedy <terry@spcuna.spc.edu> and Mark Delany 
  172. X<markd@bushwire.apana.org.au> for their patches for BSD/386 and NetBSD.
  173. X
  174. XEnjoy!
  175. X- Apostolos Lytras (lytras@avalon.unizh.ch)
  176. END-of-./freeks-1.33/README
  177. echo x - ./freeks-1.33/configfile-example
  178. sed 's/^X//' >./freeks-1.33/configfile-example << 'END-of-./freeks-1.33/configfile-example'
  179. Xhalt
  180. Xarmageddon
  181. Xshutdown
  182. Xpowerdown
  183. END-of-./freeks-1.33/configfile-example
  184. echo x - ./freeks-1.33/freeks.6
  185. sed 's/^X//' >./freeks-1.33/freeks.6 << 'END-of-./freeks-1.33/freeks.6'
  186. X.TH freeks 6 "July 10, 1994" "Apostolos Lytras" "Freeks 1.33 Manual"
  187. X.SH NAME
  188. Xfreeks \-  extended login accounting
  189. X.SH SYNOPSIS
  190. Xfreeks [\-w
  191. X.I wtmp
  192. X] [\-t] [\-c
  193. X.I configfile
  194. X]
  195. X
  196. X.SH DESCRIPTION
  197. X.B Freeks
  198. Xproduces a report on system usage based on the contents of
  199. X.I wtmp
  200. Xand sorted by the actual time different users have spent on the
  201. Xsystem.
  202. XThe first few lines contain general information about
  203. Xthe system. 
  204. X
  205. X
  206. X.SH OPTIONS
  207. XThe default for
  208. X.I wtmp
  209. Xis "/usr/adm/wtmp".
  210. XYou may specify an alternate
  211. X.I wtmp
  212. Xfile on the command line.
  213. X
  214. XWith the 't' option the user statistics are modified, showing the
  215. X\'rank\', the name, the time the user was actually logged in and
  216. Xthe number of logins. 
  217. X
  218. XWith the \'c\' option you can specify a 
  219. X.I configfile 
  220. Xcontaining the names of alternative 'shutdown' users (cf. TODO), which
  221. Xis probably interesting to SysV machine owners only.
  222. X
  223. X.SH BUGS
  224. X.B Freeks
  225. Xis (almost) limited to BSD style
  226. X.I wtmp
  227. Xfiles (cf. TODO below). It does not have a lot of fancy options. 
  228. XFreeks does make some mistakes, e.g. when a reboot entry in
  229. X.I wtmp
  230. Xhappened without a shutdown before it. If the last entry happened more
  231. Xthan a day before the reboot entry, freeks presumes that the machine
  232. Xcrashed, and will use the time of the last entry before the crash as
  233. Xtime of shutdown. This may lead to marginal errors in 'uptime' and the
  234. Xlogin times of users still logged in at that time.
  235. X
  236. XAnother bug happens when time is changed in single user mode which
  237. Xmeans it doesn't get logged. Don't do that, or delete the
  238. X.I wtmp
  239. Xfile afterwards.
  240. X
  241. X.SH TODO
  242. XSystem V has changed a lot in
  243. X.I wtmp
  244. Xbut it should be possible to run the program, if you rarely shut
  245. Xyour machine down or have a dedicated 'shutdown' user that logs in
  246. Xwhen you shut down. If this user is called 'shutdown' you needn't 
  247. Xdo nothing, if his login name is something else, you can specify that in
  248. X.I configfile
  249. X(if, of course, freeks had been compiled with CONFIGFILE defined...).
  250. X
  251. X
  252. X.SH "SEE ALSO"
  253. X.BR geeks(5)
  254. X.BR geeks(6)
  255. X.BR ac(8)
  256. X.BR wtmp(5)
  257. X.BR wtmpfix(8)
  258. X.BR login(1)
  259. X.BR init(8)
  260. X
  261. X.SH FILES
  262. X.PD 0
  263. X.TP 20
  264. X.B /usr/adm/wtmp
  265. Xwtmp file
  266. X
  267. X.SH AUTHOR
  268. XCopyright (C) 1994 by Apostolos Lytras (lytras@avalon.unizh.ch).
  269. X
  270. XThanks to Dave P. Gymer (dpg@cs.nott.ac.uk) and everyone that helped
  271. Xhim write geeks(6). It has been an important inspiration and a reason
  272. Xto write this program (because it was just too slow, geeks! ;-).
  273. X
  274. XThanks also to Wietse Venema for his information on SVR4's wtmp.
  275. X
  276. XSome of the credit must also go to the University of California,
  277. XBerkeley, for their programs ac(8), last(1) and uptime(1), which
  278. Xevaluate /usr/adm/wtmp as well. These programs were inspiring as well,
  279. Xbecause they couldn't do everything real geeks needed them to.
  280. X
  281. XThis is free software; you can redistribute it and/or modify it under
  282. Xthe terms of the GNU General Public License as published by the Free
  283. XSoftware Foundation; either version 2 of the License, or (at your
  284. Xoption) any later version.
  285. X
  286. XThe GNU General Public License is not included in the original
  287. Xdistrubution of freeks. If you don't have a copy of it already, write
  288. Xto the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
  289. XUSA.
  290. X
  291. XThis program is distributed in the hope that  it  will  be useful, but
  292. XWITHOUT ANY WARRANTY; without even the implied warranty of
  293. XMERCHANTABILITY or FITNESS  FOR  A  PARTICULAR PURPOSE.   See  the
  294. XGNU  General  Public License for more details.
  295. X
  296. END-of-./freeks-1.33/freeks.6
  297. echo x - ./freeks-1.33/freeks.c
  298. sed 's/^X//' >./freeks-1.33/freeks.c << 'END-of-./freeks-1.33/freeks.c'
  299. X/********************************************************************/
  300. X/*                                                                  */
  301. X/* freeks.c - login accounting                                      */
  302. X/* Copyright (C) 1994 by Apostolos Lytras (lytras@avalon.unizh.ch)  */
  303. X/* Version 1.33, July 10, 1994                                      */
  304. X/*                                                                  */
  305. X/*            1.33  NetBSD, BSD/386 patches from Mark Delany and    */
  306. X/*                  Terry Kennedy, who also found and fixed a bug   */
  307. X/*                  in gecos.c                                      */
  308. X/*            1.32  SysV support almost in. fixed more bugs.        */
  309. X/*            1.31  time handling still not okay.                   */
  310. X/*                  finally got some SysV help from Wietse Venema   */
  311. X/*            1.30  first attempt to include SysV support           */
  312. X/*            1.22  included hints for HP/UX 9.0x with              */
  313. X/*                  CLASSIC_ID_TYPES                                */ 
  314. X/*                  suggested by bruce@slc.com (Bruce Schuchardt)   */
  315. X/*            1.21  included bugfix for J_hash suggested by         */
  316. X/*                  awick@csugrad.cs.vt.edu (Andy Wick)             */
  317. X/*                  posted to alt.sources March 30, 1994            */
  318. X/*            1.20  first edition, posted to alt.sources            */
  319. X/*                  March 29, 1994                                  */
  320. X/*                                                                  */
  321. X/*                                                                  */
  322. X/* See the manual page (freeks.6) distributed with this file, for   */
  323. X/* restriction, warranty, distribution and copyright information.   */
  324. X/*                                                                  */
  325. X/********************************************************************/
  326. X
  327. X#include "freeks.h"
  328. X
  329. X#ifdef NO_STRDUP
  330. Xchar           *
  331. Xstrdup(char *s)
  332. X{
  333. X  char           *t = (char *) malloc(strlen(s) + 1);
  334. X
  335. X  return t ? strcpy(t, s) : t;
  336. X}
  337. X#else
  338. Xextern char    *strdup();
  339. X#endif
  340. X
  341. X
  342. XUSER            userlist[HASHTABLESIZE];
  343. XTTY            *ttylist;
  344. X
  345. Xlong            s_uptime;
  346. Xlong            s_start;
  347. Xlong            s_corr = 0;
  348. Xlong            t_corr = 0;
  349. Xlong            s_stop;
  350. Xunsigned int    s_reboots = 0;
  351. Xunsigned int    s_shutdowns = 0;
  352. Xunsigned int    s_crashes = 0;
  353. Xunsigned int    s_logouts = 0;
  354. Xunsigned int    s_logins = 0;
  355. Xunsigned int    toptenmode = 0;
  356. Xlong            now = 0;
  357. Xstatic int      shutd_state = FALSE;
  358. X
  359. X#ifdef __STDC__
  360. Xvoid J_init_all(void)
  361. X#else
  362. XJ_init_all()
  363. X#endif
  364. X{ int i;
  365. X  for ( i = 0 ; i <= HASHTABLESIZE ; i++)
  366. X  {
  367. X   if (userlist[i].name != NULL)
  368. X    { 
  369. X    userlist[i].name = NULL; 
  370. X    userlist[i].current_logins = 0;
  371. X    userlist[i].max_conc_logins = 0;
  372. X    userlist[i].logins = 0;
  373. X    userlist[i].logintimebuf = 0;
  374. X    userlist[i].needs_timeset = FALSE;
  375. X    userlist[i].time = 0;
  376. X    userlist[i].total = 0;
  377. X    userlist[i].max_time = 0;
  378. X    }
  379. X  }
  380. X  ttylist = NULL;
  381. X  s_uptime = 0;
  382. X  s_start = 0;
  383. X  s_corr = 0;
  384. X  t_corr =0;
  385. X  s_stop = 0;
  386. X  s_reboots = 0;
  387. X  s_shutdowns = 0;
  388. X  s_crashes = 0;
  389. X  s_logouts = 0;
  390. X  s_logins = 0;
  391. X  shutd_state = FALSE;
  392. X  now = 0;
  393. X}
  394. X
  395. X#ifdef CONFIGFILE
  396. X
  397. XPRIVILEGED *shutdownusers;
  398. X
  399. XPRIVILEGED *config_init(filename)
  400. Xchar *filename;
  401. X{
  402. X  FILE *fp;
  403. X  PRIVILEGED *tmp = (PRIVILEGED *)NULL;
  404. X  char priv_user[UT_NAMESIZE];
  405. X
  406. X  fp =  (FILE *)fopen(filename,"r");
  407. X  if (fp == NULL) { 
  408. X       fprintf(stderr,"Warning: Could not open config file (%s)\n", 
  409. X               filename ); return((PRIVILEGED *)NULL);
  410. X  }
  411. X  while (fscanf(fp,"%s",&priv_user) != EOF) {
  412. X    priv_user[UT_NAMESIZE] = '\0';
  413. X    if ((tmp = (PRIVILEGED *)malloc(sizeof(PRIVILEGED))) == (PRIVILEGED *)NULL)
  414. X      fprintf(stderr,("Fatal: malloc failed in config\n"));
  415. X    else {
  416. X       tmp->next = shutdownusers;
  417. X       tmp->user = (char *) strdup (priv_user);
  418. X       shutdownusers = tmp;
  419. X    }
  420. X  }
  421. X  if (fclose(fp) == 0)
  422. X  {
  423. X    return(tmp);
  424. X  }
  425. X  else
  426. X  {
  427. X    fprintf(stderr, "Fatal: couldn't close %s\n", filename);
  428. X    exit(1);
  429. X  }
  430. X}
  431. X
  432. Xint privilege_check(username,list)
  433. Xchar *username;
  434. XPRIVILEGED *list;
  435. X{
  436. X  PRIVILEGED *T;
  437. X
  438. X  if (list != NULL) {
  439. X   for (T=list ; T != NULL ; T = T->next) {
  440. X#ifdef DEBUG
  441. X    fprintf(stderr,"Debug: privileges test %s for %s\n",list->user, username);
  442. X#endif /* DEBUG */
  443. X    if (!strncmp(T->user,username,UT_NAMESIZE))  return TRUE;
  444. X   }
  445. X  };
  446. X  return FALSE;
  447. X}
  448. X
  449. X#endif /* CONFIGFILE */
  450. X
  451. Xstatic int
  452. XSedgeHash(arg)
  453. Xchar           *arg;
  454. X{
  455. X  int             h;
  456. X
  457. X  for (h = 0; *arg != '\0'; arg++)
  458. X  {
  459. X    h = (64 * h + *arg) % HASHTABLESIZE;
  460. X  }
  461. X  return h;
  462. X}
  463. X
  464. Xstatic int
  465. XJ_hash(arg)
  466. Xchar           *arg;
  467. X{
  468. X  int             Index, i, count=0;
  469. X
  470. X  Index = (int) SedgeHash(arg);
  471. X
  472. X  if (userlist[Index].name == NULL)
  473. X  {
  474. X    return Index;
  475. X  }
  476. X  for (i = Index; userlist[i].name != NULL; i++)
  477. X  {
  478. X    count++;
  479. X    if (i == HASHTABLESIZE)
  480. X    {
  481. X      i = 0;
  482. X      if (userlist[i].name == NULL)
  483. X    return i;
  484. X    }
  485. X    else if (count == HASHTABLESIZE)
  486. X    {
  487. X      fprintf(stderr, "Fatal: Hash table is full.\n");
  488. X      exit(2);
  489. X    };
  490. X    if (strcmp(userlist[i].name, arg) == 0)
  491. X      return i;
  492. X  }
  493. X  return i;
  494. X}
  495. X
  496. Xint
  497. Xucompare(i, j)
  498. XUSER           *i, *j;
  499. X{
  500. X  if (i->time > j->time)
  501. X    return -1;
  502. X  else if (i->time < j->time)
  503. X    return 1;
  504. X  return 0;
  505. X}
  506. X
  507. Xstatic TTY     *
  508. XJ_gettty(thetty)
  509. Xchar           *thetty;
  510. X{
  511. X  register TTY   *cur, *T;
  512. X
  513. X  if (ttylist != NULL)
  514. X  {
  515. X    for (T = ttylist; T != NULL; T = T->next)
  516. X    {
  517. X      if (strncmp(thetty, T->tty, UT_LINESIZE) == 0)
  518. X      {
  519. X    return (T);
  520. X      };
  521. X    }
  522. X  };
  523. X  if ((cur = (TTY *) malloc(sizeof(TTY))) == NULL)
  524. X  {
  525. X    fprintf(stderr, "Fatal: malloc failed !\n");
  526. X    exit(1);
  527. X  }
  528. X  cur->next = ttylist;
  529. X  cur->tty = (char *) strdup(thetty);
  530. X  ttylist = cur;
  531. X  return (cur);
  532. X}
  533. X
  534. Xstatic int
  535. XJ_countlogins(uhash)
  536. Xint             uhash;
  537. X{
  538. X  register TTY   *curt;
  539. X  int             count = 0;
  540. X
  541. X  if (ttylist != NULL)
  542. X  {
  543. X    for (curt = ttylist; curt != NULL; curt = curt->next)
  544. X    {
  545. X      if ((curt->used) && (uhash == curt->user_hash))
  546. X      {
  547. X    count++;
  548. X      }
  549. X      else
  550. X    continue;
  551. X    }
  552. X  };
  553. X  return count;
  554. X}
  555. X
  556. Xstatic void
  557. XJ_logout(logouttime, cur)
  558. Xlong            logouttime;
  559. XTTY            *cur;
  560. X{
  561. X  long            stayed;
  562. X  long            definite;
  563. X  int             current;
  564. X
  565. X  if (cur->used == 0)
  566. X  {
  567. X    return;
  568. X  }
  569. X  else
  570. X  {
  571. X    cur->used = 0;
  572. X    if ((logouttime != now) || (now == 0))
  573. X      /* avoid counting users still logged in */ 
  574. X    { 
  575. X      s_logouts++;
  576. X    }
  577. X    current = J_countlogins(cur->user_hash);
  578. X    userlist[cur->user_hash].current_logins = current;
  579. X    stayed = logouttime - cur->time_in;
  580. X    if (stayed < 0) 
  581. X    {
  582. X      fprintf(stderr,"Error: user %s has a negative session time.\n",
  583. X                      userlist[cur->user_hash].name);
  584. X    };
  585. X    if (stayed > userlist[cur->user_hash].max_time)
  586. X    {
  587. X      userlist[cur->user_hash].max_time = stayed;
  588. X    };
  589. X    userlist[cur->user_hash].total += stayed;
  590. X    if (current == 0)
  591. X    {
  592. X      definite = logouttime - userlist[cur->user_hash].logintimebuf;
  593. X      userlist[cur->user_hash].time += definite;
  594. X    };
  595. X  }
  596. X}
  597. X
  598. Xstatic void
  599. XJ_login(inname, logintime, tty)
  600. Xchar           *inname, *tty;
  601. Xlong            logintime;
  602. X{
  603. X  int             uhash;
  604. X  register TTY   *thistty;
  605. X
  606. X  
  607. X  uhash = J_hash(inname);
  608. X  if (userlist[uhash].name == NULL)
  609. X  {
  610. X    userlist[uhash].name = (char *) strdup(inname);
  611. X  }
  612. X  else
  613. X  {
  614. X    while (strncmp(userlist[uhash].name, inname, sizeof(inname)) != 0)
  615. X    {
  616. X      fprintf(stderr, "Fatal: could not avoid hash collision at %d: %s %s\n",
  617. X          uhash, inname, userlist[uhash].name);
  618. X      exit(2);
  619. X    }
  620. X  }
  621. X  thistty = J_gettty(tty);
  622. X  if (thistty->used)
  623. X  { /* the tty is already in use */
  624. X    if (strcmp(userlist[thistty->user_hash].name,userlist[uhash].name) == 0)
  625. X    { /* the newly logged in user is already logged in */
  626. X      return;
  627. X    }
  628. X    else
  629. X    {
  630. X      J_logout(logintime, thistty);
  631. X        
  632. X#ifdef DEBUG
  633. X      fprintf(stderr, "Debug: %s did not log out. Replaced by %s...\n",
  634. X          userlist[thistty->user_hash].name,
  635. X          userlist[uhash].name);
  636. X#endif 
  637. X    }
  638. X  };
  639. X  s_logins++;
  640. X  userlist[uhash].logins++;
  641. X  if (userlist[uhash].current_logins < 0)
  642. X  {
  643. X    userlist[uhash].current_logins = 1;
  644. X  }
  645. X  else
  646. X  {
  647. X    userlist[uhash].current_logins++;
  648. X  }
  649. X  if (userlist[uhash].current_logins == 1)
  650. X  {
  651. X    userlist[uhash].logintimebuf = logintime;
  652. X  };
  653. X  if (userlist[uhash].max_conc_logins < userlist[uhash].current_logins)
  654. X  {
  655. X    userlist[uhash].max_conc_logins = userlist[uhash].current_logins;
  656. X  };
  657. X  thistty->time_in = logintime;
  658. X  thistty->user_hash = uhash;
  659. X  thistty->used = 1;
  660. X}
  661. X
  662. X#if __STDC__
  663. Xstatic void
  664. XJ_timeprep(void)
  665. X#else
  666. Xstatic void
  667. XJ_timeprep()
  668. X#endif
  669. X{
  670. X  register TTY   *cur;
  671. X
  672. X  if (ttylist != NULL)
  673. X  {
  674. X    for (cur = ttylist; cur != NULL; cur = cur->next)
  675. X    {
  676. X      if (cur->used == 1)
  677. X      {
  678. X    userlist[cur->user_hash].needs_timeset = TRUE;
  679. X      };
  680. X    }
  681. X  };
  682. X}
  683. X
  684. Xstatic void
  685. XJ_timeset(oldtime, newtime)
  686. Xlong            oldtime, newtime;
  687. X{
  688. X  long            diff;
  689. X  register TTY   *cur;
  690. X
  691. X  diff = newtime - oldtime;
  692. X  if (ttylist != NULL)
  693. X  {
  694. X    for (cur = ttylist; cur != NULL; cur = cur->next)
  695. X    {
  696. X      if (cur->used == 1)
  697. X      {
  698. X    cur->time_in += diff;
  699. X    if (userlist[cur->user_hash].needs_timeset == TRUE)
  700. X    {
  701. X      userlist[cur->user_hash].logintimebuf += diff;
  702. X      userlist[cur->user_hash].needs_timeset = FALSE;
  703. X    };
  704. X      };
  705. X    }
  706. X  };
  707. X  s_corr += diff;
  708. X  t_corr += diff;
  709. X#ifdef DEBUG
  710. X  fprintf(stderr, "Debug: date got set. Difference is: %ld\n", diff);
  711. X#endif
  712. X}
  713. X
  714. Xvoid
  715. XJ_cleanup(endtime)
  716. Xlong            endtime;
  717. X{
  718. X  register TTY   *cur;
  719. X
  720. X  if (ttylist != NULL)
  721. X  {
  722. X    for (cur = ttylist; cur != NULL; cur = cur->next)
  723. X    {
  724. X      if (cur->used)
  725. X      {
  726. X    J_logout(endtime, cur);
  727. X      }
  728. X      else
  729. X    continue;
  730. X    }
  731. X  };
  732. X}
  733. X
  734. Xstatic void
  735. XJ_reboot(sometime, reboottime, shutdowntime)
  736. Xlong            sometime, reboottime, shutdowntime;
  737. X{
  738. X  long            thetime, timediff;
  739. X
  740. X  if (shutd_state == TRUE)
  741. X  {
  742. X    timediff = reboottime - shutdowntime;
  743. X    s_corr += timediff;
  744. X    if (timediff < 0)
  745. X    {
  746. X      thetime = reboottime;
  747. X    }
  748. X    else
  749. X    {
  750. X      thetime = shutdowntime;
  751. X    }
  752. X    s_reboots++;
  753. X  }
  754. X  else
  755. X  {
  756. X    if (((reboottime - sometime) > 86400) || (sometime > shutdowntime))
  757. X    {
  758. X      fprintf(stderr, "Warning: You have had a serious crash, I suppose\n");
  759. X      thetime = sometime;
  760. X      timediff = reboottime - sometime;
  761. X      s_corr += timediff;
  762. X      s_crashes++;
  763. X    }
  764. X    else
  765. X    {
  766. X      thetime = reboottime;
  767. X      s_shutdowns++;
  768. X      s_reboots++;
  769. X    }
  770. X  }
  771. X  J_cleanup(thetime);
  772. X}
  773. X
  774. Xstatic void
  775. XJ_print(list)
  776. XUSER           *list;
  777. X{
  778. X  int             i,rank=0;
  779. X  long            localv;
  780. X
  781. X  localv = now - (s_start + t_corr);
  782. X  if (localv < 0) {
  783. X    fprintf(stderr,"Warning: negative time covered!\n");
  784. X  };
  785. X
  786. X  s_uptime = now - (s_start + s_corr);
  787. X  if (s_uptime < 0) {
  788. X    fprintf(stderr,"Warning: negative uptime!\n");
  789. X  };
  790. X
  791. X  printf("--- System statistics---\n");
  792. X  printf("Start at:     %s", ctime((time_t *)&s_start));
  793. X  printf("End at:       %s", ctime((time_t *)&now));
  794. X  printf("Time covered:");
  795. X  timefmt(localv);
  796. X  printf("\n");
  797. X  printf("Uptime:      ");
  798. X  timefmt(s_uptime);
  799. X  printf("  (%.1f %% of total time)\n",
  800. X     (((float) s_uptime / (float) localv) * 100.0));
  801. X  printf("Booted:       %d times", s_reboots);
  802. X  printf("  (shut down %d times)\n", s_shutdowns);
  803. X  printf("Crashed:      %d times\n", s_crashes);
  804. X  printf("Logins:       %d\n", s_logins);
  805. X  printf("Logouts:      %d\n", s_logouts);
  806. X  printf("\n--- User statistics---\n");
  807. X  qsort((char *) ((USER *) list), (size_t) HASHTABLESIZE, (size_t) sizeof(struct anUser), ucompare);
  808. X if(toptenmode == 1) {
  809. X  for (i = 0; i < HASHTABLESIZE; i++)
  810. X  {
  811. X    if (list[i].name != NULL)
  812. X    {
  813. X      rank++;
  814. X      printf("%4d %-22s",
  815. X             rank,
  816. X             (char *)J_gecos_parse(list[i].name));
  817. X      timefmt(list[i].time);
  818. X      printf(" (%6d logins)\n",list[i].logins);
  819. X    };
  820. X  } 
  821. X } 
  822. X else {
  823. X#ifdef    __bsdi__    /* Actually an SPC-ism */
  824. X   printf("user          logins ttys       real      total    longest    average   %%uptime\n");
  825. X#else
  826. X   printf("user      logins ttys       real      total    longest    average   %%uptime\n");
  827. X#endif
  828. X
  829. X  for (i = 0; i < HASHTABLESIZE; i++)
  830. X  {
  831. X    if (list[i].name != NULL)
  832. X    {
  833. X#ifdef    __bsdi__    /* Actually an SPC-ism */
  834. X      printf("%-13s %6d %4d", list[i].name, list[i].logins,
  835. X#else
  836. X      printf("%-9s %6d %4d", list[i].name, list[i].logins,
  837. X#endif
  838. X         list[i].max_conc_logins);
  839. X      timefmt(list[i].time);
  840. X      timefmt(list[i].total);
  841. X#ifdef DEBUG
  842. X      if (list[i].time > list[i].total) 
  843. X      {
  844. X        fprintf(stderr,"Debug: total time greater than real time: %s\n",
  845. X                       list[i].name);
  846. X      }
  847. X#endif
  848. X      timefmt(list[i].max_time);
  849. X      timefmt((list[i].total / list[i].logins));
  850. X      printf("   %7.2f\n", (((float) list[i].time / (float) s_uptime) * 100));
  851. X    };
  852. X  }
  853. X }
  854. X}
  855. X
  856. Xvoid
  857. XJ_read_wtmp(fp, def)
  858. XFILE           *fp;
  859. Xint             def;
  860. X{
  861. X  struct utmp     logbuf, *uptr;
  862. X  int             first = TRUE;
  863. X  long            timebuf = 0;
  864. X  char            curuser[UT_NAMESIZE+1];
  865. X  char            curline[UT_LINESIZE+1];
  866. X  long            tob = 0, dot = 0;
  867. X  
  868. X  while (fread((char *) &logbuf, 1, sizeof(logbuf), fp) == sizeof(logbuf))
  869. X  {
  870. X    s_stop = logbuf.ut_time;
  871. X    if (first == TRUE)
  872. X    {
  873. X      first = FALSE;
  874. X      tob = s_stop;
  875. X      s_start = s_stop;
  876. X    };
  877. X    if ( s_stop < s_start ) 
  878. X    {
  879. X      fprintf(stderr,"Error: time scope vulneration... resetting\n");
  880. X      J_init_all();
  881. X    };
  882. X#ifndef SYSV
  883. X    if (!strncmp("reboot", logbuf.ut_name, 6))
  884. X#else
  885. X    if (logbuf.ut_type == BOOT_TIME)
  886. X#endif
  887. X    {
  888. X      J_reboot(tob, s_stop, dot);
  889. X      shutd_state = FALSE;
  890. X      continue;
  891. X    }
  892. X    else if (!strncmp("shutdown", logbuf.ut_name, UT_NAMESIZE)
  893. X#ifndef SYSV
  894. X         || logbuf.ut_line[0] == '~' 
  895. X#endif
  896. X             || shutd_state == TRUE 
  897. X#ifdef CONFIGFILE
  898. X             || (privilege_check(logbuf.ut_name,shutdownusers) == TRUE) 
  899. X#endif
  900. X            )
  901. X    {
  902. X      tob = s_stop;
  903. X      if (shutd_state == FALSE)
  904. X      {
  905. X    shutd_state = TRUE;
  906. X    s_shutdowns++;
  907. X    dot = logbuf.ut_time;
  908. X    continue;
  909. X      }
  910. X      else
  911. X    continue;
  912. X    }
  913. X#ifndef SYSV
  914. X    else if (logbuf.ut_line[0] == '|' && !logbuf.ut_line[1])
  915. X#else
  916. X    else if (logbuf.ut_type == OLD_TIME)
  917. X#endif
  918. X  {
  919. X      timebuf = logbuf.ut_time;
  920. X      J_timeprep();
  921. X      tob = s_stop;
  922. X      continue;
  923. X    }
  924. X#ifndef SYSV
  925. X    else if (logbuf.ut_line[0] == '{' && !logbuf.ut_line[1])
  926. X#else
  927. X    else if (logbuf.ut_type == NEW_TIME)
  928. X#endif
  929. X    {
  930. X      tob = s_stop;
  931. X      if (timebuf != 0)
  932. X      {
  933. X#ifdef DEBUG
  934. X        fprintf(stderr,"Debug: timesetting %ld\n",(logbuf.ut_time - timebuf));
  935. X#endif
  936. X    J_timeset(timebuf, logbuf.ut_time);
  937. X    continue;
  938. X      }
  939. X      else
  940. X    continue;
  941. X    }
  942. X    else if ((!strncmp("ftp", logbuf.ut_line, 3)) ||
  943. X         (!strncmp("uucp", logbuf.ut_line, 4)))
  944. X    {
  945. X      shutd_state = FALSE;
  946. X      tob = s_stop;
  947. X      continue;
  948. X    }
  949. X#ifndef SYSV
  950. X    else if (isalnum(logbuf.ut_name[0]) != 0)
  951. X#else
  952. X    else if (logbuf.ut_type == USER_PROCESS)
  953. X#endif
  954. X    {
  955. X      shutd_state = FALSE;
  956. X      uptr = &logbuf;
  957. X      curuser[UT_NAMESIZE] = '\0';
  958. X      curline[UT_LINESIZE] = '\0';
  959. X
  960. X      strncpy(curuser, uptr->ut_name, UT_NAMESIZE);
  961. X      strncpy(curline, uptr->ut_line, UT_LINESIZE);
  962. X      J_login(curuser, uptr->ut_time, curline);
  963. X      tob = s_stop;
  964. X      continue;
  965. X    }
  966. X#ifndef SYSV
  967. X    else if (logbuf.ut_line != NULL)
  968. X#else
  969. X    else if (logbuf.ut_type == DEAD_PROCESS)
  970. X#endif
  971. X    {
  972. X      curline[UT_LINESIZE] = '\0';
  973. X      strncpy(curline, logbuf.ut_line, UT_LINESIZE);
  974. X      J_logout(logbuf.ut_time, J_gettty(curline));
  975. X      tob = s_stop;
  976. X      continue;
  977. X    }
  978. X    else
  979. X    {
  980. X#ifndef SYSV
  981. X      fprintf(stderr, "Warning: Strange entry at %s\n%s %s\n",
  982. X              ctime((time_t *)&logbuf.ut_time), 
  983. X              logbuf.ut_name, logbuf.ut_line);
  984. X#endif
  985. X      tob = s_stop;
  986. X      continue;
  987. X    }
  988. X  }
  989. X  if (def == 0)
  990. X  {
  991. X    now = s_stop;
  992. X  }
  993. X  else
  994. X  {
  995. X    now = (long) time((time_t *) 0);
  996. X  }
  997. X  J_cleanup(now);
  998. X  J_print(userlist);
  999. X}
  1000. X
  1001. Xvoid
  1002. Xmain(argc, argv)
  1003. Xint             argc;
  1004. Xchar          **argv;
  1005. X{
  1006. X  FILE           *fd;
  1007. X#ifdef WTMP_FILE
  1008. X  char           *wtmp = WTMP_FILE;
  1009. X#else
  1010. X#ifdef _PATH_WTMP
  1011. X  char           *wtmp = _PATH_WTMP;
  1012. X#else
  1013. X  char           *wtmp = "/usr/adm/wtmp";
  1014. X#endif
  1015. X#endif
  1016. X#ifdef CONFIGFILE
  1017. X  char           *configfile = CONFIGFILE;
  1018. X#endif
  1019. X  int             def = 1;
  1020. X
  1021. X  while (--argc > 0 && **++argv == '-')
  1022. X    switch (*++*argv)
  1023. X    {
  1024. X    case 'w':
  1025. X      if (--argc > 0)
  1026. X      {
  1027. X    wtmp = *++argv;
  1028. X    def--;
  1029. X      }
  1030. X      continue;
  1031. X    case 't':
  1032. X      toptenmode++;
  1033. X      continue;
  1034. X#ifdef CONFIGFILE
  1035. X    case 'c':
  1036. X      if (--argc > 0)
  1037. X      {
  1038. X        configfile = *++argv;
  1039. X      }
  1040. X      continue;
  1041. X#endif
  1042. X    }
  1043. X#ifdef CONFIGFILE 
  1044. X    shutdownusers = config_init(configfile);
  1045. X#endif 
  1046. X
  1047. X  fd = (FILE *) fopen(wtmp, "r");
  1048. X  if (fd == NULL)
  1049. X  {
  1050. X    fprintf(stderr, "Fatal: %s ... no such file\n", wtmp);
  1051. X    exit(1);
  1052. X  }
  1053. X  J_read_wtmp(fd, def);
  1054. X  if (fclose(fd) == 0)
  1055. X  {
  1056. X    exit(0);
  1057. X  }
  1058. X  else
  1059. X  {
  1060. X    fprintf(stderr, "Fatal: couldn't close %s\n", wtmp);
  1061. X    exit(1);
  1062. X  }
  1063. X}
  1064. END-of-./freeks-1.33/freeks.c
  1065. echo x - ./freeks-1.33/freeks.cat
  1066. sed 's/^X//' >./freeks-1.33/freeks.cat << 'END-of-./freeks-1.33/freeks.cat'
  1067. X
  1068. X
  1069. X
  1070. Xfreeks(6)              Freeks 1.33 Manual               freeks(6)
  1071. X
  1072. X
  1073. X
  1074. XNAME
  1075. X     freeks -  extended login accounting
  1076. X
  1077. XSYNOPSIS
  1078. X     freeks [-w wtmp ] [-t] [-c configfile ]
  1079. X
  1080. X
  1081. XDESCRIPTION
  1082. X     Freeks produces a report on system usage based on  the  con-
  1083. X     tents of
  1084. X     wtmp and sorted by the actual  time  different  users  have
  1085. X     spent  on  the  system.  The first few lines contain general
  1086. X     information about the system.
  1087. X
  1088. X
  1089. X
  1090. XOPTIONS
  1091. X     The default for
  1092. X     wtmp is "/usr/adm/wtmp".  You may specify an alternate
  1093. X     wtmp file on the command line.
  1094. X
  1095. X     With the 't' option the user statistics are modified,  show-
  1096. X     ing  the  'rank',  the  name, the time the user was actually
  1097. X     logged in and the number of logins.
  1098. X
  1099. X     With the 'c' option you can specify a
  1100. X     configfile containing the names of  alternative  'shutdown'
  1101. X     users  (cf.  TODO),  which  is  probably interesting to SysV
  1102. X     machine owners only.
  1103. X
  1104. X
  1105. XBUGS
  1106. X     Freeks is (almost) limited to BSD style
  1107. X     wtmp files (cf. TODO below). It does  not  have  a  lot  of
  1108. X     fancy  options.  Freeks does make some mistakes, e.g. when a
  1109. X     reboot entry in
  1110. X     wtmp happened without a shutdown before  it.  If  the  last
  1111. X     entry  happened  more  than  a  day before the reboot entry,
  1112. X     freeks presumes that the machine crashed, and will  use  the
  1113. X     time of the last entry before the crash as time of shutdown.
  1114. X     This may lead to marginal errors in 'uptime' and  the  login
  1115. X     times of users still logged in at that time.
  1116. X
  1117. X     Another bug happens when time is changed in single user mode
  1118. X     which  means it doesn't get logged. Don't do that, or delete
  1119. X     the wtmp file afterwards.
  1120. X
  1121. X
  1122. X
  1123. X
  1124. X
  1125. X
  1126. XApostolos Lytras   Last change: July 10, 1994                   1
  1127. X
  1128. X
  1129. X
  1130. X
  1131. X
  1132. X
  1133. Xfreeks(6)              Freeks 1.33 Manual               freeks(6)
  1134. X
  1135. X
  1136. X
  1137. XTODO
  1138. X     System V has changed a lot in
  1139. X     wtmp but it should be possible to run the program,  if  you
  1140. X     rarely shut your machine down or have a dedicated 'shutdown'
  1141. X     user that logs in when you shut down. If this user is called
  1142. X     'shutdown'  you  needn't  do  nothing,  if his login name is
  1143. X     something else, you can specify that in
  1144. X     configfile (if, of course, freeks had  been  compiled  with
  1145. X     CONFIGFILE defined...).
  1146. X
  1147. X
  1148. X
  1149. XSEE ALSO
  1150. X     geeks(5) geeks(6) ac(8) wtmp(5) wtmpfix(8) login(1) init(8)
  1151. X
  1152. X
  1153. XFILES
  1154. X     /usr/adm/wtmp       wtmp file
  1155. X
  1156. XAUTHOR
  1157. X     Copyright     (C)     1994     by      Apostolos      Lytras
  1158. X     (lytras@avalon.unizh.ch).
  1159. X
  1160. X     Thanks to Dave P.  Gymer  (dpg@cs.nott.ac.uk)  and  everyone
  1161. X     that  helped  him  write  geeks(6). It has been an important
  1162. X     inspiration and a reason to write this program  (because  it
  1163. X     was just too slow, geeks! ;-).
  1164. X
  1165. X     Thanks also to Wietse Venema for his information  on  SVR4's
  1166. X     wtmp.
  1167. X
  1168. X     Some of the credit must also go to the University  of  Cali-
  1169. X     fornia,  Berkeley,  for  their  programs  ac(8), last(1) and
  1170. X     uptime(1), which evaluate /usr/adm/wtmp as well. These  pro-
  1171. X     grams  were  inspiring  as  well,  because  they couldn't do
  1172. X     everything real geeks needed them to.
  1173. X
  1174. X     This is free software; you can redistribute it and/or modify
  1175. X     it under the terms of the GNU General Public License as pub-
  1176. X     lished by the Free Software Foundation; either version 2  of
  1177. X     the License, or (at your option) any later version.
  1178. X
  1179. X     The GNU General Public License is not included in the origi-
  1180. X     nal  distrubution  of freeks. If you don't have a copy of it
  1181. X     already, write to the Free  Software  Foundation,  675  Mass
  1182. X     Ave, Cambridge, MA 02139, USA.
  1183. X
  1184. X     This program is distributed in the hope that  it   will   be
  1185. X     useful,  but  WITHOUT ANY WARRANTY; without even the implied
  1186. X     warranty of MERCHANTABILITY or FITNESS  FOR   A   PARTICULAR
  1187. X     PURPOSE.    See   the  GNU  General  Public License for more
  1188. X     details.
  1189. X
  1190. X
  1191. X
  1192. XApostolos Lytras   Last change: July 10, 1994                   2
  1193. X
  1194. X
  1195. END-of-./freeks-1.33/freeks.cat
  1196. echo x - ./freeks-1.33/freeks.h
  1197. sed 's/^X//' >./freeks-1.33/freeks.h << 'END-of-./freeks-1.33/freeks.h'
  1198. X/* --- start of configurable section --- */
  1199. X/*
  1200. X * HASHTABLESIZE must be prime, such as 61,113,251,509,1021 To save memory
  1201. X * choose a value close to the number of users on your system.
  1202. X *
  1203. X * Note:
  1204. X * This is not a full-fledged hashing library, just some code stolen from
  1205. X * "Algorithms in C" by Robert Sedgewick which has been refined to avoid hash
  1206. X * collisions. The algorithm which does this is very simple and probably not
  1207. X * worth a lot in more complex programs. (It does not handle removal from the
  1208. X * list, because that won't happen in this application.)
  1209. X */
  1210. X#ifndef HASHTABLESIZE
  1211. X#define HASHTABLESIZE 1021
  1212. X#endif
  1213. X
  1214. X/* NO_STRDUP:
  1215. X * if your system doesn't have the strdup routine, then uncomment the
  1216. X * definition below.  
  1217. X */
  1218. X/* #define NO_STRDUP */
  1219. X
  1220. X/* WANTGECOS:
  1221. X * If you want to use GECOS entries ("real names") in 'freeks -t' output
  1222. X * define this
  1223. X */
  1224. X#ifndef WANTGECOS
  1225. X#define WANTGECOS
  1226. X#endif
  1227. X
  1228. X/* DEBUG:
  1229. X * If you want to get more debugging output on standard error, then
  1230. X * uncomment this here or look at the debugflags in the Makefile
  1231. X */
  1232. X/* #define DEBUG */
  1233. X
  1234. X/* CONFIGFILE */
  1235. X/* System V users might want to create a configfile containing the   */
  1236. X/* names of additional usernames that create a shutdown, like `halt' */
  1237. X/* or `powerdown'. Each username must appear separately on a line in */
  1238. X/* the file                                                          */
  1239. X/* #define CONFIGFILE "/usr/local/lib/freeks/config" */
  1240. X
  1241. X/* --- you shouldn't need to change much below this --- */
  1242. X
  1243. X#if defined(__hpux)
  1244. X#ifndef SYSV
  1245. X#define _CLASSIC_ID_TYPES
  1246. X#endif
  1247. X#endif
  1248. X
  1249. X#include <stdlib.h>
  1250. X#include <stdio.h>
  1251. X#include <time.h>
  1252. X#include <sys/file.h>
  1253. X#include <ctype.h>
  1254. X#ifndef SYSV
  1255. X#include <utmp.h>
  1256. X#include <strings.h>
  1257. X#else
  1258. X#include <utmpx.h>
  1259. X#include <string.h>
  1260. X#ifndef ut_name
  1261. X#define ut_name ut_user
  1262. X#endif
  1263. X#endif
  1264. X
  1265. X#ifdef WANTGECOS
  1266. X#include <pwd.h>
  1267. X/***************************************************************/
  1268. X/* MAX_GECOS_LEN is the maximum length of a gecos entry in the */
  1269. X/* password database for use in topten ( option '-t' ) mode    */
  1270. X/* Default: 20                                                 */
  1271. X/***************************************************************/
  1272. X#ifdef    __bsdi__
  1273. X#define MAX_GECOS_LEN 32
  1274. X#else
  1275. X#define MAX_GECOS_LEN 20
  1276. X#endif
  1277. X#define minimum(a,b)  (a < b) ? a : b 
  1278. X#endif /* WANTGECOS */
  1279. X
  1280. Xstruct utmp utmp_dummy;
  1281. X#ifndef    UT_NAMESIZE
  1282. X#define UT_NAMESIZE sizeof (utmp_dummy.ut_name)
  1283. X#endif
  1284. X#ifndef    UT_LINESIZE
  1285. X#define UT_LINESIZE sizeof (utmp_dummy.ut_line)
  1286. X#endif
  1287. X
  1288. X#define TRUE 1
  1289. X#define FALSE 0
  1290. X
  1291. X#define timefmt(time) \
  1292. Xprintf(" %4ld:%02ld:%02ld", (time) / 3600, ((time) / 60) % 60, (time) % 60)
  1293. X
  1294. X#ifndef NO_STRDUP
  1295. X#if (defined(__ultrix__) || defined(nextstep3))
  1296. X#define NO_STRDUP
  1297. X#endif /* ultrix or nextstep */
  1298. X#endif
  1299. X
  1300. Xtypedef struct anUser
  1301. X{
  1302. X  char           *name;
  1303. X  int             current_logins;
  1304. X  int             max_conc_logins;
  1305. X  int             logins;
  1306. X  long            logintimebuf;
  1307. X  int             needs_timeset;
  1308. X  long            time;
  1309. X  long            total;
  1310. X  long            max_time;
  1311. X}               USER;
  1312. X
  1313. Xtypedef struct aTty
  1314. X{
  1315. X  char           *tty;
  1316. X  int             used;
  1317. X  int             user_hash;
  1318. X  long            time_in;
  1319. X  struct aTty    *next;
  1320. X}               TTY;
  1321. X
  1322. X#ifdef CONFIGFILE
  1323. Xtypedef struct priv_list {
  1324. X  char             *user;
  1325. X  struct priv_list *next;
  1326. X}               PRIVILEGED ;
  1327. X#endif
  1328. X
  1329. END-of-./freeks-1.33/freeks.h
  1330. echo x - ./freeks-1.33/gecos.c
  1331. sed 's/^X//' >./freeks-1.33/gecos.c << 'END-of-./freeks-1.33/gecos.c'
  1332. X/* gecos.c                                                             */
  1333. X/* Apostolos Lytras. June 1994                                         */
  1334. X/* This little program gets a user name on its command line for which  */
  1335. X/* it searches /etc/passwd's gecos entry and strips everything but the */
  1336. X/* first of its (comma delimited) fields...                            */
  1337. X/* BUGS: maybe the first field is not the user's real name... ?!       */
  1338. X
  1339. X#include "freeks.h"
  1340. X
  1341. X#ifndef WANTGECOS
  1342. X
  1343. Xchar *J_gecos_parse(string)
  1344. Xchar *string;
  1345. X{ 
  1346. X   return string;  /* dummy function */
  1347. X}
  1348. X
  1349. X#else
  1350. X
  1351. Xchar *J_gecos_parse(namen)
  1352. Xchar *namen;
  1353. X{
  1354. X  char out[MAX_GECOS_LEN], *output, *input;
  1355. X  int len, i;
  1356. X  struct passwd *dastruct;
  1357. X
  1358. X  dastruct = (struct passwd *) malloc (sizeof(struct passwd *));
  1359. X  if ((dastruct = getpwnam(namen)) == (struct passwd *)NULL )
  1360. X  { 
  1361. X#ifdef DEBUG
  1362. X    fprintf(stderr,"Debug: user %s is not in password file.\n",namen); 
  1363. X#endif
  1364. X    return namen;
  1365. X  };
  1366. X  if ((input = (char *)strdup(dastruct->pw_gecos)) == (char *)NULL)
  1367. X  {
  1368. X    fprintf(stderr,"Fatal: allocation for GECOS failed.\n");
  1369. X    exit(-2);
  1370. X  };
  1371. X/* This starts at 0, so we want -2 (0-based, less 1 for terminator) */
  1372. X  len = minimum((MAX_GECOS_LEN - 2),strlen(input));
  1373. X  for ( i = 0; (i <= len) && (input[i] != ',') ; i++, out[i] = '\0')
  1374. X  {
  1375. X    out[i] = input[i];
  1376. X  }
  1377. X  output = (char *)strdup(out);
  1378. X  return output;
  1379. X}
  1380. X
  1381. X#endif
  1382. END-of-./freeks-1.33/gecos.c
  1383. exit
  1384.