|
|
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.