4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
30 #pragma ident "%Z%%M% %I% %E% SMI"
32 * acctcon1 [-p] [-t] [-l file] [-o file] <wtmpx-file >ctmp-file
33 * -p print input only, no processing
34 * -t test mode: use latest time found in input, rather than
35 * current time when computing times of lines still on
36 * (only way to get repeatable data from old files)
37 * -l file causes output of line usage summary
38 * -o file causes first/last/reboots report to be written to file
39 * reads input (normally /var/adm/wtmpx), produces
40 * list of sessions, sorted by ending time in ctmp.h/ascii format
41 * A_TSIZE is max # distinct ttys
44 #include <sys/types.h>
53 int a_tsize
= A_TSIZE
;
54 int tsize
= -1; /* used slots in tbuf table */
55 struct utmpx wb
; /* record structure read into */
56 struct ctmp cb
; /* record structure written out of */
59 char tline
[LSZ
]; /* /dev/... */
60 char tname
[NSZ
]; /* user name */
61 time_t ttime
; /* start time */
62 dev_t tdev
; /* device */
63 int tlsess
; /* # complete sessions */
64 int tlon
; /* # times on (ut_type of 7) */
65 int tloff
; /* # times off (ut_type != 7) */
66 long ttotal
; /* total time used on this line */
69 #define DATE_FMT "%a %b %e %H:%M:%S %Y\n"
72 char sname
[LSZ
]; /* reasons for ACCOUNTING records */
73 char snum
; /* number of times encountered */
76 time_t datetime
; /* old time if date changed, otherwise 0 */
79 int ndates
; /* number of times date changed */
86 static char time_buf
[50];
89 static size_t wread(void);
90 static int valid(void);
91 static void fixup(FILE *);
92 static void loop(void);
93 static void bootshut(void);
94 static int iline(void);
95 static void upall(void);
96 static void update(struct tbuf
*);
97 static void printrep(void);
98 static void printlin(void);
99 static void prctmp(struct ctmp
*);
102 main(int argc
, char **argv
)
104 char *prog
= argv
[0];
106 (void)setlocale(LC_ALL
, "");
107 while (--argc
> 0 && **++argv
== '-')
124 fprintf(stderr
, "usage: %s [-p] [-t] [-l lineuse] [-o reboot]\n", prog
);
129 if ((tbuf
= (struct tbuf
*) calloc(a_tsize
,
130 sizeof (struct tbuf
))) == NULL
) {
131 fprintf(stderr
, "acctcon1: Cannot allocate memory\n");
138 printf("%.*s\t%.*s\t%lu",
144 cftime(time_buf
, DATE_FMT
, &wb
.ut_xtime
);
145 printf("\t%s", time_buf
);
155 firstime
= wb
.ut_xtime
;
161 wb
.ut_name
[0] = '\0';
162 strcpy(wb
.ut_line
, "acctcon1");
163 wb
.ut_type
= ACCOUNTING
;
165 wb
.ut_xtime
= lastime
;
179 return (fread(&wb
, sizeof(wb
), 1, stdin
) == 1);
184 * valid: check input wtmp record, return 1 if looks OK
191 /* XPG say that user names should not start with a "-". */
192 if ((c
= wb
.ut_name
[0]) == '-')
195 for (i
= 0; i
< NSZ
; i
++) {
197 if (isalnum(c
) || c
== '$' || c
== ' ' || c
== '_' || c
== '-')
205 if((wb
.ut_type
>= EMPTY
) && (wb
.ut_type
<= UTMAXTYPE
))
212 * fixup assumes that V6 wtmp (16 bytes long) is mixed in with
213 * V7 records (20 bytes each)
215 * Starting with Release 5.0 of UNIX, this routine will no
216 * longer reset the read pointer. This has a snowball effect
217 * On the following records until the offset corrects itself.
218 * If a message is printed from here, it should be regarded as
219 * a bad record and not as a V6 record.
224 fprintf(stream
, "bad wtmpx: offset %lu.\n", ftell(stdin
)-sizeof(wb
));
225 fprintf(stream
, "bad record is: %.*s\t%.*s\t%lu",
231 cftime(time_buf
, DATE_FMT
, &wb
.ut_xtime
);
232 fprintf(stream
, "\t%s", time_buf
);
234 fseek(stdin
, (long)-4, 1);
245 if(wb
.ut_line
[0] == '\0' ) /* It's an init admin process */
246 return; /* no connect accounting data here */
249 datetime
= wb
.ut_xtime
;
254 timediff
= wb
.ut_xtime
- datetime
;
255 for (tp
= tbuf
; tp
<= &tbuf
[tsize
]; tp
++)
256 tp
->ttime
+= timediff
;
264 lastime
= wb
.ut_xtime
;
271 update(&tbuf
[iline()]);
276 cftime(time_buf
, DATE_FMT
, &wb
.ut_xtime
);
277 fprintf(stderr
, "acctcon1: invalid type %d for %s %s %s",
286 * bootshut: record reboot (or shutdown)
287 * bump count, looking up wb.ut_line in sy table
294 for (i
= 0; i
< nsys
&& !EQN(wb
.ut_line
, sy
[i
].sname
); i
++)
299 "acctcon1: recompile with larger NSYS\n");
303 CPYN(sy
[i
].sname
, wb
.ut_line
);
309 * iline: look up/enter current line name in tbuf, return index
310 * (used to avoid system dependencies on naming)
317 for (i
= 0; i
<= tsize
; i
++)
318 if (EQN(wb
.ut_line
, tbuf
[i
].tline
))
320 if (++tsize
>= a_tsize
) {
321 a_tsize
= a_tsize
+ A_TSIZE
;
322 if ((tbuf
= reallocarray(tbuf
, a_tsize
,
323 sizeof (struct tbuf
))) == NULL
) {
324 fprintf(stderr
, "acctcon1: Cannot reallocate memory\n");
329 CPYN(tbuf
[tsize
].tline
, wb
.ut_line
);
330 tbuf
[tsize
].tdev
= lintodev(wb
.ut_line
);
339 wb
.ut_type
= INIT_PROCESS
; /* fudge a logoff for reboot record */
340 for (tp
= tbuf
; tp
<= &tbuf
[tsize
]; tp
++)
345 * update tbuf with new time, write ctmp record for end of session
348 update(struct tbuf
*tp
)
350 time_t told
, /* last time for tbuf record */
351 tnew
; /* time of this record */
352 /* Difference is connect time */
356 cftime(time_buf
, DATE_FMT
, &told
);
357 fprintf(stderr
, "The old time is: %s", time_buf
);
358 cftime(time_buf
, DATE_FMT
, &tnew
);
359 fprintf(stderr
, "the new time is: %s", time_buf
);
361 cftime(time_buf
, DATE_FMT
, &told
);
362 fprintf(stderr
, "acctcon1: bad times: old: %s", time_buf
);
363 cftime(time_buf
, DATE_FMT
, &tnew
);
364 fprintf(stderr
, "new: %s", time_buf
);
373 if(tp
->tname
[0] != '\0') { /* Someone logged in without */
374 /* logging off. Put out record. */
375 cb
.ct_tty
= tp
->tdev
;
376 CPYN(cb
.ct_name
, tp
->tname
);
377 cb
.ct_uid
= namtouid(cb
.ct_name
);
379 if (pnpsplit(cb
.ct_start
, (ulong_t
)(tnew
-told
),
381 fprintf(stderr
, "acctcon1: could not calculate prime/non-prime hours\n");
386 tp
->ttotal
+= tnew
-told
;
388 else /* Someone just logged in */
390 CPYN(tp
->tname
, wb
.ut_name
);
396 if(tp
->tname
[0] != '\0') { /* Someone logged off */
397 /* Set up and print ctmp record */
398 cb
.ct_tty
= tp
->tdev
;
399 CPYN(cb
.ct_name
, tp
->tname
);
400 cb
.ct_uid
= namtouid(cb
.ct_name
);
402 if (pnpsplit(cb
.ct_start
, (ulong_t
)(tnew
-told
),
404 fprintf(stderr
, "acctcon1: could not calculate prime/non-prime hours\n");
408 tp
->ttotal
+= tnew
-told
;
419 freopen(report
, "w", stdout
);
420 cftime(time_buf
, DATE_FMT
, &firstime
);
421 printf("from %s", time_buf
);
422 cftime(time_buf
, DATE_FMT
, &lastime
);
423 printf("to %s", time_buf
);
425 printf("%d\tdate change%c\n",ndates
,(ndates
>1 ? 's' : '\0'));
426 for (i
= 0; i
< nsys
; i
++)
427 printf("%d\t%.*s\n", sy
[i
].snum
,
428 sizeof (sy
[i
].sname
), sy
[i
].sname
);
432 * print summary of line usage
433 * accuracy only guaranteed for wtmpx file started fresh
441 int tsess
, ton
, toff
;
443 freopen(replin
, "w", stdout
);
445 tsess
= ton
= toff
= 0;
446 timet
= MINS(lastime
-firstime
);
447 printf("TOTAL DURATION IS %.0f MINUTES\n", timet
);
448 printf("LINE MINUTES PERCENT # SESS # ON # OFF\n");
449 for (tp
= tbuf
; tp
<= &tbuf
[tsize
]; tp
++) {
450 timei
= MINS(tp
->ttotal
);
455 printf("%-*.*s %-7.0f %-7.0f %-6d %-4d %-5d\n",
460 (timet
> 0.)? 100*timei
/timet
: 0.,
465 printf("TOTALS %-7.0f -- %-6d %-4d %-5d\n",
466 ttime
, tsess
, ton
, toff
);
470 prctmp(struct ctmp
*t
)
473 printf("%u\t%ld\t%.*s\t%lu\t%lu\t%lu",
481 cftime(time_buf
, DATE_FMT
, &t
->ct_start
);
482 printf("\t%s", time_buf
);