2 * Copyright (c) 2007 Diomidis Spinellis
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
33 #include <sys/types.h>
45 int readrec_forward(FILE *f
, struct acctv2
*av2
);
46 int readrec_backward(FILE *f
, struct acctv2
*av2
);
49 * Reverse offsetof: return the offset of field f
50 * from the end of the structure s.
52 #define roffsetof(s, f) (sizeof(s) - offsetof(s, f))
55 * Read exactly one record of size size from stream f into ptr.
56 * Failure to read the complete record is considered a file format error,
57 * and will set errno to EFTYPE.
58 * Return 0 on success, EOF on end of file or error.
61 fread_record(void *ptr
, size_t size
, FILE *f
)
65 if ((rv
= fread(ptr
, 1, size
, f
)) == size
)
67 else if (ferror(f
) || rv
== 0)
77 * Return the value of a comp_t field.
85 for (exp
= v
>> 13; exp
; exp
--)
87 return ((double)result
/ AHZV1
);
91 * Read a v1 accounting record stored at the current
92 * position of stream f.
93 * Convert the data to the current record format.
94 * Return EOF on error or end-of-file.
97 readrec_v1(FILE *f
, struct acctv2
*av2
)
102 if ((rv
= fread_record(&av1
, sizeof(av1
), f
)) == EOF
)
106 av2
->ac_len
= av2
->ac_len2
= sizeof(*av2
);
107 memcpy(av2
->ac_comm
, av1
.ac_comm
, AC_COMM_LEN
);
108 av2
->ac_utime
= decode_comp(av1
.ac_utime
) * 1000000;
109 av2
->ac_stime
= decode_comp(av1
.ac_stime
) * 1000000;
110 av2
->ac_etime
= decode_comp(av1
.ac_etime
) * 1000000;
111 av2
->ac_btime
= av1
.ac_btime
;
112 av2
->ac_uid
= av1
.ac_uid
;
113 av2
->ac_gid
= av1
.ac_gid
;
114 av2
->ac_mem
= av1
.ac_mem
;
115 av2
->ac_io
= decode_comp(av1
.ac_io
);
116 av2
->ac_tty
= av1
.ac_tty
;
117 av2
->ac_flagx
= av1
.ac_flag
| ANVER
;
122 * Read an v2 accounting record stored at the current
123 * position of stream f.
124 * Return EOF on error or end-of-file.
127 readrec_v2(FILE *f
, struct acctv2
*av2
)
129 return (fread_record(av2
, sizeof(*av2
), f
));
133 * Read a new-style (post-v1) accounting record stored at
134 * the current position of stream f.
135 * Convert the data to the current record format.
136 * Return EOF on error or end-of-file.
139 readrec_vx(FILE *f
, struct acctv2
*av2
)
141 uint8_t magic
, version
;
143 if (fread_record(&magic
, sizeof(magic
), f
) == EOF
||
144 fread_record(&version
, sizeof(version
), f
) == EOF
||
145 ungetc(version
, f
) == EOF
||
146 ungetc(magic
, f
) == EOF
)
150 return (readrec_v2(f
, av2
));
152 /* Add handling for more versions here. */
161 * Read an accounting record stored at the current
162 * position of stream f.
163 * Old-format records are converted to the current record
165 * Return the number of records read (1 or 0 at the end-of-file),
169 readrec_forward(FILE *f
, struct acctv2
*av2
)
173 if ((magic
= getc(f
)) == EOF
)
174 return (ferror(f
) ? EOF
: 0);
175 if (ungetc(magic
, f
) == EOF
)
178 /* Old record format. */
179 rv
= readrec_v1(f
, av2
);
181 /* New record formats. */
182 rv
= readrec_vx(f
, av2
);
183 return (rv
== EOF
? EOF
: 1);
187 * Read an accounting record ending at the current
188 * position of stream f.
189 * Old-format records are converted to the current record
191 * The file pointer is positioned at the beginning of the
193 * Return the number of records read (1 or 0 at the end-of-file),
197 readrec_backward(FILE *f
, struct acctv2
*av2
)
203 if ((pos
= ftell(f
)) == -1)
207 if (fseek(f
, -roffsetof(struct acctv2
, ac_trailer
),
209 (c
= getc(f
)) == EOF
)
212 /* New record formats. */
213 if (fseeko(f
, pos
- roffsetof(struct acctv2
, ac_len2
),
215 fread_record(&len
, sizeof(len
), f
) == EOF
||
216 fseeko(f
, pos
- len
, SEEK_SET
) == EOF
||
217 readrec_vx(f
, av2
) == EOF
||
218 fseeko(f
, pos
- len
, SEEK_SET
) == EOF
)
223 /* Old record format. */
224 if (fseeko(f
, pos
- sizeof(struct acctv1
), SEEK_SET
) == EOF
||
225 readrec_v1(f
, av2
) == EOF
||
226 fseeko(f
, pos
- sizeof(struct acctv1
), SEEK_SET
) == EOF
)