File: al_share.cpp

package info (click to toggle)
acct 6.5.4-2.1
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 3,132 kB
  • ctags: 1,428
  • sloc: sh: 10,390; ansic: 9,695; cpp: 289; makefile: 185
file content (466 lines) | stat: -rw-r--r-- 13,914 bytes parent folder | download
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
/* 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;
          (void) signal (SIGINT, handler);
#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));
              fprintf (stddebug, " -> %-24.24s)\n",
                       ctime ((time_t *) &(rec->ut_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
                       <miquels@drinkel.ow.org> 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
             <miquels@drinkel.ow.org> 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
            }
        }
    }
}