-
Notifications
You must be signed in to change notification settings - Fork 0
/
al_share.cpp
467 lines (385 loc) · 13.6 KB
/
al_share.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
/* al_share.cpp
*
* code shared between ac & last
*
* to get the code for last, #define BACKWARDS before #including this
* file.
*
*/
/* This is the loop that handles the parsing of entries. Since it's
virtually identical for ac & last, I figured it was better to have
only one copy of it to reduce the possiblity of errors. */
void parse_entries(void)
{
struct utmp *rec; /* the current record */
int expecting_clock = 0; /* set to a nonzero value if the next
entry is expected to be the second
half of a clock pair */
time_t clock_before = 0; /* the clock before the date cmd */
short first_time = 1;
/* loop while there are still entries to read... */
while ((rec = utmp_get_entry ()) != NULL)
{
/* Munge the record for those systems that have a bsd/sysv mix
of records. */
if (debugging_enabled)
{
(void)fprintf(stddebug, "---------------------------------------------------------------------------\nCURRENT REC: ");
print_utmp_record(rec, stddebug);
}
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
if (fix_ut_type_field (rec) && debugging_enabled)
{
(void)fprintf (stddebug, " MUNGED REC: ");
print_utmp_record (rec, stddebug);
}
#endif
/* Throw away obviously bad records. */
if (bad_utmp_record (rec))
{
if (print_file_problems)
{
utmp_print_file_and_line (stddebug);
(void)fprintf(stddebug, ": problem: bad record\n");
}
continue; /* skip it */
}
if (first_time)
{
first_time = 0;
#ifdef BACKWARDS
/* last: The first time through, we need to set up the
LAST_TIME variable correctly. We also set up the signal
handler here (rather than somewhere earlier) so we're
guaranteed to get a good value for LAST_TIME if the
program gets interrupted. */
last_time = rec->ut_time + 1;
sigact.sa_handler = handler;
(void) sigaction (SIGINT, &sigact, NULL);
#else
/* ac: if this is the first time, we need to set up
next_midnight correctly, so that do_totals will function
correctly. */
next_midnight = midnight_after_me (rec->ut_time);
#endif
}
#ifdef BACKWARDS
/* last: if the time of this record occurs AFTER the time of the
last record, there's something wrong. To deal with it, log
everyone in at the time of the record. Unfortunately, this
means that statistics cannot be collected for the users on
these ttys... Also, reset last_time so THIS check can be
made correctly. Similarly, if we see a huge jump forward in
time, there's something wrong. If we're being nasty, go
ahead and assign the time to the user. Otherwise, clear out
the list of logins. NOTE: the '|' entry is a special case,
so ignore it. */
if ((rec->RECORD_TYPE != NEW_TIME)
&& ((rec->ut_time - time_warp_leniency > last_time)
|| (rec->ut_time < last_time - time_warp_suspicious)))
#else
/* ac: if the time of this record occurs BEFORE the time of the
last record, there's something wrong. To deal with it, log
everyone out at the next midnight, doing the totals at that
time. Then reset NEXT_MIDNIGHT so the next do_totals call is
correct. Also, reset LAST_TIME so this check can be made
correctly. Similarly, if we see a huge jump forward in time,
there's something wrong. If we're being nasty, go ahead and
assign the time to the user. Otherwise, clear out the list
of logins. NOTE: the '{' entry is a special case, so ignore
it. */
if ((rec->RECORD_TYPE != NEW_TIME)
&& ((rec->ut_time + time_warp_leniency < last_time)
|| (rec->ut_time > last_time + time_warp_suspicious)))
#endif
{
if (print_file_problems)
{
utmp_print_file_and_line (stddebug);
(void)fprintf(stddebug, ": problem: time warp (%-24.24s",
ctime (&last_time));
time_t tmp_time = rec->ut_time;
fprintf (stddebug, " -> %-24.24s)\n", ctime (&tmp_time));
}
#ifdef BACKWARDS
/* last: update the event stuff */
last_time = rec->ut_time;
last_event = "warp";
log_everyone_in(rec->ut_time);
#else
/* ac: force an update to occur by passing two times which
are one second apart -- DO_TOTALS does it's thing if the
first argument is less than the second. */
do_totals (&next_midnight, next_midnight + 1,
nasty_time_warp, FALSE, "time warp");
/* Fix up NEXT_MIDNIGHT to reflect our new time base. */
next_midnight = midnight_after_me (rec->ut_time);
#endif
}
last_time = rec->ut_time; /* so we're ready to run next time */
#ifndef BACKWARDS
/* ac: if we're doing totals every midnight, we have to check
and see if the current record occurs past the next midnight.
If it does, print out the totals for the evening and
increment the NEXT_MIDNIGHT variable. Continue until the
record is before our midnight. */
if (rec->RECORD_TYPE != NEW_TIME)
do_totals (&next_midnight, (time_t) rec->ut_time,
TRUE, TRUE, "midnight logout");
#endif
/* Process each record, depending on its type. */
switch (rec->RECORD_TYPE)
{
#ifdef BACKWARDS
case OLD_TIME:
#else
case NEW_TIME:
#endif
/* Change the time if we've already seen the other half of
the date change command. */
if (expecting_clock)
{
#ifdef BACKWARDS
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
if (print_which_recs >= 1)
#endif
print_record(rec, 0, NULL, "old time", "");
#endif
update_system_time (rec->ut_time - clock_before);
expecting_clock = 0;
#ifndef BACKWARDS
next_midnight = midnight_after_me (rec->ut_time);
#endif
}
else if (print_file_problems)
{
utmp_print_file_and_line (stddebug);
fprintf (stddebug,
": problem: unpaired time record (ignored)\n");
#ifdef BACKWARDS
print_record(rec, 0, NULL, "old time", "");
#endif
}
break;
#ifdef BACKWARDS
case NEW_TIME:
#else
case OLD_TIME:
#endif
/* This is the first half of a time change that we should
see. */
#ifdef BACKWARDS
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
if (print_which_recs >= 1)
#endif
print_record(rec, 0, NULL, "new time", "");
#endif
expecting_clock = 1;
clock_before = rec->ut_time;
break;
case BOOT_TIME:
if (strncmp (rec->ut_name, "shutdown", NAME_LEN) == 0)
{
#if defined (HAVE_STRUCT_UTMP_UT_TYPE) && (defined (RUN_LVL) || defined (BACKWARDS))
do_shutdown:
#endif
#ifdef BACKWARDS
#ifdef HAVE_STRUCT_UTMP_UT_TYPE
if (print_which_recs >= 1)
#endif
print_record(rec, 0, NULL, "system down", "");
#if defined (HAVE_STRUCT_UTMP_UT_TYPE) && defined (RUN_LVL) && defined (__linux__)
do_shutdown_part_2:
#endif
last_event = "down";
last_event_time = rec->ut_time;
log_everyone_in(rec->ut_time);
#else /* ! BACKWARDS */
log_everyone_out(rec->ut_time, TRUE, FALSE, "shutdown");
#endif
}
else
{
#ifdef BACKWARDS
print_record(rec, 0, NULL, "system boot", "");
last_event = "crash";
last_event_time = rec->ut_time;
log_everyone_in(rec->ut_time);
#else
/* The system was rebooted at the given time, so we
don't know when it really went down. Let's be nice
to the users, and don't count the time against their
total time. Just clear the current logins! The
NASTY_REBOOT flag is put in for compatibility... */
log_everyone_out(rec->ut_time, nasty_reboot, FALSE, "reboot");
#endif
}
break;
/* Handle those types which simply print things out, rather
than linking up logins/logouts. */
#ifdef HAVE_STRUCT_UTMP_UT_TYPE /* just in case */
#ifdef RUN_LVL
case RUN_LVL:
/* This should be either "shutdown" (a special case) or a
runlevel change record. */
#ifdef BACKWARDS
if (strncmp (rec->ut_name, "shutdown", NAME_LEN) == 0)
goto do_shutdown;
else
{
#ifdef __linux__
/* The init program by Miquel van Smoorenburg
<[email protected]> writes its runlevel to the
UT_PID field. */
#ifdef HAVE_SNPRINTF
char s[13], lvl = rec->ut_pid & 255;
(void)snprintf(s, sizeof(s), "(to lvl %c)", lvl);
#else
char s[12], lvl = rec->ut_pid & 255;
(void)sprintf(s, "(to lvl %c)", lvl);
#endif
/* Note that this will print if we specify the `-x' flag
to be compatible with Debian. */
if (print_which_recs >= 1)
print_record(rec, 0, NULL, s, "");
if ((lvl == '0') || (lvl == '6'))
goto do_shutdown_part_2;
#else /* ! __linux__ */
if (print_which_recs >= 2)
print_record(rec, 0, NULL, NULL, "");
#endif /* ! __linux__ */
}
#else /* ! BACKWARDS */
if (strncmp (rec->ut_name, "shutdown", NAME_LEN) == 0)
goto do_shutdown;
#ifdef __linux__
/* The init program by Miquel van Smoorenburg
<[email protected]> writes its runlevel to the
UT_PID field. */
{
char lvl = rec->ut_pid & 255;
if ((lvl == '0') || (lvl == '6'))
goto do_shutdown;
}
#endif /* __linux__ */
/* Otherwise ignore this. */
#endif /* ! BACKWARDS */
break;
#endif
#ifdef LOGIN_PROCESS
/* This is a record written by the "login" program as it
waits for input on a particular tty. */
case LOGIN_PROCESS:
#ifdef BACKWARDS
if (print_which_recs >= 2)
print_record(rec, 0, "(login)", NULL, "");
#endif
break;
#endif
#ifdef INIT_PROCESS
/* This is a record written by the "init" program for things
other than run level changes. */
case INIT_PROCESS:
#ifdef BACKWARDS
if (print_which_recs >= 2)
print_record(rec, 0, "(init)", NULL, "");
#endif
break;
#endif
#ifdef ACCOUNTING
case ACCOUNTING:
#ifdef BACKWARDS
if (print_which_recs >= 2)
print_record(rec, 0, "(acct)", NULL, "");
#endif
break;
#endif
#ifdef EMPTY
case EMPTY:
#ifdef BACKWARDS
if (print_which_recs >= 2)
print_record(rec, 0, "(empty)", NULL, "");
#endif
break;
#endif
/* Handle those types which are counted as logins/logouts. */
#ifdef USER_PROCESS
/* A record written for a regular login. If the system
doesn't have DEAD_PROCESS, we might see a logout here, so
check UT_NAME. */
case USER_PROCESS:
if (rec->ut_name[0] == '\0')
#ifdef BACKWARDS
log_out(rec, FALSE);
#else
log_out(rec);
#endif
else
log_in(rec);
break;
#endif
#ifdef DEAD_PROCESS
/* A record written when a process exits -- ftpd, login, and
other things spawned by init. If the record has a tty,
try to log it out. Otherwise, it's a background
process and should be ignored. */
case DEAD_PROCESS:
if (rec->ut_line[0] != '\0')
#ifdef BACKWARDS
log_out(rec, FALSE);
#else
log_out(rec);
#endif
break;
#endif
#endif /* HAVE_STRUCT_UTMP_UT_TYPE */
/* FIXME: here we assume that unknown types are things that
are to be treated as logins/logouts in the BSD sense. If
this is incorrect behavior on some systems, #ifdefs
should be added above to handle the new values for the
UT_TYPE field. */
default:
if (rec->ut_line[0] == '\0')
{
if (print_file_problems)
{
utmp_print_file_and_line(stddebug);
(void)fprintf(stddebug, ": problem: empty record\n");
}
}
else
{
if (rec->ut_name[0] == '\0')
#ifdef BACKWARDS
log_out(rec, FALSE);
#else
log_out(rec);
#endif
else
log_in(rec);
}
break;
}
if (debugging_enabled)
{
struct hashtab_order ho;
struct hashtab_elem *he;
for (he = hashtab_first (login_table, &ho); he != NULL; he = hashtab_next(&ho))
{
char *ttyname = hashtab_get_key(he);
struct login_data *l = hashtab_get_value(he);
#ifdef BACKWARDS
(void)fprintf(stddebug, "**\t%-*.*s %s %s",
TTY_LEN, TTY_LEN, ttyname,
l->fake_entry ? "FAKE" : "real",
ctime(&(l->time)));
#else
(void)fprintf(stddebug, "**\t%-*.*s %-*.*s %s",
TTY_LEN, TTY_LEN, ttyname,
NAME_LEN, NAME_LEN, l->ut_name,
ctime(&(l->time)));
#endif
}
}
}
}