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."