[alt.sources] lastlog for SVR4

tin@smsc.sony.com (Tin Le) (05/23/91)

I ported this from Tom C.'s posting in just a few minutes.  There is also
a lastlogin for System V (I have it running on ISC v2.0.2).  With this,
you could have the same functionalities as with BSD systems.

Submitted-by: tin@rn31
Archive-name: lastlog/part01

---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is lastlog, a shell archive (produced by shar 3.49)
# To extract the files from this archive, save it to a file, remove
# everything above the "!/bin/sh" line above, and type "sh file_name".
#
# made 05/22/1991 21:05 UTC by tin@rn31
# Source directory /usr1/tin/News/last
#
# existing files will NOT be overwritten unless -c is specified
# This format requires very little intelligence at unshar time.
# "if test", "echo", "true", and "sed" may be needed.
#
# This shar contains:
# length  mode       name
# ------ ---------- ------------------------------------------
#    282 -rw-r--r-- Makefile
#   3458 -rw-r--r-- lastlog.c
#
# ============= Makefile ==============
if test -f 'Makefile' -a X"$1" != X"-c"; then
	echo 'x - skipping Makefile (File already exists)'
else
echo 'x - extracting Makefile (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'Makefile' &&
X#
X#  Makefile for last
X#
X# 5/22/91 Tin
X#
XTARGET = last
XOBJECTS = lastlog.o 
XCFLAGS = -O -DSVR4
XLDFLAGS = -s
XLIBS = 
XINCLDIR = /usr/include
X
X$(TARGET): $(OBJECTS)
X	$(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(OBJECTS) $(LIBS)
X
Xclean:
X	-rm -f $(OBJECTS) core
X
Xclobber: clean
X	-rm -f $(TARGET)
X
SHAR_EOF
true || echo 'restore of Makefile failed'
fi
# ============= lastlog.c ==============
if test -f 'lastlog.c' -a X"$1" != X"-c"; then
	echo 'x - skipping lastlog.c (File already exists)'
else
echo 'x - extracting lastlog.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'lastlog.c' &&
X/*
X * lastlog - print last login time for all users, based on times
X *            stored in /usr/adm/lastlog.
X *
X * Lines are printed oldest first, with name, date/time, and gecos
X * field on each line.
X *
X * No command line options. Runs on VAX/4.2 BSD Unix, Sony RISC SVR4.
X *
X * compile with:  cc -O -o lastlog lastlog.c
X *
X * Tin Le, Sony Microsystems, San Jose 5/22/91
X * - Adapted for SVR4.
X *
X * Rex Sanders, US Geological Survey, Pacific Marine Geology, 12/19/85
X */
X
X#include <stdio.h>
X#include <sys/types.h>
X#ifdef SVR4
X#include <fcntl.h>
X#include <string.h>
X#else
X#include <sys/file.h>
X#include <strings.h>
X#endif
X#include <lastlog.h>
X#include <pwd.h>
X#ifndef SVR4
X#include <sysexits.h>
X#else
X#define EX_OSFILE	1
X#define EX_SOFTWARE	2
X#endif
X
X/* In case your UNIX put lastlog somewhere other than */adm/lastlog */
X#define LASTLOG		"/usr/adm/lastlog"
X
X/* maximum number of users/entries in /etc/passwd */
X#define MAXU       5000
X/* maximum length of the gecos field in /etc/passwd */
X#define MAXG        100
X
Xchar   *ctime ();
Xlong    lseek ();
X
Xstruct info_s {
X    int     time;
X#ifdef SVR4	/* Actually there is no hard limit in SVR4 struct passwd
X		** Change this to char *name, and malloc your string if you
X		** really want to get complicated.
X		** 5/22/91 Tin
X		*/
X    char    name[15];
X#else
X    char    name[9];
X#endif
X    char    gecos[MAXG];
X};
Xstruct info_s   info[MAXU];
X
Xmain (argc, argv) char **argv; {
X    int     infocmp ();
X    struct lastlog  ll;
X    struct passwd  *pw;
X    char    lastdate[25];
X    int     llfd;
X    register int    nusers = 0;
X    register int    i;
X
X    if ((llfd = open (LASTLOG, O_RDONLY)) < 0) {
X	perror("open()");
X	fprintf(stderr, "lastlog: %s\n", LASTLOG);
X	exit (EX_OSFILE);
X    }
X
X/*
X * For each user in password file, grab password info
X */
X    while (pw = getpwent ()) {
X    /* 
X     * Grab info from lastlog file
X     */
X	 if (!strcmp(pw->pw_passwd,"*"))
X		continue;
X         if (lseek (llfd, (long) pw -> pw_uid * sizeof ll, 0) == -1) {
X	    fprintf(stderr,"%s: lseek for uid %d failed\n", *argv, pw->pw_uid);
X	    continue;
X	 } 
X         if (read (llfd, (char *) & ll, sizeof ll) != sizeof ll) {
X	    fprintf(stderr, "%s: read for uid %d (%s) failed\n",
X		*argv, pw->pw_uid, pw->pw_name);
X	    continue;
X	 } 
X
X
X         info[nusers].time = ll.ll_time;
X#ifdef SVR4
X         strcpy (info[nusers].name, pw -> pw_name);
X#else
X         strncpy (info[nusers].name, pw -> pw_name, 9);
X#endif
X         strncpy (info[nusers].gecos, pw -> pw_gecos, MAXG);
X         if (nusers++ == MAXU) {
X	    fprintf(stderr, "%s: recompile with MAXU > %d\n",
X		*argv, MAXU);
X	    exit(EX_SOFTWARE);
X	 } 
X    }
X
X/*
X * Sort users by last login time
X */
X    qsort ((char *) info, nusers, sizeof (struct info_s), infocmp);
X
X/*
X * Print info for each user
X */
X    for (i = 0; i < nusers; i++) {
X         if (info[i].time) {
X             strncpy (lastdate, ctime (&info[i].time), 24);
X             lastdate[24] = '\0';
X         }
X         else
X             strcpy (lastdate, "never logged in");
X
X         printf ("%-12s %-24s    %s\n", info[i].name, lastdate,
X                   info[i].gecos);
X    }
X
X    close (llfd);
X    endpwent ();
X}
X
X/*
X * infocmp - compare 2 info entries for qsort
X */
X
Xinfocmp (info1, info2)
Xstruct info_s  *info1,
X               *info2;
X{
X    register int    r;
X
X    if (info1 -> time == info2 -> time)
X         r = 0;
X    else
X         r = (info1 -> time > info2 -> time) ? 1 : -1;
X
X    return (r);
X}
X
SHAR_EOF
true || echo 'restore of lastlog.c failed'
fi
exit 0
-- 
.----------------------------------------------------------------------
. Tin Le                    Work Internet: tin@smsc.Sony.COM
. Sony Microsystems              UUCP: {uunet,mips}!sonyusa!tin
. Work: (408) 944-4157      Home Internet: tin@szebra.uu.net