|
|
1.1 ! root 1: /* ! 2: * AC ! 3: * Login connect-time accounting. ! 4: */ ! 5: ! 6: #include <stdio.h> ! 7: #include <ctype.h> ! 8: #include <utmp.h> ! 9: #include <time.h> ! 10: ! 11: #define DAYSEC (24*60*60L) /* Seconds in a day */ ! 12: #define HOUR (60*60) /* Seconds in hour */ ! 13: ! 14: char *wtmpf = "/usr/adm/wtmp"; ! 15: char *months[] = { ! 16: "January", "February", "March", "April", "May", "June", ! 17: "July", "August", "September", "October", "November", "December", ! 18: }; ! 19: ! 20: char *days[] = { ! 21: "Sunday", "Monday", "Tuesday", "Wednesday", ! 22: "Thursday", "Friday", "Saturday" ! 23: }; ! 24: char **plist; /* List of do-only people */ ! 25: ! 26: typedef struct TERM { ! 27: struct TERM *t_next; ! 28: char t_line[8]; ! 29: char t_name[DIRSIZ]; ! 30: time_t t_time; ! 31: } TERM; ! 32: ! 33: TERM *terminals; ! 34: ! 35: typedef struct PEOPLE { ! 36: struct PEOPLE *p_next; ! 37: char p_name[DIRSIZ]; ! 38: time_t p_time; ! 39: } PEOPLE; ! 40: ! 41: PEOPLE *people; ! 42: ! 43: time_t lasttime; /* Last time read from file */ ! 44: time_t runtotal; /* Running total used by ac -d */ ! 45: time_t midnight; /* Time of next midnight */ ! 46: ! 47: int dflag; /* Daily version (midnight-midnight) */ ! 48: int pflag; /* Print totals by people */ ! 49: int badflag; /* Possible bad file format */ ! 50: ! 51: main(argc, argv) ! 52: char *argv[]; ! 53: { ! 54: register char *ap; ! 55: ! 56: while (argc>1 && *argv[1]=='-') { ! 57: for (ap = &argv[1][1]; *ap != '\0'; ap++) ! 58: switch (*ap) { ! 59: case 'd': ! 60: dflag = 1; ! 61: break; ! 62: ! 63: case 'p': ! 64: pflag = 1; ! 65: break; ! 66: ! 67: ! 68: case 'w': ! 69: if (argc < 2) ! 70: usage(); ! 71: wtmpf = argv[2]; ! 72: argv++; ! 73: argc--; ! 74: break; ! 75: ! 76: default: ! 77: usage(); ! 78: } ! 79: argv++; ! 80: argc--; ! 81: } ! 82: plist = argv+1; ! 83: readwtmp(); ! 84: print(0); ! 85: if (badflag) ! 86: acerr("possible bad file format"); ! 87: exit(0); ! 88: } ! 89: ! 90: /* ! 91: * Read through the wtmp file keeping track of ! 92: * each individual user. At the end either print total ! 93: * or by individual people. ! 94: */ ! 95: readwtmp() ! 96: { ! 97: struct utmp ut; ! 98: register struct tm *tmp; ! 99: register TERM *tp; ! 100: register FILE *fp; ! 101: time_t tdelta; ! 102: ! 103: if ((fp = fopen(wtmpf, "r")) == NULL) { ! 104: fprintf(stderr, "ac: cannot open %s\n", wtmpf); ! 105: exit(1); ! 106: } ! 107: while (fread(&ut, sizeof ut, 1, fp) == 1) { ! 108: if (dflag && midnight==0) { ! 109: tmp = localtime(&ut.ut_time); ! 110: midnight = ut.ut_time - tmp->tm_sec ! 111: - tmp->tm_min*60 - tmp->tm_hour*60*60L + DAYSEC; ! 112: } else while (dflag && lasttime>=midnight) { ! 113: atmidnight(); ! 114: print(1); ! 115: midnight += DAYSEC; ! 116: } ! 117: if (ut.ut_line[1] == '\0') ! 118: switch (ut.ut_line[0]) { ! 119: case '~': /* Reboot */ ! 120: lasttime = ut.ut_time; ! 121: logout(NULL); ! 122: continue; ! 123: ! 124: case '|': /* Old time */ ! 125: tdelta = ut.ut_time; ! 126: continue; ! 127: ! 128: case '}': /* New time */ ! 129: tdelta = ut.ut_time-tdelta; ! 130: lasttime = ut.ut_time; ! 131: for (tp = terminals; tp!=NULL; tp = tp->t_next) ! 132: tp->t_time += tdelta; ! 133: continue; ! 134: } ! 135: if (ut.ut_time < lasttime) { ! 136: if (lasttime-ut.ut_time > 60) { ! 137: badflag++; ! 138: continue; ! 139: } ! 140: ut.ut_time = lasttime; ! 141: } else ! 142: lasttime = ut.ut_time; ! 143: logout(&ut); ! 144: if (ut.ut_name[0] != '\0') ! 145: login(&ut); ! 146: } ! 147: fclose(fp); ! 148: time(&lasttime); ! 149: logout(NULL); ! 150: } ! 151: ! 152: /* ! 153: * Mark a user as logged out. ! 154: * The user is given by the tty-name ! 155: * found in the utmp structure pointer. ! 156: * If this pointer is NULL, log all users ! 157: * out (e.g. at reboot and end of file). ! 158: */ ! 159: logout(utp) ! 160: register struct utmp *utp; ! 161: { ! 162: register TERM *tp, *ptp; ! 163: ! 164: loop: ! 165: if (terminals == NULL) ! 166: return; ! 167: ptp = NULL; ! 168: for (tp=terminals; tp != NULL; ptp=tp, tp=tp->t_next) ! 169: if (utp==NULL || strncmp(tp->t_line, utp->ut_line, 8)==0) { ! 170: if (ptp == NULL) ! 171: terminals = tp->t_next; else ! 172: ptp->t_next = tp->t_next; ! 173: tp->t_time = (utp==NULL ? lasttime : utp->ut_time) ! 174: - tp->t_time; ! 175: enter(tp); ! 176: free((char *)tp); ! 177: if (utp != NULL) ! 178: return; ! 179: goto loop; ! 180: } ! 181: } ! 182: ! 183: /* ! 184: * Log the times recorded for the terminals by ! 185: * midnight of the current day. ! 186: */ ! 187: atmidnight() ! 188: { ! 189: register TERM *tp; ! 190: ! 191: for (tp = terminals; tp != NULL; tp = tp->t_next) { ! 192: if (tp->t_time < midnight) { ! 193: tp->t_time = midnight-tp->t_time; ! 194: enter(tp); ! 195: tp->t_time = midnight; ! 196: } ! 197: } ! 198: } ! 199: ! 200: /* ! 201: * Mark the user found on this terminal ! 202: * as logged in. ! 203: */ ! 204: login(utp) ! 205: register struct utmp *utp; ! 206: { ! 207: register TERM *tp; ! 208: register char *np; ! 209: ! 210: for (np = utp->ut_name; *np != '\0'; np++) ! 211: if (!isascii(*np) || !isprint(*np)) { ! 212: badflag++; ! 213: lasttime = 0; ! 214: return; ! 215: } ! 216: for (np = utp->ut_line; *np != '\0'; np++) ! 217: if (!isascii(*np) || (!isalpha(*np) && !isdigit(*np))) { ! 218: badflag++; ! 219: lasttime = 0; ! 220: return; ! 221: } ! 222: if (*plist != NULL) { ! 223: register char **plp; ! 224: ! 225: for (plp = plist; *plp != NULL; plp++) ! 226: if (**plp == *utp->ut_name ! 227: && strncmp(*plp, utp->ut_name, DIRSIZ)==0) ! 228: break; ! 229: if (*plp == NULL) ! 230: return; ! 231: } ! 232: if ((tp = (TERM*)malloc(sizeof(TERM)))==NULL) ! 233: acerr("Out of memory for terminals"); ! 234: tp->t_time = utp->ut_time; ! 235: strncpy(tp->t_name, utp->ut_name, DIRSIZ); ! 236: strncpy(tp->t_line, utp->ut_line, 8); ! 237: tp->t_next = terminals; ! 238: terminals = tp; ! 239: } ! 240: ! 241: /* ! 242: * Enter a terminal node into the people table. ! 243: */ ! 244: enter(tp) ! 245: register TERM *tp; ! 246: { ! 247: register PEOPLE *pp; ! 248: ! 249: if (tp->t_name[0] == '\0') ! 250: return; ! 251: for (pp = people; pp != NULL; pp = pp->p_next) ! 252: if (strncmp(tp->t_name, pp->p_name, DIRSIZ) == 0) { ! 253: pp->p_time += tp->t_time; ! 254: return; ! 255: } ! 256: if ((pp = (PEOPLE *)malloc(sizeof(PEOPLE))) == NULL) ! 257: acerr("Out of memory for people"); ! 258: pp->p_next = people; ! 259: people = pp; ! 260: pp->p_time = tp->t_time; ! 261: strncpy(pp->p_name, tp->t_name, DIRSIZ); ! 262: } ! 263: ! 264: /* ! 265: * Print the results, depending on the flags. ! 266: * The `flag' says whether print is called at the ! 267: * end (0) or for each midnight-midnight period (1). ! 268: */ ! 269: print(flag) ! 270: int flag; ! 271: { ! 272: register struct tm *tmp; ! 273: register PEOPLE *pp; ! 274: time_t total = 0; ! 275: ! 276: if (dflag) { ! 277: time_t endofday; ! 278: ! 279: endofday = midnight-2*HOUR; ! 280: tmp = localtime(&endofday); ! 281: printf("%s %s %d:\n", days[tmp->tm_wday], months[tmp->tm_mon], ! 282: tmp->tm_mday); ! 283: } ! 284: for (pp = people; pp != NULL; pp = pp->p_next) { ! 285: if (pp->p_time > 0) { ! 286: total += pp->p_time; ! 287: if (pflag) ! 288: prtime(pp->p_name, pp->p_time); ! 289: } ! 290: if (flag) ! 291: pp->p_time = 0; ! 292: } ! 293: runtotal += total; ! 294: prtime("Total:", total); ! 295: if (dflag) { ! 296: printf("\n"); ! 297: if (flag == 0) { ! 298: dflag = 0; ! 299: prtime("Total:", runtotal); ! 300: } ! 301: } ! 302: } ! 303: ! 304: /* ! 305: * Print a time entry with a name. ! 306: */ ! 307: prtime(name, time) ! 308: char *name; ! 309: time_t time; ! 310: { ! 311: if (dflag) ! 312: printf("\t"); ! 313: printf("%-*.*s", DIRSIZ, DIRSIZ, name); ! 314: time = (time+30)/60; ! 315: printf("%3ld:%02ld\n", time/60, time%60); ! 316: } ! 317: ! 318: /* ! 319: * Error reporting. ! 320: */ ! 321: /* VARARGS */ ! 322: acerr(x) ! 323: { ! 324: fprintf(stderr, "ac: %r\n", &x); ! 325: exit(1); ! 326: } ! 327: ! 328: usage() ! 329: { ! 330: fprintf(stderr, "Usage: ac [-w wtmpfile] [-d] [-p] [username ...]\n"); ! 331: exit(1); ! 332: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.