[alt.sources] When does wtmp reset?

tchrist@convex.COM (Tom Christiansen) (05/22/91)

From the keyboard of tpm-sprl!tpm@uunet.uu.net (Terence P. Ma):
:I know that the last login date is in /var/adm/lastlog.  Is there an easy
:way to get the lastlogin date and time of all users or groups of users
:without using "finger -s user1 user2 ..." to get at it?

Here's a C program to do that.  Perl version (runs 3x slower; sigh)
available upon request.  

--tom

/*
 * lastlog - print last login time for all users, based on times
 *            stored in /usr/adm/lastlog.
 *
 * Lines are printed oldest first, with name, date/time, and gecos
 * field on each line.
 *
 * No command line options. Runs on VAX/4.2 BSD Unix.
 *
 * compile with:  cc -O -o lastlog lastlog.c
 *
 * Rex Sanders, US Geological Survey, Pacific Marine Geology, 12/19/85
 */

#include <stdio.h>
#include <strings.h>
#include <sys/file.h>
#include <sys/types.h>
#include <lastlog.h>
#include <pwd.h>
#include <sysexits.h>

/* maximum number of users/entries in /etc/passwd */
#define MAXU       5000
/* maximum length of the gecos field in /etc/passwd */
#define MAXG        100

char   *ctime ();
long    lseek ();

struct info_s {
    int     time;
    char    name[9];
    char    gecos[MAXG];
};
struct info_s   info[MAXU];

main (argc, argv) char **argv; {
    int     infocmp ();
    struct lastlog  ll;
    struct passwd  *pw;
    char    lastdate[25];
    int     llfd;
    register int    nusers = 0;
    register int    i;

    if ((llfd = open ("/usr/adm/lastlog", O_RDONLY)) < 0) {
         perror ("lastlog: /usr/adm/lastlog");
         exit (EX_OSFILE);
    }

/*
 * For each user in password file, grab password info
 */
    while (pw = getpwent ()) {
    /* 
     * Grab info from lastlog file
     */
	 if (!strcmp(pw->pw_passwd,"*"))
		continue;
         if (lseek (llfd, (long) pw -> pw_uid * sizeof ll, 0) == -1) {
	    fprintf(stderr,"%s: lseek for uid %d failed\n", *argv, pw->pw_uid);
	    continue;
	 } 
         if (read (llfd, (char *) & ll, sizeof ll) != sizeof ll) {
	    fprintf(stderr, "%s: read for uid %d failed\n", *argv, pw->pw_uid);
	    continue;
	 } 


         info[nusers].time = ll.ll_time;
         strncpy (info[nusers].name, pw -> pw_name, 9);
         strncpy (info[nusers].gecos, pw -> pw_gecos, MAXG);
         if (nusers++ == MAXU) {
	    fprintf(stderr, "%s: recompile with MAXU > %d\n",
		*argv, MAXU);
	    exit(EX_SOFTWARE);
	 } 
    }

/*
 * Sort users by last login time
 */
    qsort ((char *) info, nusers, sizeof (struct info_s), infocmp);

/*
 * Print info for each user
 */
    for (i = 0; i < nusers; i++) {
         if (info[i].time) {
             strncpy (lastdate, ctime (&info[i].time), 24);
             lastdate[24] = '\0';
         }
         else
             strcpy (lastdate, "never logged in");

         printf ("%-8s %-24s    %s\n", info[i].name, lastdate,
                   info[i].gecos);
    }

    close (llfd);
    endpwent ();
}

/*
 * infocmp - compare 2 info entries for qsort
 */

infocmp (info1, info2)
struct info_s  *info1,
               *info2;
{
    register int    r;

    if (info1 -> time == info2 -> time)
         r = 0;
    else
         r = (info1 -> time > info2 -> time) ? 1 : -1;

    return (r);
}
--
Tom Christiansen		tchrist@convex.com	convex!tchrist
		"So much mail, so little time."