Annotation of coherent/d/bin/ac.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.