]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - usr.bin/lastcomm/readrec.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / usr.bin / lastcomm / readrec.c
1 /*-
2  * Copyright (c) 2007 Diomidis Spinellis
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
34 #include <sys/acct.h>
35
36 #include <errno.h>
37 #include <stddef.h>
38 #include <stdio.h>
39 #include <string.h>
40
41 int      readrec_forward(FILE *f, struct acctv2 *av2);
42 int      readrec_backward(FILE *f, struct acctv2 *av2);
43
44 /*
45  * Reverse offsetof: return the offset of field f
46  * from the end of the structure s.
47  */
48 #define roffsetof(s, f) (sizeof(s) - offsetof(s, f))
49
50 /*
51  * Read exactly one record of size size from stream f into ptr.
52  * Failure to read the complete record is considered a file format error,
53  * and will set errno to EFTYPE.
54  * Return 0 on success, EOF on end of file or error.
55  */
56 static int
57 fread_record(void *ptr, size_t size, FILE *f)
58 {
59         size_t rv;
60
61         if ((rv = fread(ptr, 1, size, f)) == size)
62                 return (0);
63         else if (ferror(f) || rv == 0)
64                 return (EOF);
65         else {
66                 /* Short read. */
67                 errno = EFTYPE;
68                 return (EOF);
69         }
70 }
71
72 /*
73  * Return the value of a comp_t field.
74  */
75 static float
76 decode_comp(comp_t v)
77 {
78         int result, exp;
79
80         result = v & 017777;
81         for (exp = v >> 13; exp; exp--)
82                 result <<= 3;
83         return ((double)result / AHZV1);
84 }
85
86 /*
87  * Read a v1 accounting record stored at the current
88  * position of stream f.
89  * Convert the data to the current record format.
90  * Return EOF on error or end-of-file.
91  */
92 static int
93 readrec_v1(FILE *f, struct acctv2 *av2)
94 {
95         struct acctv1 av1;
96         int rv;
97
98         if ((rv = fread_record(&av1, sizeof(av1), f)) == EOF)
99                 return (EOF);
100         av2->ac_zero = 0;
101         av2->ac_version = 2;
102         av2->ac_len = av2->ac_len2 = sizeof(*av2);
103         memcpy(av2->ac_comm, av1.ac_comm, AC_COMM_LEN);
104         av2->ac_utime = decode_comp(av1.ac_utime) * 1000000;
105         av2->ac_stime = decode_comp(av1.ac_stime) * 1000000;
106         av2->ac_etime = decode_comp(av1.ac_etime) * 1000000;
107         av2->ac_btime = av1.ac_btime;
108         av2->ac_uid = av1.ac_uid;
109         av2->ac_gid = av1.ac_gid;
110         av2->ac_mem = av1.ac_mem;
111         av2->ac_io = decode_comp(av1.ac_io);
112         av2->ac_tty = av1.ac_tty;
113         av2->ac_flagx = av1.ac_flag | ANVER;
114         return (0);
115 }
116
117 /*
118  * Read an v2 accounting record stored at the current
119  * position of stream f.
120  * Return EOF on error or end-of-file.
121  */
122 static int
123 readrec_v2(FILE *f, struct acctv2 *av2)
124 {
125         return (fread_record(av2, sizeof(*av2), f));
126 }
127
128 /*
129  * Read a new-style (post-v1) accounting record stored at
130  * the current position of stream f.
131  * Convert the data to the current record format.
132  * Return EOF on error or end-of-file.
133  */
134 static int
135 readrec_vx(FILE *f, struct acctv2 *av2)
136 {
137         uint8_t magic, version;
138
139         if (fread_record(&magic, sizeof(magic), f) == EOF ||
140             fread_record(&version, sizeof(version), f) == EOF ||
141             ungetc(version, f) == EOF ||
142             ungetc(magic, f) == EOF)
143                 return (EOF);
144         switch (version) {
145         case 2:
146                 return (readrec_v2(f, av2));
147
148         /* Add handling for more versions here. */
149
150         default:
151                 errno = EFTYPE;
152                 return (EOF);
153         }
154 }
155
156 /*
157  * Read an accounting record stored at the current
158  * position of stream f.
159  * Old-format records are converted to the current record
160  * format.
161  * Return the number of records read (1 or 0 at the end-of-file),
162  * or EOF on error.
163  */
164 int
165 readrec_forward(FILE *f, struct acctv2 *av2)
166 {
167         int magic, rv;
168
169         if ((magic = getc(f)) == EOF)
170                 return (ferror(f) ? EOF : 0);
171         if (ungetc(magic, f) == EOF)
172                 return (EOF);
173         if (magic != 0)
174                 /* Old record format. */
175                 rv = readrec_v1(f, av2);
176         else
177                 /* New record formats. */
178                 rv = readrec_vx(f, av2);
179         return (rv == EOF ? EOF : 1);
180 }
181
182 /*
183  * Read an accounting record ending at the current
184  * position of stream f.
185  * Old-format records are converted to the current record
186  * format.
187  * The file pointer is positioned at the beginning of the
188  * record read.
189  * Return the number of records read (1 or 0 at the end-of-file),
190  * or EOF on error.
191  */
192 int
193 readrec_backward(FILE *f, struct acctv2 *av2)
194 {
195         off_t pos;
196         int c;
197         uint16_t len;
198
199         if ((pos = ftell(f)) == -1)
200                 return (EOF);
201         if (pos == 0)
202                 return (0);
203         if (fseek(f, -roffsetof(struct acctv2, ac_trailer),
204             SEEK_CUR) == EOF ||
205             (c = getc(f)) == EOF)
206                 return (EOF);
207         if (c & ANVER) {
208                 /* New record formats. */
209                 if (fseeko(f, pos - roffsetof(struct acctv2, ac_len2),
210                     SEEK_SET) == EOF ||
211                     fread_record(&len, sizeof(len), f) == EOF ||
212                     fseeko(f, pos - len, SEEK_SET) == EOF ||
213                     readrec_vx(f, av2) == EOF ||
214                     fseeko(f, pos - len, SEEK_SET) == EOF)
215                         return (EOF);
216                 else
217                         return (1);
218         } else {
219                 /* Old record format. */
220                 if (fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF ||
221                     readrec_v1(f, av2) == EOF ||
222                     fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF)
223                         return (EOF);
224                 else
225                         return (1);
226         }
227 }