2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2007 Diomidis Spinellis
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/param.h>
32 #include <sys/types.h>
40 int readrec_forward(FILE *f
, struct acctv3
*av2
);
41 int readrec_backward(FILE *f
, struct acctv3
*av2
);
44 * Reverse offsetof: return the offset of field f
45 * from the end of the structure s.
47 #define roffsetof(s, f) (sizeof(s) - offsetof(s, f))
50 * Read exactly one record of size size from stream f into ptr.
51 * Failure to read the complete record is considered a file format error,
52 * and will set errno to EFTYPE.
53 * Return 0 on success, EOF on end of file or error.
56 fread_record(void *ptr
, size_t size
, FILE *f
)
60 if ((rv
= fread(ptr
, 1, size
, f
)) == size
)
62 else if (ferror(f
) || rv
== 0)
72 * Return the value of a comp_t field.
80 for (exp
= v
>> 13; exp
; exp
--)
82 return ((double)result
/ AHZV1
);
86 * Read a v1 accounting record stored at the current
87 * position of stream f.
88 * Convert the data to the current record format.
89 * Return EOF on error or end-of-file.
92 readrec_v1(FILE *f
, struct acctv3
*av3
)
97 if ((rv
= fread_record(&av1
, sizeof(av1
), f
)) == EOF
)
101 av3
->ac_len
= av3
->ac_len2
= sizeof(*av3
);
102 memcpy(av3
->ac_comm
, av1
.ac_comm
, AC_COMM_LEN
);
103 av3
->ac_utime
= decode_comp(av1
.ac_utime
) * 1000000;
104 av3
->ac_stime
= decode_comp(av1
.ac_stime
) * 1000000;
105 av3
->ac_etime
= decode_comp(av1
.ac_etime
) * 1000000;
106 av3
->ac_btime
= av1
.ac_btime
;
107 av3
->ac_uid
= av1
.ac_uid
;
108 av3
->ac_gid
= av1
.ac_gid
;
109 av3
->ac_mem
= av1
.ac_mem
;
110 av3
->ac_io
= decode_comp(av1
.ac_io
);
111 av3
->ac_tty
= av1
.ac_tty
;
112 av3
->ac_flagx
= av1
.ac_flag
| ANVER
;
117 * Read an v2 accounting record stored at the current
118 * position of stream f.
119 * Return EOF on error or end-of-file.
122 readrec_v2(FILE *f
, struct acctv3
*av3
)
127 if ((rv
= fread_record(&av2
, sizeof(av2
), f
)) == EOF
)
131 av3
->ac_len
= av3
->ac_len2
= sizeof(*av3
);
132 memcpy(av3
->ac_comm
, av2
.ac_comm
, AC_COMM_LEN
);
133 av3
->ac_utime
= av2
.ac_utime
;
134 av3
->ac_stime
= av2
.ac_stime
;
135 av3
->ac_etime
= av2
.ac_etime
;
136 av3
->ac_btime
= av2
.ac_btime
;
137 av3
->ac_uid
= av2
.ac_uid
;
138 av3
->ac_gid
= av2
.ac_gid
;
139 av3
->ac_mem
= av2
.ac_mem
;
140 av3
->ac_io
= av2
.ac_io
;
141 av3
->ac_tty
= av2
.ac_tty
;
142 av3
->ac_flagx
= av2
.ac_flagx
;
147 * Read an v2 accounting record stored at the current
148 * position of stream f.
149 * Return EOF on error or end-of-file.
152 readrec_v3(FILE *f
, struct acctv3
*av3
)
155 return (fread_record(av3
, sizeof(*av3
), f
));
159 * Read a new-style (post-v1) accounting record stored at
160 * the current position of stream f.
161 * Convert the data to the current record format.
162 * Return EOF on error or end-of-file.
165 readrec_vx(FILE *f
, struct acctv3
*av3
)
167 uint8_t magic
, version
;
169 if (fread_record(&magic
, sizeof(magic
), f
) == EOF
||
170 fread_record(&version
, sizeof(version
), f
) == EOF
||
171 ungetc(version
, f
) == EOF
||
172 ungetc(magic
, f
) == EOF
)
176 return (readrec_v2(f
, av3
));
178 return (readrec_v3(f
, av3
));
180 /* Add handling for more versions here. */
189 * Read an accounting record stored at the current
190 * position of stream f.
191 * Old-format records are converted to the current record
193 * Return the number of records read (1 or 0 at the end-of-file),
197 readrec_forward(FILE *f
, struct acctv3
*av3
)
201 if ((magic
= getc(f
)) == EOF
)
202 return (ferror(f
) ? EOF
: 0);
203 if (ungetc(magic
, f
) == EOF
)
206 /* Old record format. */
207 rv
= readrec_v1(f
, av3
);
209 /* New record formats. */
210 rv
= readrec_vx(f
, av3
);
211 return (rv
== EOF
? EOF
: 1);
215 * Read an accounting record ending at the current
216 * position of stream f.
217 * Old-format records are converted to the current record
219 * The file pointer is positioned at the beginning of the
221 * Return the number of records read (1 or 0 at the end-of-file),
225 readrec_backward(FILE *f
, struct acctv3
*av3
)
231 if ((pos
= ftell(f
)) == -1)
235 if (fseek(f
, -roffsetof(struct acctv3
, ac_trailer
),
237 (c
= getc(f
)) == EOF
)
241 * New record formats. For v2 and v3 offset from the
242 * end for ac_len2 should be same.
244 if (fseeko(f
, pos
- roffsetof(struct acctv2
, ac_len2
),
246 fread_record(&len
, sizeof(len
), f
) == EOF
||
247 fseeko(f
, pos
- len
, SEEK_SET
) == EOF
||
248 readrec_vx(f
, av3
) == EOF
||
249 fseeko(f
, pos
- len
, SEEK_SET
) == EOF
)
254 /* Old record format. */
255 if (fseeko(f
, pos
- sizeof(struct acctv1
), SEEK_SET
) == EOF
||
256 readrec_v1(f
, av3
) == EOF
||
257 fseeko(f
, pos
- sizeof(struct acctv1
), SEEK_SET
) == EOF
)