1fdbe5babSDiomidis Spinellis /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4fdbe5babSDiomidis Spinellis * Copyright (c) 2007 Diomidis Spinellis 5fdbe5babSDiomidis Spinellis * All rights reserved. 6fdbe5babSDiomidis Spinellis * 7fdbe5babSDiomidis Spinellis * Redistribution and use in source and binary forms, with or without 8fdbe5babSDiomidis Spinellis * modification, are permitted provided that the following conditions 9fdbe5babSDiomidis Spinellis * are met: 10fdbe5babSDiomidis Spinellis * 1. Redistributions of source code must retain the above copyright 11fdbe5babSDiomidis Spinellis * notice, this list of conditions and the following disclaimer. 12fdbe5babSDiomidis Spinellis * 2. Redistributions in binary form must reproduce the above copyright 13fdbe5babSDiomidis Spinellis * notice, this list of conditions and the following disclaimer in the 14fdbe5babSDiomidis Spinellis * documentation and/or other materials provided with the distribution. 15fdbe5babSDiomidis Spinellis * 16fdbe5babSDiomidis Spinellis * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17fdbe5babSDiomidis Spinellis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18fdbe5babSDiomidis Spinellis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19fdbe5babSDiomidis Spinellis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20fdbe5babSDiomidis Spinellis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21fdbe5babSDiomidis Spinellis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22fdbe5babSDiomidis Spinellis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23fdbe5babSDiomidis Spinellis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24fdbe5babSDiomidis Spinellis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25fdbe5babSDiomidis Spinellis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26fdbe5babSDiomidis Spinellis * SUCH DAMAGE. 27fdbe5babSDiomidis Spinellis * 28fdbe5babSDiomidis Spinellis */ 29fdbe5babSDiomidis Spinellis 30fdbe5babSDiomidis Spinellis #include <sys/cdefs.h> 31fdbe5babSDiomidis Spinellis __FBSDID("$FreeBSD$"); 32fdbe5babSDiomidis Spinellis 33fdbe5babSDiomidis Spinellis #include <sys/param.h> 34fdbe5babSDiomidis Spinellis #include <sys/stat.h> 35fdbe5babSDiomidis Spinellis #include <sys/types.h> 36fdbe5babSDiomidis Spinellis #include <sys/acct.h> 37fdbe5babSDiomidis Spinellis 38fdbe5babSDiomidis Spinellis #include <errno.h> 39fdbe5babSDiomidis Spinellis #include <stddef.h> 40fdbe5babSDiomidis Spinellis #include <stdio.h> 41fdbe5babSDiomidis Spinellis #include <string.h> 42fdbe5babSDiomidis Spinellis 4369921123SKonstantin Belousov int readrec_forward(FILE *f, struct acctv3 *av2); 4469921123SKonstantin Belousov int readrec_backward(FILE *f, struct acctv3 *av2); 45fdbe5babSDiomidis Spinellis 46fdbe5babSDiomidis Spinellis /* 47fdbe5babSDiomidis Spinellis * Reverse offsetof: return the offset of field f 48fdbe5babSDiomidis Spinellis * from the end of the structure s. 49fdbe5babSDiomidis Spinellis */ 50fdbe5babSDiomidis Spinellis #define roffsetof(s, f) (sizeof(s) - offsetof(s, f)) 51fdbe5babSDiomidis Spinellis 52fdbe5babSDiomidis Spinellis /* 53fdbe5babSDiomidis Spinellis * Read exactly one record of size size from stream f into ptr. 54fdbe5babSDiomidis Spinellis * Failure to read the complete record is considered a file format error, 55fdbe5babSDiomidis Spinellis * and will set errno to EFTYPE. 56fdbe5babSDiomidis Spinellis * Return 0 on success, EOF on end of file or error. 57fdbe5babSDiomidis Spinellis */ 58fdbe5babSDiomidis Spinellis static int 59fdbe5babSDiomidis Spinellis fread_record(void *ptr, size_t size, FILE *f) 60fdbe5babSDiomidis Spinellis { 61fdbe5babSDiomidis Spinellis size_t rv; 62fdbe5babSDiomidis Spinellis 63fdbe5babSDiomidis Spinellis if ((rv = fread(ptr, 1, size, f)) == size) 64fdbe5babSDiomidis Spinellis return (0); 65fdbe5babSDiomidis Spinellis else if (ferror(f) || rv == 0) 66fdbe5babSDiomidis Spinellis return (EOF); 67fdbe5babSDiomidis Spinellis else { 68fdbe5babSDiomidis Spinellis /* Short read. */ 69fdbe5babSDiomidis Spinellis errno = EFTYPE; 70fdbe5babSDiomidis Spinellis return (EOF); 71fdbe5babSDiomidis Spinellis } 72fdbe5babSDiomidis Spinellis } 73fdbe5babSDiomidis Spinellis 74fdbe5babSDiomidis Spinellis /* 75fdbe5babSDiomidis Spinellis * Return the value of a comp_t field. 76fdbe5babSDiomidis Spinellis */ 77fdbe5babSDiomidis Spinellis static float 78fdbe5babSDiomidis Spinellis decode_comp(comp_t v) 79fdbe5babSDiomidis Spinellis { 80fdbe5babSDiomidis Spinellis int result, exp; 81fdbe5babSDiomidis Spinellis 82fdbe5babSDiomidis Spinellis result = v & 017777; 83fdbe5babSDiomidis Spinellis for (exp = v >> 13; exp; exp--) 84fdbe5babSDiomidis Spinellis result <<= 3; 85fdbe5babSDiomidis Spinellis return ((double)result / AHZV1); 86fdbe5babSDiomidis Spinellis } 87fdbe5babSDiomidis Spinellis 88fdbe5babSDiomidis Spinellis /* 89fdbe5babSDiomidis Spinellis * Read a v1 accounting record stored at the current 90fdbe5babSDiomidis Spinellis * position of stream f. 91fdbe5babSDiomidis Spinellis * Convert the data to the current record format. 92fdbe5babSDiomidis Spinellis * Return EOF on error or end-of-file. 93fdbe5babSDiomidis Spinellis */ 94fdbe5babSDiomidis Spinellis static int 9569921123SKonstantin Belousov readrec_v1(FILE *f, struct acctv3 *av3) 96fdbe5babSDiomidis Spinellis { 97fdbe5babSDiomidis Spinellis struct acctv1 av1; 98fdbe5babSDiomidis Spinellis int rv; 99fdbe5babSDiomidis Spinellis 100fdbe5babSDiomidis Spinellis if ((rv = fread_record(&av1, sizeof(av1), f)) == EOF) 101fdbe5babSDiomidis Spinellis return (EOF); 10269921123SKonstantin Belousov av3->ac_zero = 0; 10369921123SKonstantin Belousov av3->ac_version = 3; 10469921123SKonstantin Belousov av3->ac_len = av3->ac_len2 = sizeof(*av3); 10569921123SKonstantin Belousov memcpy(av3->ac_comm, av1.ac_comm, AC_COMM_LEN); 10669921123SKonstantin Belousov av3->ac_utime = decode_comp(av1.ac_utime) * 1000000; 10769921123SKonstantin Belousov av3->ac_stime = decode_comp(av1.ac_stime) * 1000000; 10869921123SKonstantin Belousov av3->ac_etime = decode_comp(av1.ac_etime) * 1000000; 10969921123SKonstantin Belousov av3->ac_btime = av1.ac_btime; 11069921123SKonstantin Belousov av3->ac_uid = av1.ac_uid; 11169921123SKonstantin Belousov av3->ac_gid = av1.ac_gid; 11269921123SKonstantin Belousov av3->ac_mem = av1.ac_mem; 11369921123SKonstantin Belousov av3->ac_io = decode_comp(av1.ac_io); 11469921123SKonstantin Belousov av3->ac_tty = av1.ac_tty; 11569921123SKonstantin Belousov av3->ac_flagx = av1.ac_flag | ANVER; 116fdbe5babSDiomidis Spinellis return (0); 117fdbe5babSDiomidis Spinellis } 118fdbe5babSDiomidis Spinellis 119fdbe5babSDiomidis Spinellis /* 120fdbe5babSDiomidis Spinellis * Read an v2 accounting record stored at the current 121fdbe5babSDiomidis Spinellis * position of stream f. 122fdbe5babSDiomidis Spinellis * Return EOF on error or end-of-file. 123fdbe5babSDiomidis Spinellis */ 124fdbe5babSDiomidis Spinellis static int 12569921123SKonstantin Belousov readrec_v2(FILE *f, struct acctv3 *av3) 126fdbe5babSDiomidis Spinellis { 12769921123SKonstantin Belousov struct acctv2 av2; 12869921123SKonstantin Belousov int rv; 12969921123SKonstantin Belousov 13069921123SKonstantin Belousov if ((rv = fread_record(&av2, sizeof(av2), f)) == EOF) 13169921123SKonstantin Belousov return (EOF); 13269921123SKonstantin Belousov av3->ac_zero = 0; 13369921123SKonstantin Belousov av3->ac_version = 3; 13469921123SKonstantin Belousov av3->ac_len = av3->ac_len2 = sizeof(*av3); 13569921123SKonstantin Belousov memcpy(av3->ac_comm, av2.ac_comm, AC_COMM_LEN); 13669921123SKonstantin Belousov av3->ac_utime = av2.ac_utime; 13769921123SKonstantin Belousov av3->ac_stime = av2.ac_stime; 13869921123SKonstantin Belousov av3->ac_etime = av2.ac_etime; 13969921123SKonstantin Belousov av3->ac_btime = av2.ac_btime; 14069921123SKonstantin Belousov av3->ac_uid = av2.ac_uid; 14169921123SKonstantin Belousov av3->ac_gid = av2.ac_gid; 14269921123SKonstantin Belousov av3->ac_mem = av2.ac_mem; 14369921123SKonstantin Belousov av3->ac_io = av2.ac_io; 14469921123SKonstantin Belousov av3->ac_tty = av2.ac_tty; 14569921123SKonstantin Belousov av3->ac_flagx = av2.ac_flagx; 14669921123SKonstantin Belousov return (0); 14769921123SKonstantin Belousov } 14869921123SKonstantin Belousov 14969921123SKonstantin Belousov /* 15069921123SKonstantin Belousov * Read an v2 accounting record stored at the current 15169921123SKonstantin Belousov * position of stream f. 15269921123SKonstantin Belousov * Return EOF on error or end-of-file. 15369921123SKonstantin Belousov */ 15469921123SKonstantin Belousov static int 15569921123SKonstantin Belousov readrec_v3(FILE *f, struct acctv3 *av3) 15669921123SKonstantin Belousov { 15769921123SKonstantin Belousov 15869921123SKonstantin Belousov return (fread_record(av3, sizeof(*av3), f)); 159fdbe5babSDiomidis Spinellis } 160fdbe5babSDiomidis Spinellis 161fdbe5babSDiomidis Spinellis /* 162fdbe5babSDiomidis Spinellis * Read a new-style (post-v1) accounting record stored at 163fdbe5babSDiomidis Spinellis * the current position of stream f. 164fdbe5babSDiomidis Spinellis * Convert the data to the current record format. 165fdbe5babSDiomidis Spinellis * Return EOF on error or end-of-file. 166fdbe5babSDiomidis Spinellis */ 167fdbe5babSDiomidis Spinellis static int 16869921123SKonstantin Belousov readrec_vx(FILE *f, struct acctv3 *av3) 169fdbe5babSDiomidis Spinellis { 170fdbe5babSDiomidis Spinellis uint8_t magic, version; 171fdbe5babSDiomidis Spinellis 172fdbe5babSDiomidis Spinellis if (fread_record(&magic, sizeof(magic), f) == EOF || 173fdbe5babSDiomidis Spinellis fread_record(&version, sizeof(version), f) == EOF || 174fdbe5babSDiomidis Spinellis ungetc(version, f) == EOF || 175fdbe5babSDiomidis Spinellis ungetc(magic, f) == EOF) 176fdbe5babSDiomidis Spinellis return (EOF); 177fdbe5babSDiomidis Spinellis switch (version) { 178fdbe5babSDiomidis Spinellis case 2: 17969921123SKonstantin Belousov return (readrec_v2(f, av3)); 18069921123SKonstantin Belousov case 3: 18169921123SKonstantin Belousov return (readrec_v3(f, av3)); 182fdbe5babSDiomidis Spinellis 183fdbe5babSDiomidis Spinellis /* Add handling for more versions here. */ 184fdbe5babSDiomidis Spinellis 185fdbe5babSDiomidis Spinellis default: 186fdbe5babSDiomidis Spinellis errno = EFTYPE; 187fdbe5babSDiomidis Spinellis return (EOF); 188fdbe5babSDiomidis Spinellis } 189fdbe5babSDiomidis Spinellis } 190fdbe5babSDiomidis Spinellis 191fdbe5babSDiomidis Spinellis /* 192fdbe5babSDiomidis Spinellis * Read an accounting record stored at the current 193fdbe5babSDiomidis Spinellis * position of stream f. 194fdbe5babSDiomidis Spinellis * Old-format records are converted to the current record 195fdbe5babSDiomidis Spinellis * format. 196fdbe5babSDiomidis Spinellis * Return the number of records read (1 or 0 at the end-of-file), 197fdbe5babSDiomidis Spinellis * or EOF on error. 198fdbe5babSDiomidis Spinellis */ 199fdbe5babSDiomidis Spinellis int 20069921123SKonstantin Belousov readrec_forward(FILE *f, struct acctv3 *av3) 201fdbe5babSDiomidis Spinellis { 202fdbe5babSDiomidis Spinellis int magic, rv; 203fdbe5babSDiomidis Spinellis 204fdbe5babSDiomidis Spinellis if ((magic = getc(f)) == EOF) 205fdbe5babSDiomidis Spinellis return (ferror(f) ? EOF : 0); 206fdbe5babSDiomidis Spinellis if (ungetc(magic, f) == EOF) 207fdbe5babSDiomidis Spinellis return (EOF); 208fdbe5babSDiomidis Spinellis if (magic != 0) 209fdbe5babSDiomidis Spinellis /* Old record format. */ 21069921123SKonstantin Belousov rv = readrec_v1(f, av3); 211fdbe5babSDiomidis Spinellis else 212fdbe5babSDiomidis Spinellis /* New record formats. */ 21369921123SKonstantin Belousov rv = readrec_vx(f, av3); 214fdbe5babSDiomidis Spinellis return (rv == EOF ? EOF : 1); 215fdbe5babSDiomidis Spinellis } 216fdbe5babSDiomidis Spinellis 217fdbe5babSDiomidis Spinellis /* 218fdbe5babSDiomidis Spinellis * Read an accounting record ending at the current 219fdbe5babSDiomidis Spinellis * position of stream f. 220fdbe5babSDiomidis Spinellis * Old-format records are converted to the current record 221fdbe5babSDiomidis Spinellis * format. 222fdbe5babSDiomidis Spinellis * The file pointer is positioned at the beginning of the 223fdbe5babSDiomidis Spinellis * record read. 224fdbe5babSDiomidis Spinellis * Return the number of records read (1 or 0 at the end-of-file), 225fdbe5babSDiomidis Spinellis * or EOF on error. 226fdbe5babSDiomidis Spinellis */ 227fdbe5babSDiomidis Spinellis int 22869921123SKonstantin Belousov readrec_backward(FILE *f, struct acctv3 *av3) 229fdbe5babSDiomidis Spinellis { 230fdbe5babSDiomidis Spinellis off_t pos; 231fdbe5babSDiomidis Spinellis int c; 232fdbe5babSDiomidis Spinellis uint16_t len; 233fdbe5babSDiomidis Spinellis 234fdbe5babSDiomidis Spinellis if ((pos = ftell(f)) == -1) 235fdbe5babSDiomidis Spinellis return (EOF); 236fdbe5babSDiomidis Spinellis if (pos == 0) 237fdbe5babSDiomidis Spinellis return (0); 23869921123SKonstantin Belousov if (fseek(f, -roffsetof(struct acctv3, ac_trailer), 239fdbe5babSDiomidis Spinellis SEEK_CUR) == EOF || 240fdbe5babSDiomidis Spinellis (c = getc(f)) == EOF) 241fdbe5babSDiomidis Spinellis return (EOF); 242fdbe5babSDiomidis Spinellis if (c & ANVER) { 24369921123SKonstantin Belousov /* 24469921123SKonstantin Belousov * New record formats. For v2 and v3 offset from the 24569921123SKonstantin Belousov * end for ac_len2 should be same. 24669921123SKonstantin Belousov */ 247fdbe5babSDiomidis Spinellis if (fseeko(f, pos - roffsetof(struct acctv2, ac_len2), 248fdbe5babSDiomidis Spinellis SEEK_SET) == EOF || 249fdbe5babSDiomidis Spinellis fread_record(&len, sizeof(len), f) == EOF || 250fdbe5babSDiomidis Spinellis fseeko(f, pos - len, SEEK_SET) == EOF || 25169921123SKonstantin Belousov readrec_vx(f, av3) == EOF || 252fdbe5babSDiomidis Spinellis fseeko(f, pos - len, SEEK_SET) == EOF) 253fdbe5babSDiomidis Spinellis return (EOF); 254fdbe5babSDiomidis Spinellis else 255fdbe5babSDiomidis Spinellis return (1); 256fdbe5babSDiomidis Spinellis } else { 257fdbe5babSDiomidis Spinellis /* Old record format. */ 258fdbe5babSDiomidis Spinellis if (fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF || 25969921123SKonstantin Belousov readrec_v1(f, av3) == EOF || 260fdbe5babSDiomidis Spinellis fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF) 261fdbe5babSDiomidis Spinellis return (EOF); 262fdbe5babSDiomidis Spinellis else 263fdbe5babSDiomidis Spinellis return (1); 264fdbe5babSDiomidis Spinellis } 265fdbe5babSDiomidis Spinellis } 266