DOCUMENT ID: 1329-02 SYNOPSIS: A program to print wtmp OS RELEASE: 2.x PRODUCT: Solaris x86 KEYWORDS: wtmp listing login accounting DESCRIPTION: There are occasions when the "login" time of a user must be calculated for a special purpose. Wtmp is the system file containing this information. This is a structured file consisting of both character and binary elements as can be observed by inspecting /usr/include/utmp.h. A "login" session is defined by a pair of file entries, one with start time and on with stop time. Several pending "login" entries will exist in a multiuser system environment. A C program is required to process the utmp structured file and produce readable output. The sample program will illustrate several of the caveats of processing wtmp. Several items are of note: Character elements in records are not null terminated. "ut_time" is in UNIX seconds since 1970. "ut_type" element must be monitored to determine entries related to login sessions. The user name, start time and stop will be printed on stdout until one of three conditions: an EOF on the wtmp file, max records are processed, or the number of pending entries is exceeded. ------------------------program start-------------------------------------- #include#include #include #include #include #include /* * Structure returned by ftime system call */ struct timeb { time_t time; unsigned short millitm; short timezone; short dstflag; }; char buffer[256]; struct utmp x_utmp; #define PENDING_CNT 50 #define FIND_EMPTY 1 #define FIND_MATCH 2 static char *zentry[] = { "EMPTY", "RUN_LVL", "BOOT_TIME", "OLD_TIME", "NEW_TIME", "INIT_PROCESS", "LOGIN_PROCESS", "USER_PROCESS", "DEAD_PROCESS", "ACCOUNTING" }; typedef struct { short used; struct utmp log_wtmp; } PENDINGS; PENDINGS pendings[PENDING_CNT]; /* * argv[1] records to dump * argv[2] alternate wtmp formatted file */ main(argc,argv) int argc; char *argv[]; { int fd; int record=0; char wtmp_name[128]; int max_records=10000; int u_size = sizeof(x_utmp); int r_index; int cc; if (argc < 2) { record = atoi(argv[1]); if (!record) max_records = record; } if (argc < 3) strcpy(wtmp_name,WTMP_FILE); else strcpy(wtmp_name,argv[2]); /* * Open a wtmp formatted file */ if( !(fd= open(wtmp_name,O_RDONLY))) { fprintf(stderr,"error opening wtmp file (%s)\n",wtmp_name); exit(1); } memset (pendings,(char) 0,sizeof(pendings)); for (record = 0;;record++) { cc = read(fd,&x_utmp,u_size); if (!cc) break; strncpy(buffer,x_utmp.ut_name,8); buffer[8] = '\0'; switch(x_utmp.ut_type) { case DEAD_PROCESS: if (!findpend(FIND_MATCH,buffer,&r_index)) { /* * print completed entry */ pendings[r_index].used = 0; strncpy(buffer,pendings[r_index].log_wtmp.ut_name,8); buffer[8] = '\0'; printf ("%8s ",buffer); printtime(&pendings[r_index].log_wtmp.ut_time); printtime(&x_utmp.ut_time); printf(" total seconds %ld\n", x_utmp.ut_time-pendings[r_index].log_wtmp.ut_time); } break; case USER_PROCESS: if(!findpend(FIND_EMPTY,buffer,&r_index)) { /* * add entry to the pile */ pendings[r_index].used++; pendings[r_index].log_wtmp = x_utmp; } else { fprintf(stderr,"Too many pendings\n"); exit(1); } break; } } } /* * dump entry */ dumpentry(x_utmp) struct utmp *x_utmp; { char name[10]; char line[20]; strncpy(name,x_utmp->ut_name,8); name[8] = '\0'; strncpy (line,x_utmp->ut_line,12); line[12] = '\0'; printf ("[%8s] [%12s] %12s ",name,line,zentry[x_utmp->ut_type]); printtime(&x_utmp->ut_time); printf("\n"); } /* * print time entry */ printtime(time_entry) long *time_entry; { struct tm *tm; tm = localtime(time_entry); printf("%02d/%02d/%02d %02d:%02d:%02d ", tm->tm_mon+1,tm->tm_mday,tm->tm_year, tm->tm_hour,tm->tm_min,tm->tm_sec); } /* * Find a pending entry * * return zero on search success, -1 on failure * return_index will point to pending entry * */ int findpend(control,name,return_index) int control; char name[]; int *return_index; { int index; char buff[20]; strncpy(buff,name,8); buff[8]='\0'; for (index = 0; index < PENDING_CNT; index++) { if (control == FIND_EMPTY) { if (!pendings[index].used) { *return_index = index; return(0); } } else { if (!strncmp(pendings[index].log_wtmp.ut_name,name,8)) { *return_index = index; return(0); } } } return (-1); } ------------------------ program end--------------------------------------- DATE APPROVED: 05/08/95