home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume28
/
freeks
/
part01
next >
Wrap
Text File
|
1994-07-02
|
37KB
|
1,435 lines
Newsgroups: comp.sources.unix
From: lytras@avalon.unizh.ch (Apostolos Lytras)
Subject: v28i080: freeks - a who-is-logged-on report similar to "geeks", V1.32, Part01/01
Message-id: <1.773199264.16584@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: lytras@avalon.unizh.ch (Apostolos Lytras)
Posting-Number: Volume 28, Issue 80
Archive-Name: freeks/part01
here is a clone for 'geeks' I have written. It is significantly
faster than geeks but doesn't have as many fancy options.
From the 'man' page:
DESCRIPTION
Freeks produces a report on system usage based on the con-
tents of wtmp and sorted by the actual time different users
have spent on the system. The format of the output is
almost similar to geeks(6). The first lines are different,
they contain general information about the system. In the
'User statistics' section the last field is different also,
containing the percentage of total uptime the user spent
logged in to the system.
This new version has some SVR4 support built into it, but I couldn't
test that enough, so I'd be happy to hear from you, if you have SVR4
and notice a bug...
Enjoy
- Apostolos
#! /bin/sh
# This is a shell archive. Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file". Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
# freeks-1.32/Makefile
# freeks-1.32/README
# freeks-1.32/configfile-example
# freeks-1.32/freeks.6
# freeks-1.32/freeks.c
# freeks-1.32/freeks.cat
# freeks-1.32/freeks.h
# freeks-1.32/gecos.c
#
echo x - freeks-1.32/Makefile
sed 's/^X//' >freeks-1.32/Makefile << 'END-of-freeks-1.32/Makefile'
X# Makefile for freeks 1.32
X
X# Configure this for your system (default is {SunOS,Ultrix} with gcc)
X#
X# NOTE: if your system has far more (or far less) users than 1021, you
X# may wish to change the value for HASHTABLESIZE. That value must
X# be prime. You can change it in freeks.c, or here by adding
X# -DHASHTABLESIZE=2003 (for about 2000 users for example) to CFLAGS.
X# If you have a lot of users and you want to improve performance a bit,
X# it's probably best to test a prime number around (1.5*number_of_users)
X# which should cause less searching for free positions in the hash
X# table (the searching is linear!) when the table gets full.
X#
X# NOTE FOR SYSTEM V: System V doesn't log shutdowns by default. If you
X# want accurate information about system uptime then create a
X# shutdown user whose login will indicate that the system was shut
X# down. Then define CONFIGFILE in freeks.c (or call the account
X# "shutdown") and create the configfile in the appropriate
X# place.
X
X# Some general Variables
X#
Xprefix = /usr/local
Xpostfix = 6
XMANPATH = ${prefix}/man/man${postfix}
XCP = install -c -m
XMODE1 = 755
XMODE2 = 644
XOBJS = freeks.o gecos.o
X
X# SunOS 4.1.3 / Ultrix 4.0 with gcc
X#
XCC = gcc
XCFLAGS = -Wall -W -Wno-implicit -O
X
X# SunOS 4.1.3 with Sun C compiler
X#
X#CC = cc
X#CFLAGS = -O
X
X# Slowaris 2.3 with gcc
X#
X#CC = gcc
X#CFLAGS = -Wall -W -O -DSYSV
X
X# HP/UX 9.0x.
X#
X# CC = cc
X# CFLAGS = -Aa -O
X
X# Nextstep 3.x with NeXT's (g)cc
X#
X# CC = cc
X# CFLAGS = -Wall -W -Dnextstep3 -O
X
X# more flags
X# DEBUGFLAGS = -DDEBUG -g -ansi -pedantic -DWANTGECOS
XDEBUGFLAGS =
X# LDFLAGS = -s
XLDFLAGS =
X
X# -------- from here on you shouldn't need to change anything ---
X
Xall: freeks
X
Xfreeks: ${OBJS}
X ${CC} ${CFLAGS} ${DEBUGFLAGS} ${LDFLAGS} -o $@ ${OBJS}
X
Xfreeks.o:
X ${CC} ${CFLAGS} ${DEBUGFLAGS} -c $*.c
X
Xgecos.o:
X ${CC} ${CFLAGS} ${DEBUGFLAGS} -c $*.c
X
Xinstall: all
X ${CP} ${MODE1} ${BINARY} ${prefix}/bin; \
X ${CP} ${MODE2} freeks.6 ${MANPATH}/freeks.${postfix}
X
Xclean:
X rm -f freeks *~ core *.o
END-of-freeks-1.32/Makefile
echo x - freeks-1.32/README
sed 's/^X//' >freeks-1.32/README << 'END-of-freeks-1.32/README'
XFirst of all read the manual page...
X(e.g. with 'nroff -man freeks.6 | more')
X
XINSTALLATION:
X
X1) Edit the Makefile to match your system.
X2) Check if you have to change anything in 'freeks.h'
X3) 'make'
X4) Test-run freeks.
X5) 'make install'
X6) 'make clean'
X
XPORTABILITY:
X
XI've tested this on the following systems:
XMachine Type Operating System Compiler
XDecsystem 5200 Ultrix 4.0 gcc 2.2.2
XNextstation m68k Nextstep 3.2 cc (Next's Version of gcc 2.2.2)
XSparcstation 1 SunOS 4.1.3 gcc 2.5.8
XSparcClassic SunOS 5.3 (Solaris 2.3) gcc 2.5.8
X
XTHANKS:
X
Xbruce@slc.com (Bruce Schuchardt) sent me some patches to make freeks
Xrun on HP/UX 9.0x with HP's cc. I've built them into the source. He said
Xthat there are a couple of minor compilation warnings which could be
Xignored.
X
XWietse Venema for his feedback on SysV peculiarities...
X
XEnjoy!
X- Apostolos Lytras (lytras@avalon.unizh.ch)
END-of-freeks-1.32/README
echo x - freeks-1.32/configfile-example
sed 's/^X//' >freeks-1.32/configfile-example << 'END-of-freeks-1.32/configfile-example'
Xhalt
Xarmageddon
Xshutdown
Xpowerdown
END-of-freeks-1.32/configfile-example
echo x - freeks-1.32/freeks.6
sed 's/^X//' >freeks-1.32/freeks.6 << 'END-of-freeks-1.32/freeks.6'
X.TH freeks 6 "June 24, 1994" "Apostolos Lytras" "Freeks 1.32 Geeking Manual"
X.SH NAME
Xfreeks \- fast 'geeks style' login accounting
X.SH SYNOPSIS
Xfreeks [\-w
X.I wtmp
X] [\-t] [\-c
X.I configfile
X]
X
X.SH DESCRIPTION
X.B Freeks
Xis a
X.B fast
Xand
X.B reduced
Xversion of
X.B geeks(6).
XThe default for
X.I wtmp
Xis "/usr/adm/wtmp".
X
X.B Freeks
Xproduces a report on system usage based on the contents of
X.I wtmp
Xand sorted by the actual time different users have spent on the
Xsystem. The format of the output is almost similar to
X.B geeks(6).
XThe first lines are different, they contain general information about
Xthe system. In the 'User statistics' section the last field is
Xdifferent also, containing the percentage of total uptime the user
Xspent logged in to the system.
X
X
X.SH OPTIONS
XYou may specify an alternate
X.I wtmp
Xfile on the command line.
X
XWith the 't' option the user statistics are modified, showing the
X\'geek rank\', the name, the time the user was actually logged in and
Xthe number of logins.
X
XWith the \'c\' option you can specify a
X.I configfile
Xcontaining the names of alternative 'shutdown' users (cf. TODO), which
Xis probably interesting to SysV machine owners only.
X
X.SH BUGS
X.B Freeks
Xis (almost) limited to BSD style
X.I wtmp
Xfiles (cf. TODO below). It does not have a lot of fancy options. It
Xdoes not include a server similar to
X.B geeksd(6).
XFreeks does make some mistakes, e.g. when a reboot entry in
X.I wtmp
Xhappened without a shutdown before it. If the last entry happened more
Xthan a day before the reboot entry, freeks presumes that the machine
Xcrashed, and will use the time of the last entry before the crash as
Xtime of shutdown. This may lead to marginal errors in 'uptime' and the
Xlogin times of users still logged in at that time.
X
XAnother bug happens when time is changed in single user mode which
Xmeans it doesn't get logged. Don't do that, or delete the
X.I wtmp
Xfile afterwards.
X
X.SH TODO
XSystem V has changed a lot in
X.I wtmp
Xbut it should be possible to run the program, if you rarely shut
Xyour machine down or have a dedicated 'shutdown' user that logs in
Xwhen you shut down. If this user is called 'shutdown' you needn't
Xdo nothing, if his login name is something else, you can specify that in
X.I configfile
X(if, of course, freeks had been compiled with CONFIGFILE defined...).
X
X
X.SH "SEE ALSO"
X.BR geeks(5)
X.BR geeks(6)
X.BR ac(8)
X.BR wtmp(5)
X.BR wtmpfix(8)
X.BR login(1)
X.BR init(8)
X
X.SH FILES
X.PD 0
X.TP 20
X.B /usr/adm/wtmp
Xwtmp file
X
X.SH AUTHOR
XCopyright (C) 1994 by Apostolos Lytras (lytras@avalon.unizh.ch).
X
XThanks to Dave P. Gymer (dpg@cs.nott.ac.uk) and everyone that helped
Xhim write geeks(6). It has been an important inspiration and a reason
Xto write this program (because it was just too slow, geeks! ;-).
X
XThanks also to Wietse Venema for his information on SVR4's wtmp.
X
XSome of the credit must also go to the University of California,
XBerkeley, for their programs ac(8), last(1) and uptime(1), which
Xevaluate /usr/adm/wtmp as well. These programs were inspiring as well,
Xbecause they couldn't do everything real geeks needed them to.
X
XThis is free software; you can redistribute it and/or modify it under
Xthe terms of the GNU General Public License as published by the Free
XSoftware Foundation; either version 2 of the License, or (at your
Xoption) any later version.
X
XThe GNU General Public License is not included in the original
Xdistrubution of freeks. If you don't have a copy of it already, write
Xto the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
XUSA.
X
XThis program is distributed in the hope that it will be useful, but
XWITHOUT ANY WARRANTY; without even the implied warranty of
XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
XGNU General Public License for more details.
X
END-of-freeks-1.32/freeks.6
echo x - freeks-1.32/freeks.c
sed 's/^X//' >freeks-1.32/freeks.c << 'END-of-freeks-1.32/freeks.c'
X/********************************************************************/
X/* */
X/* freeks.c - login accounting */
X/* Copyright (C) 1994 by Apostolos Lytras (lytras@avalon.unizh.ch) */
X/* Version 1.32, June 24, 1994 */
X/* */
X/* 1.32 SysV support almost in. fixed more bugs. */
X/* 1.31 time handling still not okay. */
X/* finally got some SysV help from Wietse Venema */
X/* 1.30 first attempt to include SysV support */
X/* 1.22 included hints for HP/UX 9.0x with */
X/* CLASSIC_ID_TYPES */
X/* suggested by bruce@slc.com (Bruce Schuchardt) */
X/* 1.21 included bugfix for J_hash suggested by */
X/* awick@csugrad.cs.vt.edu (Andy Wick) */
X/* posted to alt.sources March 30, 1994 */
X/* 1.20 first edition, posted to alt.sources */
X/* March 29, 1994 */
X/* */
X/* */
X/* See the manual page (freeks.6) distributed with this file, for */
X/* restriction and warranty information. */
X/* */
X/********************************************************************/
X
X#include "freeks.h"
X
X#ifdef NO_STRDUP
Xchar *
Xstrdup(char *s)
X{
X char *t = (char *) malloc(strlen(s) + 1);
X
X return t ? strcpy(t, s) : t;
X}
X#else
Xextern char *strdup();
X#endif
X
X
XUSER userlist[HASHTABLESIZE];
XTTY *ttylist;
X
Xlong s_uptime;
Xlong s_start;
Xlong s_corr = 0;
Xlong t_corr = 0;
Xlong s_stop;
Xunsigned int s_reboots = 0;
Xunsigned int s_shutdowns = 0;
Xunsigned int s_crashes = 0;
Xunsigned int s_logouts = 0;
Xunsigned int s_logins = 0;
Xunsigned int toptenmode = 0;
Xlong now = 0;
Xstatic int shutd_state = FALSE;
X
X#ifdef __STDC__
Xvoid J_init_all(void)
X#else
XJ_init_all()
X#endif
X{ int i;
X for ( i = 0 ; i <= HASHTABLESIZE ; i++)
X {
X if (userlist[i].name != NULL)
X {
X userlist[i].name = NULL;
X userlist[i].current_logins = 0;
X userlist[i].max_conc_logins = 0;
X userlist[i].logins = 0;
X userlist[i].logintimebuf = 0;
X userlist[i].needs_timeset = FALSE;
X userlist[i].time = 0;
X userlist[i].total = 0;
X userlist[i].max_time = 0;
X }
X }
X ttylist = NULL;
X s_uptime = 0;
X s_start = 0;
X s_corr = 0;
X t_corr =0;
X s_stop = 0;
X s_reboots = 0;
X s_shutdowns = 0;
X s_crashes = 0;
X s_logouts = 0;
X s_logins = 0;
X shutd_state = FALSE;
X now = 0;
X}
X
X#ifdef CONFIGFILE
X
XPRIVILEGED *shutdownusers;
X
XPRIVILEGED *config_init(filename)
Xchar *filename;
X{
X FILE *fp;
X PRIVILEGED *tmp = (PRIVILEGED *)NULL;
X char priv_user[UT_NAMESIZE];
X
X fp = (FILE *)fopen(filename,"r");
X if (fp == NULL) {
X fprintf(stderr,"Warning: Could not open config file (%s)\n",
X filename ); return((PRIVILEGED *)NULL);
X }
X while (fscanf(fp,"%s",&priv_user) != EOF) {
X priv_user[UT_NAMESIZE] = '\0';
X if ((tmp = (PRIVILEGED *)malloc(sizeof(PRIVILEGED))) == (PRIVILEGED *)NULL)
X fprintf(stderr,("Fatal: malloc failed in config\n"));
X else {
X tmp->next = shutdownusers;
X tmp->user = (char *) strdup (priv_user);
X shutdownusers = tmp;
X }
X }
X if (fclose(fp) == 0)
X {
X return(tmp);
X }
X else
X {
X fprintf(stderr, "Fatal: couldn't close %s\n", filename);
X exit(1);
X }
X}
X
Xint privilege_check(username,list)
Xchar *username;
XPRIVILEGED *list;
X{
X PRIVILEGED *T;
X
X if (list != NULL) {
X for (T=list ; T != NULL ; T = T->next) {
X#ifdef DEBUG
X fprintf(stderr,"Debug: privileges test %s for %s\n",list->user, username);
X#endif /* DEBUG */
X if (!strncmp(T->user,username,UT_NAMESIZE)) return TRUE;
X }
X };
X return FALSE;
X}
X
X#endif /* CONFIGFILE */
X
Xstatic int
XSedgeHash(arg)
Xchar *arg;
X{
X int h;
X
X for (h = 0; *arg != '\0'; arg++)
X {
X h = (64 * h + *arg) % HASHTABLESIZE;
X }
X return h;
X}
X
Xstatic int
XJ_hash(arg)
Xchar *arg;
X{
X int Index, i, count=0;
X
X Index = (int) SedgeHash(arg);
X
X if (userlist[Index].name == NULL)
X {
X return Index;
X }
X for (i = Index; userlist[i].name != NULL; i++)
X {
X count++;
X if (i == HASHTABLESIZE)
X {
X i = 0;
X if (userlist[i].name == NULL)
X return i;
X }
X else if (count == HASHTABLESIZE)
X {
X fprintf(stderr, "Fatal: Hash table is full.\n");
X exit(2);
X };
X if (strcmp(userlist[i].name, arg) == 0)
X return i;
X }
X return i;
X}
X
Xint
Xucompare(i, j)
XUSER *i, *j;
X{
X if (i->time > j->time)
X return -1;
X else if (i->time < j->time)
X return 1;
X return 0;
X}
X
Xstatic TTY *
XJ_gettty(thetty)
Xchar *thetty;
X{
X register TTY *cur, *T;
X
X if (ttylist != NULL)
X {
X for (T = ttylist; T != NULL; T = T->next)
X {
X if (strncmp(thetty, T->tty, UT_LINESIZE) == 0)
X {
X return (T);
X };
X }
X };
X if ((cur = (TTY *) malloc(sizeof(TTY))) == NULL)
X {
X fprintf(stderr, "Fatal: malloc failed !\n");
X exit(1);
X }
X cur->next = ttylist;
X cur->tty = (char *) strdup(thetty);
X ttylist = cur;
X return (cur);
X}
X
Xstatic int
XJ_countlogins(uhash)
Xint uhash;
X{
X register TTY *curt;
X int count = 0;
X
X if (ttylist != NULL)
X {
X for (curt = ttylist; curt != NULL; curt = curt->next)
X {
X if ((curt->used) && (uhash == curt->user_hash))
X {
X count++;
X }
X else
X continue;
X }
X };
X return count;
X}
X
Xstatic void
XJ_logout(logouttime, cur)
Xlong logouttime;
XTTY *cur;
X{
X long stayed;
X long definite;
X int current;
X
X if (cur->used == 0)
X {
X return;
X }
X else
X {
X cur->used = 0;
X if ((logouttime != now) || (now == 0))
X /* avoid counting users still logged in */
X {
X s_logouts++;
X }
X current = J_countlogins(cur->user_hash);
X userlist[cur->user_hash].current_logins = current;
X stayed = logouttime - cur->time_in;
X if (stayed < 0)
X {
X fprintf(stderr,"Error: user %s has a negative session time.\n",
X userlist[cur->user_hash].name);
X };
X if (stayed > userlist[cur->user_hash].max_time)
X {
X userlist[cur->user_hash].max_time = stayed;
X };
X userlist[cur->user_hash].total += stayed;
X if (current == 0)
X {
X definite = logouttime - userlist[cur->user_hash].logintimebuf;
X userlist[cur->user_hash].time += definite;
X };
X }
X}
X
Xstatic void
XJ_login(inname, logintime, tty)
Xchar *inname, *tty;
Xlong logintime;
X{
X int uhash;
X register TTY *thistty;
X
X
X uhash = J_hash(inname);
X if (userlist[uhash].name == NULL)
X {
X userlist[uhash].name = (char *) strdup(inname);
X }
X else
X {
X while (strncmp(userlist[uhash].name, inname, sizeof(inname)) != 0)
X {
X fprintf(stderr, "Fatal: could not avoid hash collision at %d: %s %s\n",
X uhash, inname, userlist[uhash].name);
X exit(2);
X }
X }
X thistty = J_gettty(tty);
X if (thistty->used)
X { /* the tty is already in use */
X if (strcmp(userlist[thistty->user_hash].name,userlist[uhash].name) == 0)
X { /* the newly logged in user is already logged in */
X return;
X }
X else
X {
X J_logout(logintime, thistty);
X
X#ifdef DEBUG
X fprintf(stderr, "Debug: %s did not log out. Replaced by %s...\n",
X userlist[thistty->user_hash].name,
X userlist[uhash].name);
X#endif
X }
X };
X s_logins++;
X userlist[uhash].logins++;
X if (userlist[uhash].current_logins < 0)
X {
X userlist[uhash].current_logins = 1;
X }
X else
X {
X userlist[uhash].current_logins++;
X }
X if (userlist[uhash].current_logins == 1)
X {
X userlist[uhash].logintimebuf = logintime;
X };
X if (userlist[uhash].max_conc_logins < userlist[uhash].current_logins)
X {
X userlist[uhash].max_conc_logins = userlist[uhash].current_logins;
X };
X thistty->time_in = logintime;
X thistty->user_hash = uhash;
X thistty->used = 1;
X}
X
X#if __STDC__
Xstatic void
XJ_timeprep(void)
X#else
Xstatic void
XJ_timeprep()
X#endif
X{
X register TTY *cur;
X
X if (ttylist != NULL)
X {
X for (cur = ttylist; cur != NULL; cur = cur->next)
X {
X if (cur->used == 1)
X {
X userlist[cur->user_hash].needs_timeset = TRUE;
X };
X }
X };
X}
X
Xstatic void
XJ_timeset(oldtime, newtime)
Xlong oldtime, newtime;
X{
X long diff;
X register TTY *cur;
X
X diff = newtime - oldtime;
X if (ttylist != NULL)
X {
X for (cur = ttylist; cur != NULL; cur = cur->next)
X {
X if (cur->used == 1)
X {
X cur->time_in += diff;
X if (userlist[cur->user_hash].needs_timeset == TRUE)
X {
X userlist[cur->user_hash].logintimebuf += diff;
X userlist[cur->user_hash].needs_timeset = FALSE;
X };
X };
X }
X };
X s_corr += diff;
X t_corr += diff;
X#ifdef DEBUG
X fprintf(stderr, "Debug: date got set. Difference is: %ld\n", diff);
X#endif
X}
X
Xvoid
XJ_cleanup(endtime)
Xlong endtime;
X{
X register TTY *cur;
X
X if (ttylist != NULL)
X {
X for (cur = ttylist; cur != NULL; cur = cur->next)
X {
X if (cur->used)
X {
X J_logout(endtime, cur);
X }
X else
X continue;
X }
X };
X}
X
Xstatic void
XJ_reboot(sometime, reboottime, shutdowntime)
Xlong sometime, reboottime, shutdowntime;
X{
X long thetime, timediff;
X
X if (shutd_state == TRUE)
X {
X timediff = reboottime - shutdowntime;
X s_corr += timediff;
X if (timediff < 0)
X {
X thetime = reboottime;
X }
X else
X {
X thetime = shutdowntime;
X }
X s_reboots++;
X }
X else
X {
X if (((reboottime - sometime) > 86400) || (sometime > shutdowntime))
X {
X fprintf(stderr, "Warning: You have had a serious crash, I suppose\n");
X thetime = sometime;
X timediff = reboottime - sometime;
X s_corr += timediff;
X s_crashes++;
X }
X else
X {
X thetime = reboottime;
X s_shutdowns++;
X s_reboots++;
X }
X }
X J_cleanup(thetime);
X}
X
Xstatic void
XJ_print(list)
XUSER *list;
X{
X int i,rank=0;
X long localv;
X
X localv = now - (s_start + t_corr);
X if (localv < 0) {
X fprintf(stderr,"Warning: negative time covered!\n");
X };
X
X s_uptime = now - (s_start + s_corr);
X if (s_uptime < 0) {
X fprintf(stderr,"Warning: negative uptime!\n");
X };
X
X printf("--- System statistics---\n");
X printf("Start at: %s", ctime((time_t *)&s_start));
X printf("End at: %s", ctime((time_t *)&now));
X printf("Time covered:");
X timefmt(localv);
X printf("\n");
X printf("Uptime: ");
X timefmt(s_uptime);
X printf(" (%.1f %% of total time)\n",
X (((float) s_uptime / (float) localv) * 100.0));
X printf("Booted: %d times", s_reboots);
X printf(" (shut down %d times)\n", s_shutdowns);
X printf("Crashed: %d times\n", s_crashes);
X printf("Logins: %d\n", s_logins);
X printf("Logouts: %d\n", s_logouts);
X printf("\n--- User statistics---\n");
X qsort((char *) ((USER *) list), (size_t) HASHTABLESIZE, (size_t) sizeof(struct anUser), ucompare);
X if(toptenmode == 1) {
X for (i = 0; i < HASHTABLESIZE; i++)
X {
X if (list[i].name != NULL)
X {
X rank++;
X printf("%4d %-22s",
X rank,
X (char *)J_gecos_parse(list[i].name));
X timefmt(list[i].time);
X printf(" (%6d logins)\n",list[i].logins);
X };
X }
X }
X else {
X printf("user logins ttys real total longest average %%uptime\n");
X
X for (i = 0; i < HASHTABLESIZE; i++)
X {
X if (list[i].name != NULL)
X {
X printf("%-9s %6d %4d", list[i].name, list[i].logins,
X list[i].max_conc_logins);
X timefmt(list[i].time);
X timefmt(list[i].total);
X#ifdef DEBUG
X if (list[i].time > list[i].total)
X {
X fprintf(stderr,"Debug: total time greater than real time: %s\n",
X list[i].name);
X }
X#endif
X timefmt(list[i].max_time);
X timefmt((list[i].total / list[i].logins));
X printf(" %7.2f\n", (((float) list[i].time / (float) s_uptime) * 100));
X };
X }
X }
X}
X
Xvoid
XJ_read_wtmp(fp, def)
XFILE *fp;
Xint def;
X{
X struct utmp logbuf, *uptr;
X int first = TRUE;
X long timebuf = 0;
X char curuser[UT_NAMESIZE+1];
X char curline[UT_LINESIZE+1];
X long tob = 0, dot = 0;
X
X while (fread((char *) &logbuf, 1, sizeof(logbuf), fp) == sizeof(logbuf))
X {
X s_stop = logbuf.ut_time;
X if (first == TRUE)
X {
X first = FALSE;
X tob = s_stop;
X s_start = s_stop;
X };
X if ( s_stop < s_start )
X {
X fprintf(stderr,"Error: time scope vulneration... resetting\n");
X J_init_all();
X };
X#ifndef SYSV
X if (!strncmp("reboot", logbuf.ut_name, 6))
X#else
X if (logbuf.ut_type == BOOT_TIME)
X#endif
X {
X J_reboot(tob, s_stop, dot);
X shutd_state = FALSE;
X continue;
X }
X else if (!strncmp("shutdown", logbuf.ut_name, UT_NAMESIZE)
X#ifndef SYSV
X || logbuf.ut_line[0] == '~'
X#endif
X || shutd_state == TRUE
X#ifdef CONFIGFILE
X || (privilege_check(logbuf.ut_name,shutdownusers) == TRUE)
X#endif
X )
X {
X tob = s_stop;
X if (shutd_state == FALSE)
X {
X shutd_state = TRUE;
X s_shutdowns++;
X dot = logbuf.ut_time;
X continue;
X }
X else
X continue;
X }
X#ifndef SYSV
X else if (logbuf.ut_line[0] == '|' && !logbuf.ut_line[1])
X#else
X else if (logbuf.ut_type == OLD_TIME)
X#endif
X {
X timebuf = logbuf.ut_time;
X J_timeprep();
X tob = s_stop;
X continue;
X }
X#ifndef SYSV
X else if (logbuf.ut_line[0] == '{' && !logbuf.ut_line[1])
X#else
X else if (logbuf.ut_type == NEW_TIME)
X#endif
X {
X tob = s_stop;
X if (timebuf != 0)
X {
X#ifdef DEBUG
X fprintf(stderr,"Debug: timesetting %ld\n",(logbuf.ut_time - timebuf));
X#endif
X J_timeset(timebuf, logbuf.ut_time);
X continue;
X }
X else
X continue;
X }
X else if ((!strncmp("ftp", logbuf.ut_line, 3)) ||
X (!strncmp("uucp", logbuf.ut_line, 4)))
X {
X shutd_state = FALSE;
X tob = s_stop;
X continue;
X }
X#ifndef SYSV
X else if (isalnum(logbuf.ut_name[0]) != 0)
X#else
X else if (logbuf.ut_type == USER_PROCESS)
X#endif
X {
X shutd_state = FALSE;
X uptr = &logbuf;
X curuser[UT_NAMESIZE] = '\0';
X curline[UT_LINESIZE] = '\0';
X
X strncpy(curuser, uptr->ut_name, UT_NAMESIZE);
X strncpy(curline, uptr->ut_line, UT_LINESIZE);
X J_login(curuser, uptr->ut_time, curline);
X tob = s_stop;
X continue;
X }
X#ifndef SYSV
X else if (logbuf.ut_line != NULL)
X#else
X else if (logbuf.ut_type == DEAD_PROCESS)
X#endif
X {
X curline[UT_LINESIZE] = '\0';
X strncpy(curline, logbuf.ut_line, UT_LINESIZE);
X J_logout(logbuf.ut_time, J_gettty(curline));
X tob = s_stop;
X continue;
X }
X else
X {
X#ifndef SYSV
X fprintf(stderr, "Warning: Strange entry at %s\n%s %s\n",
X ctime((time_t *)&logbuf.ut_time),
X logbuf.ut_name, logbuf.ut_line);
X#endif
X tob = s_stop;
X continue;
X }
X }
X if (def == 0)
X {
X now = s_stop;
X }
X else
X {
X now = (long) time((time_t *) 0);
X }
X J_cleanup(now);
X J_print(userlist);
X}
X
Xvoid
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X FILE *fd;
X#ifdef WTMP_FILE
X char *wtmp = WTMP_FILE;
X#else
X char *wtmp = "/usr/adm/wtmp";
X#endif
X#ifdef CONFIGFILE
X char *configfile = CONFIGFILE;
X#endif
X int def = 1;
X
X while (--argc > 0 && **++argv == '-')
X switch (*++*argv)
X {
X case 'w':
X if (--argc > 0)
X {
X wtmp = *++argv;
X def--;
X }
X continue;
X case 't':
X toptenmode++;
X continue;
X#ifdef CONFIGFILE
X case 'c':
X if (--argc > 0)
X {
X configfile = *++argv;
X }
X continue;
X#endif
X }
X#ifdef CONFIGFILE
X shutdownusers = config_init(configfile);
X#endif
X
X fd = (FILE *) fopen(wtmp, "r");
X if (fd == NULL)
X {
X fprintf(stderr, "Fatal: %s ... no such file\n", wtmp);
X exit(1);
X }
X J_read_wtmp(fd, def);
X if (fclose(fd) == 0)
X {
X exit(0);
X }
X else
X {
X fprintf(stderr, "Fatal: couldn't close %s\n", wtmp);
X exit(1);
X }
X}
END-of-freeks-1.32/freeks.c
echo x - freeks-1.32/freeks.cat
sed 's/^X//' >freeks-1.32/freeks.cat << 'END-of-freeks-1.32/freeks.cat'
X
X
X
Xfreeks(6) Freeks 1.32 Geeking Manual freeks(6)
X
X
X
XNAME
X freeks - fast 'geeks style' login accounting
X
XSYNOPSIS
X freeks [-w wtmp ] [-t] [-c configfile ]
X
X
XDESCRIPTION
X Freeks is a fast and reduced version of geeks(6). The
X default for wtmp is "/usr/adm/wtmp".
X
X Freeks produces a report on system usage based on the con-
X tents of wtmp and sorted by the actual time different users
X have spent on the system. The format of the output is
X almost similar to geeks(6). The first lines are different,
X they contain general information about the system. In the
X 'User statistics' section the last field is different also,
X containing the percentage of total uptime the user spent
X logged in to the system.
X
X
X
XOPTIONS
X You may specify an alternate wtmp file on the command line.
X
X With the 't' option the user statistics are modified, show-
X ing the 'geek rank', the name, the time the user was actu-
X ally logged in and the number of logins.
X
X With the 'c' option you can specify a configfile containing
X the names of alternative 'shutdown' users (cf. TODO), which
X is probably interesting to SysV machine owners only.
X
X
XBUGS
X Freeks is (almost) limited to BSD style wtmp files (cf. TODO
X below). It does not have a lot of fancy options. It does not
X include a server similar to geeksd(6). Freeks does make some
X mistakes, e.g. when a reboot entry in wtmp happened without
X a shutdown before it. If the last entry happened more than a
X day before the reboot entry, freeks presumes that the
X machine crashed, and will use the time of the last entry
X before the crash as time of shutdown. This may lead to mar-
X ginal errors in 'uptime' and the login times of users still
X logged in at that time.
X
X Another bug happens when time is changed in single user mode
X which means it doesn't get logged. Don't do that, or delete
X the wtmp file afterwards.
X
X
X
X
X
X
XApostolos Lytras Last change: June 24, 1994 1
X
X
X
X
X
X
Xfreeks(6) Freeks 1.32 Geeking Manual freeks(6)
X
X
X
XTODO
X System V has changed a lot in wtmp but it should be possible
X to run the program, if you rarely shut your machine down or
X have a dedicated 'shutdown' user that logs in when you shut
X down. If this user is called 'shutdown' you needn't do noth-
X ing, if his login name is something else, you can specify
X that in configfile (if, of course, freeks had been compiled
X with CONFIGFILE defined...).
X
X
X
XSEE ALSO
X geeks(5) geeks(6) ac(8) wtmp(5) wtmpfix(8) login(1) init(8)
X
X
XFILES
X /usr/adm/wtmp wtmp file
X
XAUTHOR
X Copyright (C) 1994 by Apostolos Lytras
X (lytras@avalon.unizh.ch).
X
X Thanks to Dave P. Gymer (dpg@cs.nott.ac.uk) and everyone
X that helped him write geeks(6). It has been an important
X inspiration and a reason to write this program (because it
X was just too slow, geeks! ;-).
X
X Thanks also to Wietse Venema for his information on SVR4's
X wtmp.
X
X Some of the credit must also go to the University of Cali-
X fornia, Berkeley, for their programs ac(8), last(1) and
X uptime(1), which evaluate /usr/adm/wtmp as well. These pro-
X grams were inspiring as well, because they couldn't do
X everything real geeks needed them to.
X
X This is free software; you can redistribute it and/or modify
X it under the terms of the GNU General Public License as pub-
X lished by the Free Software Foundation; either version 2 of
X the License, or (at your option) any later version.
X
X The GNU General Public License is not included in the origi-
X nal distrubution of freeks. If you don't have a copy of it
X already, write to the Free Software Foundation, 675 Mass
X Ave, Cambridge, MA 02139, USA.
X
X This program is distributed in the hope that it will be
X useful, but WITHOUT ANY WARRANTY; without even the implied
X warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
X PURPOSE. See the GNU General Public License for more
X details.
X
X
X
X
XApostolos Lytras Last change: June 24, 1994 2
X
X
X
X
X
X
Xfreeks(6) Freeks 1.32 Geeking Manual freeks(6)
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
X
XApostolos Lytras Last change: June 24, 1994 3
X
X
X
X
X
X
END-of-freeks-1.32/freeks.cat
echo x - freeks-1.32/freeks.h
sed 's/^X//' >freeks-1.32/freeks.h << 'END-of-freeks-1.32/freeks.h'
X/* --- start of configurable section --- */
X/*
X * HASHTABLESIZE must be prime, such as 61,113,251,509,1021 To save memory
X * choose a value close to the number of users on your system.
X *
X * Note:
X * This is not a full-fledged hashing library, just some code stolen from
X * "Algorithms in C" by Robert Sedgewick which has been refined to avoid hash
X * collisions. The algorithm which does this is very simple and probably not
X * worth a lot in more complex programs. (It does not handle removal from the
X * list, because that won't happen in this application.)
X */
X#ifndef HASHTABLESIZE
X#define HASHTABLESIZE 1021
X#endif
X
X/* NO_STRDUP:
X * if your system doesn't have the strdup routine, then uncomment the
X * definition below.
X */
X/* #define NO_STRDUP */
X
X/* WANTGECOS:
X * If you want to use GECOS entries ("real names") in 'freeks -t' output
X * define this
X */
X#ifndef WANTGECOS
X#define WANTGECOS
X#endif
X
X/* DEBUG:
X * If you want to get more debugging output on standard error, then
X * uncomment this here or look at the debugflags in the Makefile
X */
X/* #define DEBUG */
X
X/* CONFIGFILE */
X/* System V users might want to create a configfile containing the */
X/* names of additional usernames that create a shutdown, like `halt' */
X/* or `powerdown'. Each username must appear separately on a line in */
X/* the file */
X/* #define CONFIGFILE "/usr/local/lib/freeks/config" */
X
X/* --- you shouldn't need to change much below this --- */
X
X#if defined(__hpux)
X#ifndef SYSV
X#define _CLASSIC_ID_TYPES
X#endif
X#endif
X
X#include <stdlib.h>
X#include <stdio.h>
X#include <time.h>
X#include <sys/file.h>
X#include <ctype.h>
X#ifndef SYSV
X#include <utmp.h>
X#include <strings.h>
X#else
X#include <utmpx.h>
X#include <string.h>
X#ifndef ut_name
X#define ut_name ut_user
X#endif
X#endif
X
X#ifdef WANTGECOS
X#include <pwd.h>
X/***************************************************************/
X/* MAX_GECOS_LEN is the maximum length of a gecos entry in the */
X/* password database for use in topten ( option '-t' ) mode */
X/* Default: 20 */
X/***************************************************************/
X#define MAX_GECOS_LEN 20
X#define minimum(a,b) (a < b) ? a : b
X#endif /* WANTGECOS */
X
Xstruct utmp dummy;
X#define UT_NAMESIZE sizeof (dummy.ut_name)
X#define UT_LINESIZE sizeof (dummy.ut_line)
X
X#define TRUE 1
X#define FALSE 0
X
X#define timefmt(time) \
Xprintf(" %4ld:%02ld:%02ld", (time) / 3600, ((time) / 60) % 60, (time) % 60)
X
X#ifndef NO_STRDUP
X#if (defined(__ultrix__) || defined(nextstep3))
X#define NO_STRDUP
X#endif /* ultrix or nextstep */
X#endif
X
Xtypedef struct anUser
X{
X char *name;
X int current_logins;
X int max_conc_logins;
X int logins;
X long logintimebuf;
X int needs_timeset;
X long time;
X long total;
X long max_time;
X} USER;
X
Xtypedef struct aTty
X{
X char *tty;
X int used;
X int user_hash;
X long time_in;
X struct aTty *next;
X} TTY;
X
X#ifdef CONFIGFILE
Xtypedef struct priv_list {
X char *user;
X struct priv_list *next;
X} PRIVILEGED ;
X#endif
X
END-of-freeks-1.32/freeks.h
echo x - freeks-1.32/gecos.c
sed 's/^X//' >freeks-1.32/gecos.c << 'END-of-freeks-1.32/gecos.c'
X/* gecos.c */
X/* Apostolos Lytras. June 1994 */
X/* This little program gets a user name on its command line for which */
X/* it searches /etc/passwd's gecos entry and strips everything but the */
X/* first of its (comma delimited) fields... */
X/* BUGS: maybe the first field is not the user's real name... ?! */
X
X#include "freeks.h"
X
X#ifndef WANTGECOS
X
Xchar *J_gecos_parse(string)
Xchar *string;
X{
X return string; /* dummy function */
X}
X
X#else
X
Xchar *J_gecos_parse(namen)
Xchar *namen;
X{
X char out[MAX_GECOS_LEN], *output, *input;
X int len, i;
X struct passwd *dastruct;
X
X dastruct = (struct passwd *) malloc (sizeof(struct passwd *));
X if ((dastruct = getpwnam(namen)) == (struct passwd *)NULL )
X {
X#ifdef DEBUG
X fprintf(stderr,"Debug: user %s is not in password file.\n",namen);
X#endif
X return namen;
X };
X if ((input = (char *)strdup(dastruct->pw_gecos)) == (char *)NULL)
X {
X fprintf(stderr,"Fatal: allocation for GECOS failed.\n");
X exit(-2);
X };
X len = minimum((MAX_GECOS_LEN - 1),strlen(input));
X for ( i = 0; (i <= len) && (input[i] != ',') ; i++, out[i] = '\0')
X {
X out[i] = input[i];
X }
X output = (char *)strdup(out);
X return output;
X}
X
X#endif
END-of-freeks-1.32/gecos.c
exit