home *** CD-ROM | disk | FTP | other *** search
- From decwrl!purdue!gatech!cwjcc!hal!ncoast!allbery Fri Nov 18 20:44:33 PST 1988
- Article 726 of comp.sources.misc:
- Path: granite!decwrl!purdue!gatech!cwjcc!hal!ncoast!allbery
- From: moran@tron.UUCP
- Newsgroups: comp.sources.misc
- Subject: v05i049: "last" command for System V
- Message-ID: <8811111227.AA24477@tron.WEC.COM>
- Date: 15 Nov 88 00:27:31 GMT
- Sender: allbery@ncoast.UUCP
- Reply-To: moran@tron.UUCP
- Lines: 397
- Approved: allbery@ncoast.UUCP
-
- Posting-number: Volume 5, Issue 49
- Submitted-by: "A. Nonymous" <moran@tron.UUCP>
- Archive-name: s5last
-
- # This is a shell archive.
- # Remove everything above and including the cut line.
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # last.1
- # Makefile
- # last.c
- # This archive created: Thu Nov 10 00:50:45 1988
- echo shar: extracting last.1
- sed 's/^X //' << \SHAR_EOF > last.1
- X .\" Copyright (c) 1988 Harvey R. Moran Jr.
- X .\" 1936 Altavue Rd.
- X .\" Catonsville, Md., 21228
- X .\"
- X .\" moran%tron.UUCP@umbc3.UMD.EDU Internet
- X .\" {wb3ffv,netsys}!hrmhpc!harvey UUCP
- X .\"
- X .\" This software may be freely distributed provided that this
- X .\" copyright notice is left intact and provided that:
- X .\" a) The source code in machine readable format
- X .\" is included with any binary distribution.
- X .\" b) If a binary version of this program or a derived work is sold,
- X .\" the source code must be provided in machine readable
- X .\" format for no additional charge.
- X .\" c) No derived works may impose restrictions limiting free
- X .\" distribution of the source code.
- X .\" Source code in this context includes the C language source code
- X .\" provided here as file "last.c" and the manual page provide here as
- X .\" file "last.1". It also includes any works derived from either of these.
- X .TH last 1L LOCAL
- X .SH NAME
- X last \- indicate last logins of users
- X .SH SYNTAX
- X .B last
- X [
- X .I -N
- X ] [
- X .I name
- X ]
- X .SH DESCRIPTION
- X The
- X .I last
- X command
- X looks back in the
- X .I wtmp
- X file which records all logins and logouts for information about
- X a user, or all users in reverse time order.
- X The optional argument
- X .I -N
- X specifies the maximum number of lines to print.
- X The optional
- X .I name
- X specifies the name of a user of interest.
- X If the session is still continuing \fBlast\fR
- X so indicates.
- X .PP
- X The
- X .I last
- X command
- X with no arguments prints a record of all logins and logouts.
- X .SH ORIGIN
- X This command is modeled on the
- X .I last
- X command which comes with the
- X Berkeley Software Distribution (BSD) of UNIX(tm). The Berkeley version
- X also permits specifying a terminal name. It also includes the
- X field specifying the remote machine in the case of a network login.
- X No such field is present in the System V.2 version of /etc/wtmp.
- X .SH FILES
- X /etc/wtmp login data base
- X .SH SEE\ ALSO
- X utmp(4) login data base format description
- SHAR_EOF
- if test 2013 -ne "`wc -c last.1`"
- then
- echo shar: error transmitting last.1 '(should have been 2013 characters)'
- fi
- echo shar: extracting Makefile
- sed 's/^X //' << \SHAR_EOF > Makefile
- X DEFS = -DMAXENTRIES=1024 # maximum number of entries in /etc/wtmp handled
- X CFLAGS = -O -s $(DEFS) # -O(ptomize) -s(trip symbols)
- X
- X last: last.c
- X cc $(CFLAGS) -o last last.c
- SHAR_EOF
- if test 172 -ne "`wc -c Makefile`"
- then
- echo shar: error transmitting Makefile '(should have been 172 characters)'
- fi
- echo shar: extracting last.c
- sed 's/^X //' << \SHAR_EOF > last.c
- X /*
- X * last.c -- examine the wtmp file for last login information
- X *
- X * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- X * Copyright (c) 1988 Harvey R. Moran Jr.
- X * 1936 Altavue Rd.
- X * Catonsville, Md., 21228
- X *
- X * moran%tron.UUCP@umbc3.UMD.EDU Internet
- X * {wb3ffv,netsys}!hrmhpc!harvey UUCP
- X *
- X * This software may be freely distributed provided that this
- X * copyright notice is left intact and provided that:
- X * a) The source code in machine readable format
- X * is included with any binary distribution.
- X * b) If a binary version of this program or a derived work is sold,
- X * the source code must be provided in machine readable
- X * format for no additional charge.
- X * c) No derived works may impose restrictions limiting free
- X * distribution of the source code.
- X * Source code in this context includes the C language source code
- X * provided here as file "last.c" and the manual page provide here as
- X * file "last.1". It also includes any works derived from either of these.
- X *
- X * =*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
- X * Developed using Microport System V/AT 2.3U
- X *
- X * usage:
- X * last [ -N ] [ username ]
- X *
- X * This will print the usage of the system as
- X * recorded in WTMP_FILE (defined in /usr/include/utmp.h) for
- X * all users except the ones listed in exclude[] (below).
- X * The option -N specifies that a maximum of N lines of
- X * output will be generated.
- X * The optional username form will restrict information printed
- X * to be logins by the specified user.
- X *
- X * This command is modeled on the "last" command which is distributed
- X * with the Berkeley Software Distribution (BSD) of UNIX(tm).
- X * The print formats are slightly different. The field which
- X * specifies a network login identification are not provided with this
- X * version because the information is not available in the System V.2
- X * UNIX(tm) WTMP_FILE file.
- X *
- X * It will also quit (with error message) if there are more than
- X * MAXENTRIES entries in your WTMP_FILE (/etc/wtmp on my system).
- X *
- X * Harvey Moran 11/10/88
- X */
- X #include <stdio.h>
- X #include <fcntl.h>
- X #include <sys/types.h>
- X #include <utmp.h>
- X #include <time.h>
- X
- X #ifndef MAXENTRIES
- X # define MAXENTRIES 1024 /* maximum entries in WTMP_FILE handled */
- X #endif
- X
- X #define STILL_IN -1L
- X #define AVOID -1L
- X
- X typedef int BOOL;
- X #define YES 1
- X #define NO 0
- X
- X typedef struct utmp WTMP_t;
- X WTMP_t proc_tab;
- X
- X typedef struct {
- X char user_name[9];
- X short pid;
- X time_t x_time;
- X time_t y_time;
- X } ENTRY;
- X
- X ENTRY entries[MAXENTRIES];
- X
- X /*
- X * user process user names to be excluded from display
- X * change per local installation. Perhaps these should be
- X * in an environment variable instead, but there are already
- X * so many of them.
- X */
- X char *exclude[] = { "rc2", "crtsaver", "LOGIN", NULL };
- X
- X char *keep_list = (char *) NULL;
- X
- X /*
- X * forward declared functions
- X */
- X
- X char *delta_time();
- X void qsort();
- X int cmp_ENTRY(), cmp_ENTRY_1();
- X
- X main(ac, av)
- X int ac;
- X char *av[];
- X {
- X int i, j, fd;
- X unsigned count = (unsigned) -1; /* BIG unsigned int. */
- X char intime[27], outtime[27], elapsed[27];
- X long time_tmp;
- X
- X if ( ac > 1 && (i = atoi(av[1])) < 0 ) {
- X count = (unsigned) -i;
- X for ( i = 2; i < ac; ++i )
- X av[i-1] = av[i];
- X av[i] = NULL;
- X --ac;
- X }
- X if ( (fd=open(WTMP_FILE, (O_RDONLY|O_NDELAY))) == -1 ) {
- X fprintf(stderr, "%s:Can't open %s\n", av[0], WTMP_FILE);
- X exit(1);
- X }
- X i = 0;
- X while ( read(fd, &proc_tab, sizeof(WTMP_t)) == sizeof(WTMP_t) ) {
- X switch ( proc_tab.ut_type ) {
- X case EMPTY: /* Empty slot in the WTMP_FILE */
- X case INIT_PROCESS: /* Process started by "init" */
- X case LOGIN_PROCESS: /* A "getty" process waiting for login */
- X case ACCOUNTING:
- X break; /* IGNORE all these forever */
- X
- X case RUN_LVL: /* Change of Run Level */
- X case BOOT_TIME: /* Boot time */
- X case OLD_TIME: /* Old time of Day was */
- X case NEW_TIME: /* New Time of Day set */
- X break; /* IGNORE all these for now */
- X
- X case USER_PROCESS: /* A user process was started */
- X case DEAD_PROCESS: /* A user (I think) process died */
- X strncpy(entries[i].user_name, proc_tab.ut_user, sizeof(proc_tab.ut_user));
- X if ( omit(entries[i].user_name, ac, av) )
- X break;
- X if ( ac == 2 && strcmp(av[1], entries[i].user_name) )
- X break; /* not the user of interest */
- X entries[i].pid = proc_tab.ut_pid;
- X entries[i].x_time = proc_tab.ut_time;
- X if ( ++i > (sizeof(entries)/sizeof(ENTRY)) ) {
- X fprintf(stderr, "Too many entries in %s\n", WTMP_FILE);
- X fprintf(stderr, "Fix program %s\n", av[0]);
- X exit(2);
- X }
- X break;
- X
- X default:
- X fprintf(stderr, "Ignoring GARBAGE in file %s. (ut_type = 0x%02x)\n", WTMP_FILE, proc_tab.ut_type);
- X break;
- X }
- X }
- X /*
- X * sort by pid, x_time
- X */
- X qsort((char *) entries, i, sizeof(ENTRY), cmp_ENTRY);
- X j = 0;
- X #define E entries /* minimize line wrapping of source code */
- X do {
- X if ( j == (i-1) ) {
- X /*
- X * final login has no corresponding logout
- X * avoid referencing array element with is empty (or does not exist)
- X */
- X E[j].y_time = STILL_IN;
- X break;
- X }
- X else if ( E[j].pid != E[j+1].pid ) { /* login has no corresponding logout */
- X E[j].y_time = STILL_IN;
- X ++j;
- X }
- X else { /* E[j].pid == E[j+1].pid , i.e. login/logout pair */
- X E[j].y_time = E[j+1].x_time;
- X E[j+1].x_time = AVOID;
- X j += 2;
- X }
- X } while ( j < i );
- X /*
- X * sort by descending x_time
- X */
- X qsort((char *) entries, i, sizeof(ENTRY), cmp_ENTRY_1);
- X for ( j = 0; j < i && count; ++j ) {
- X if ( E[j].x_time == AVOID )
- X continue;
- X else if ( E[j].y_time == STILL_IN ) {
- X time_tmp = (long) E[j].x_time;
- X (void) strcpy(intime, asctime(localtime(&time_tmp)));
- X intime[20] = '\0'; /* strip year */
- X printf("%-8s %s %s still-logged-in\n", E[j].user_name, intime, " ");
- X --count;
- X }
- X else {
- X time_tmp = (long) E[j].x_time;
- X (void) strcpy(intime, asctime(localtime(&time_tmp)));
- X time_tmp = (long) E[j].y_time;
- X (void) strcpy(outtime, asctime(localtime(&time_tmp)));
- X intime[20] = outtime[20] = '\0'; /* strip year */
- X time_tmp = (long) (E[j].y_time - E[j].x_time);
- X (void) strcpy(elapsed, delta_time(time_tmp));
- X printf("%-8s %s-%s %s\n", E[j].user_name, intime, outtime+10, elapsed);
- X --count;
- X }
- X }
- X #undef E
- X }
- X
- X /*
- X * return comparison of 2 ENTRY type records
- X * suitable for sorting by: pid, x_time
- X */
- X
- X cmp_ENTRY(a, b)
- X ENTRY *a, *b;
- X {
- X if ( a->pid < b->pid )
- X return (-1);
- X if ( a->pid > b->pid )
- X return (1);
- X if ( a->x_time < b->x_time )
- X return (-1);
- X if ( a->x_time > b->x_time )
- X return (1);
- X return (0);
- X }
- X
- X /*
- X * return comparison of 2 ENTRY type records
- X * suitable for a descending sort by: x_time
- X */
- X cmp_ENTRY_1(a,b)
- X ENTRY *a, *b;
- X {
- X if ( a->x_time < b->x_time )
- X return (1);
- X if ( a->x_time > b->x_time )
- X return (-1);
- X return (0);
- X }
- X
- X
- X /*
- X * return whether to omit this name
- X * It is omitted if:
- X * a) the name matches something in the exclude list
- X * b) the name does not match something in the invocation argument list
- X * and the argument list is not null
- X */
- X BOOL
- X omit(name, ac, av)
- X char *name;
- X int ac;
- X char *av[];
- X {
- X char **p;
- X int i;
- X
- X for ( p = &exclude[0]; *p != (char *) NULL; ++p ) {
- X if ( strcmp(*p, name) == 0 )
- X return (YES);
- X }
- X if ( ac == 1 ) /* empty argument list, do not omit any */
- X return (NO);
- X for ( i = 1; i < ac; ++i ) {
- X if ( strcmp(name, av[i]) == 0 )
- X return (NO);
- X }
- X return (YES);
- X }
- X
- X
- X char *
- X delta_time(t)
- X long t;
- X {
- X static char AscTime[11];
- X int sec, min, hr, da;
- X long x, y;
- X
- X sec = t % 60L;
- X x = (t - (long) sec)/60L;
- X min = x % 60L;
- X x = (x - (long) min)/60L;
- X hr = x % 24;
- X x = (x - (long) hr)/24L;
- X da = x;
- X if ( da )
- X (void) sprintf(AscTime, "%3d+%02d:%02d:%02d", da, hr, min, sec);
- X else
- X (void) sprintf(AscTime, " %02d:%02d:%02d", hr, min, sec);
- X return (AscTime);
- X }
- SHAR_EOF
- if test 7908 -ne "`wc -c last.c`"
- then
- echo shar: error transmitting last.c '(should have been 7908 characters)'
- fi
- # End of shell archive
- exit 0
-
-
-