|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <utmp.h> ! 3: ! 4: struct utmp u, ulist[100], *ufreep = &ulist[0]; ! 5: ! 6: int boot = 0; /* set to 1 when a boot is encountered */ ! 7: ! 8: long t_final; /* end of a given period of up time */ ! 9: long t_old, t_new; /* login session start and stop times */ ! 10: ! 11: FILE *ufp; /* file pointer for wtmp file */ ! 12: ! 13: int argc; ! 14: char **argv; ! 15: ! 16: char *WTMP = "/usr/adm/wtmp"; ! 17: ! 18: struct { ! 19: char *flag; ! 20: char *title; ! 21: } spcl[] = { ! 22: "~", "Reboot", ! 23: "|", "Old time", ! 24: "{", "New time", ! 25: NULL, NULL, ! 26: }; ! 27: ! 28: struct utmp *lookup(); ! 29: char *ctime(), *strcpy(); ! 30: ! 31: main(ac, av) ! 32: int ac; ! 33: char **av; ! 34: { ! 35: argc = ac-1; ! 36: argv = av+1; ! 37: time(&t_final); ! 38: if ((ufp = fopen(WTMP, "r")) == NULL) { ! 39: fprintf(stderr, "log: cannot open %s\n", WTMP); ! 40: exit(1); ! 41: } ! 42: fseek(ufp, 0L, 2); ! 43: uscan(); ! 44: fclose(ufp); ! 45: exit(0); ! 46: } ! 47: ! 48: /* ! 49: * display info for current ufp ! 50: */ ! 51: uscan() ! 52: { ! 53: register char *q; ! 54: register int i; ! 55: ! 56: while (revread()) { ! 57: if (strcmp(u.ut_line, "~") == 0) { ! 58: boot = 1; ! 59: ufreep = &ulist[0]; ! 60: t_final = u.ut_time; ! 61: } ! 62: if (strcmp(u.ut_name, "") == 0) ! 63: *lookup() = u; ! 64: if (!okay()) ! 65: continue; ! 66: t_old = u.ut_time; ! 67: q = ctime(&t_old); ! 68: if (strcmp(u.ut_name, "") == 0) { ! 69: for (i = 0; spcl[i].flag; i++) ! 70: if (strcmp(spcl[i].flag, u.ut_line) == 0) ! 71: printf("%s: %s", spcl[i].title, q); ! 72: continue; ! 73: } else { ! 74: printf("%-8.8s%-8.8s%16.16s - ", ! 75: u.ut_name, u.ut_line, q); ! 76: t_new = lookup()->ut_time; ! 77: if (t_new == 0) { ! 78: t_new = t_final; ! 79: if (boot) ! 80: printf("boot "); ! 81: else ! 82: printf(" now "); ! 83: } ! 84: else ! 85: printf("%5.5s", 11+ctime(&t_new)); ! 86: printf(" ("); prelapse(t_new-t_old); printf(")\n"); ! 87: } ! 88: } ! 89: } ! 90: ! 91: /* ! 92: * print elapsed time ! 93: */ ! 94: ! 95: #define MINUTE (60L) ! 96: #define HOUR (60L * MINUTE) ! 97: #define DAY (24L * HOUR) ! 98: ! 99: prelapse(t) ! 100: long t; ! 101: { ! 102: register int days, hours, minutes; ! 103: ! 104: days = t/DAY; ! 105: t %= DAY; ! 106: hours = t/HOUR; ! 107: t %= HOUR; ! 108: minutes = t/MINUTE; ! 109: if (days) ! 110: printf("%d+", days); ! 111: printf("%d:%02d", hours, minutes); ! 112: } ! 113: ! 114: /* ! 115: * locate tty line entry in ulist; make one if necessary ! 116: */ ! 117: struct utmp * ! 118: lookup() ! 119: { ! 120: register struct utmp *p; ! 121: ! 122: for (p = &ulist[0]; p < ufreep; p++) ! 123: if (strcmp(p->ut_line, u.ut_line) == 0) ! 124: return(p); ! 125: if (p >= &ulist[sizeof(ulist)]) { ! 126: fprintf(stderr, "log: ulist overflow\n"); ! 127: exit(1); ! 128: } ! 129: ufreep++; ! 130: strcpy(p->ut_name, ""); ! 131: strcpy(p->ut_line, ""); ! 132: p->ut_time = 0L; ! 133: return(p); ! 134: } ! 135: ! 136: /* ! 137: * return 1 if this entry should be printed, else 0 ! 138: */ ! 139: okay() ! 140: { ! 141: register int count; ! 142: register char **pp; ! 143: ! 144: if (argc <= 0) ! 145: return(1); ! 146: for (count=argc, pp=argv; count>0; --count, pp++) { ! 147: if (strcmp(*pp, u.ut_line) == 0) ! 148: return(1); ! 149: if (strcmp(*pp, u.ut_name) == 0) ! 150: return(1); ! 151: } ! 152: return(0); ! 153: } ! 154: ! 155: /* ! 156: * buffered reverse read of next utmp entry. ! 157: */ ! 158: revread() ! 159: { ! 160: static struct utmp ubuf[100]; ! 161: static int nitems = 0; ! 162: long nbytes; ! 163: ! 164: if (nitems <= 0) { ! 165: fflush(stdout); ! 166: nbytes = ftell(ufp); ! 167: if (nbytes > sizeof(ubuf)) ! 168: nbytes = sizeof(ubuf); ! 169: nitems = nbytes / sizeof(ubuf[0]); ! 170: if (fseek(ufp, -nbytes, 1) == -1) ! 171: return(0); ! 172: if (fread(&ubuf[0], sizeof(ubuf[0]), nitems, ufp) != nitems) ! 173: return(0); ! 174: if (fseek(ufp, -nbytes, 1) == -1) ! 175: return(0); ! 176: } ! 177: if (--nitems < 0) ! 178: return(0); ! 179: u = ubuf[nitems]; ! 180: return(1); ! 181: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.