1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #include <exacct.h>
32*7c478bd9Sstevel@tonic-gate #include <exacct_impl.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/exacct_impl.h>
34*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
35*7c478bd9Sstevel@tonic-gate #include <unistd.h>
36*7c478bd9Sstevel@tonic-gate #include <strings.h>
37*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
38*7c478bd9Sstevel@tonic-gate #include <stdio.h>
39*7c478bd9Sstevel@tonic-gate #include <errno.h>
40*7c478bd9Sstevel@tonic-gate #include <thread.h>
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #define	EXACCT_HDR_STR	"exacct"
43*7c478bd9Sstevel@tonic-gate #define	EXACCT_HDR_LEN	7
44*7c478bd9Sstevel@tonic-gate 
45*7c478bd9Sstevel@tonic-gate #define	DEFAULT_ENTRIES	4
46*7c478bd9Sstevel@tonic-gate #define	SYSINFO_BUFSIZE	256
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate static mutex_t		keylock;
49*7c478bd9Sstevel@tonic-gate static thread_key_t	errkey;
50*7c478bd9Sstevel@tonic-gate static int		keyonce = 0;
51*7c478bd9Sstevel@tonic-gate static int		exacct_errval = 0;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * extended accounting file access routines
55*7c478bd9Sstevel@tonic-gate  *
56*7c478bd9Sstevel@tonic-gate  *   exacct_ops.c implements the library-specific routines of libexacct:  the
57*7c478bd9Sstevel@tonic-gate  *   operations associated with file access and record traversal.  (The
58*7c478bd9Sstevel@tonic-gate  *   complementary routines which permit hierarchy building and record packing
59*7c478bd9Sstevel@tonic-gate  *   are provided in exacct_core.c, which is used by both libexacct and the
60*7c478bd9Sstevel@tonic-gate  *   kernel.) At its heart are the unpack, get, and next routines, which
61*7c478bd9Sstevel@tonic-gate  *   navigate the packed records produced by ea_pack_object.
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate /*
65*7c478bd9Sstevel@tonic-gate  * Group stack manipulation code.  As groups can be nested, we need a mechanism
66*7c478bd9Sstevel@tonic-gate  * for saving and restoring the current position within the outer groups.  This
67*7c478bd9Sstevel@tonic-gate  * state stack is stored within the ea_file_impl_t structure, in the ef_depth,
68*7c478bd9Sstevel@tonic-gate  * ef_ndeep and ef_mxdeep members.  On error all these functions set
69*7c478bd9Sstevel@tonic-gate  * exacct_error and return -1.
70*7c478bd9Sstevel@tonic-gate  */
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate /*
73*7c478bd9Sstevel@tonic-gate  * If the stack is NULL, create and initialise it.
74*7c478bd9Sstevel@tonic-gate  * If is is not NULL, check it still has space - if not, double its size.
75*7c478bd9Sstevel@tonic-gate  */
76*7c478bd9Sstevel@tonic-gate static int stack_check(ea_file_impl_t *f)
77*7c478bd9Sstevel@tonic-gate {
78*7c478bd9Sstevel@tonic-gate 	if (f->ef_depth == NULL) {
79*7c478bd9Sstevel@tonic-gate 		if ((f->ef_depth =
80*7c478bd9Sstevel@tonic-gate 		    ea_alloc(DEFAULT_ENTRIES * sizeof (ea_file_depth_t)))
81*7c478bd9Sstevel@tonic-gate 		    == NULL) {
82*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
83*7c478bd9Sstevel@tonic-gate 			return (-1);
84*7c478bd9Sstevel@tonic-gate 		}
85*7c478bd9Sstevel@tonic-gate 		bzero(f->ef_depth, DEFAULT_ENTRIES * sizeof (ea_file_depth_t));
86*7c478bd9Sstevel@tonic-gate 		f->ef_mxdeep = DEFAULT_ENTRIES;
87*7c478bd9Sstevel@tonic-gate 		f->ef_ndeep = -1;
88*7c478bd9Sstevel@tonic-gate 	} else if (f->ef_ndeep + 1 >= f->ef_mxdeep) {
89*7c478bd9Sstevel@tonic-gate 		ea_file_depth_t *newstack;
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 		if ((newstack =
92*7c478bd9Sstevel@tonic-gate 		    ea_alloc(f->ef_mxdeep * 2 * sizeof (ea_file_depth_t)))
93*7c478bd9Sstevel@tonic-gate 		    == NULL) {
94*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
95*7c478bd9Sstevel@tonic-gate 			return (-1);
96*7c478bd9Sstevel@tonic-gate 		}
97*7c478bd9Sstevel@tonic-gate 		bcopy(f->ef_depth, newstack,
98*7c478bd9Sstevel@tonic-gate 		    f->ef_mxdeep * sizeof (ea_file_depth_t));
99*7c478bd9Sstevel@tonic-gate 		bzero(newstack + f->ef_mxdeep,
100*7c478bd9Sstevel@tonic-gate 		    f->ef_mxdeep * sizeof (ea_file_depth_t));
101*7c478bd9Sstevel@tonic-gate 		ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t));
102*7c478bd9Sstevel@tonic-gate 		f->ef_mxdeep *= 2;
103*7c478bd9Sstevel@tonic-gate 		f->ef_depth = newstack;
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate 	return (0);
106*7c478bd9Sstevel@tonic-gate }
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate /*
109*7c478bd9Sstevel@tonic-gate  * Free a stack.
110*7c478bd9Sstevel@tonic-gate  */
111*7c478bd9Sstevel@tonic-gate static void stack_free(ea_file_impl_t *f)
112*7c478bd9Sstevel@tonic-gate {
113*7c478bd9Sstevel@tonic-gate 	if (f->ef_depth != NULL) {
114*7c478bd9Sstevel@tonic-gate 		ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t));
115*7c478bd9Sstevel@tonic-gate 		f->ef_depth = NULL;
116*7c478bd9Sstevel@tonic-gate 	}
117*7c478bd9Sstevel@tonic-gate 	f->ef_mxdeep = 0;
118*7c478bd9Sstevel@tonic-gate 	f->ef_ndeep = -1;
119*7c478bd9Sstevel@tonic-gate }
120*7c478bd9Sstevel@tonic-gate 
121*7c478bd9Sstevel@tonic-gate /*
122*7c478bd9Sstevel@tonic-gate  * Add a new group onto the stack, pushing down one frame.  nobj is the number
123*7c478bd9Sstevel@tonic-gate  * of items in the group.  We have to read this many objects before popping
124*7c478bd9Sstevel@tonic-gate  * back up to an enclosing group - see next_object() and previous_object()
125*7c478bd9Sstevel@tonic-gate  * below.
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate static int stack_new_group(ea_file_impl_t *f, int nobjs)
128*7c478bd9Sstevel@tonic-gate {
129*7c478bd9Sstevel@tonic-gate 	if (stack_check(f) != 0) {
130*7c478bd9Sstevel@tonic-gate 		stack_free(f);
131*7c478bd9Sstevel@tonic-gate 		/* exacct_errno set above. */
132*7c478bd9Sstevel@tonic-gate 		return (-1);
133*7c478bd9Sstevel@tonic-gate 	}
134*7c478bd9Sstevel@tonic-gate 	f->ef_ndeep++;
135*7c478bd9Sstevel@tonic-gate 	f->ef_depth[f->ef_ndeep].efd_obj = 0;
136*7c478bd9Sstevel@tonic-gate 	f->ef_depth[f->ef_ndeep].efd_nobjs = nobjs;
137*7c478bd9Sstevel@tonic-gate 	return (0);
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * Step forwards along the objects within the current group.  If we are still
142*7c478bd9Sstevel@tonic-gate  * within a group, return 1.  If we have reached the end of the current group,
143*7c478bd9Sstevel@tonic-gate  * unwind the stack back up to the nearest enclosing group that still has
144*7c478bd9Sstevel@tonic-gate  * unprocessed objects and return 0.  On EOF or error, set exacct_error
145*7c478bd9Sstevel@tonic-gate  * accordingly and return -1.  xread() is required so that this function can
146*7c478bd9Sstevel@tonic-gate  * work either on files or memory buffers.
147*7c478bd9Sstevel@tonic-gate  */
148*7c478bd9Sstevel@tonic-gate static int
149*7c478bd9Sstevel@tonic-gate stack_next_object(
150*7c478bd9Sstevel@tonic-gate     ea_file_impl_t *f,
151*7c478bd9Sstevel@tonic-gate     size_t (*xread)(ea_file_impl_t *, void *, size_t))
152*7c478bd9Sstevel@tonic-gate {
153*7c478bd9Sstevel@tonic-gate 	uint32_t scratch32;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 	/*
156*7c478bd9Sstevel@tonic-gate 	 * If the stack is empty we are not in a group, so there will be no
157*7c478bd9Sstevel@tonic-gate 	 * stack manipulation to do and no large backskips to step over.
158*7c478bd9Sstevel@tonic-gate 	 */
159*7c478bd9Sstevel@tonic-gate 	if (f->ef_ndeep < 0) {
160*7c478bd9Sstevel@tonic-gate 		return (0);
161*7c478bd9Sstevel@tonic-gate 	}
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	/*
164*7c478bd9Sstevel@tonic-gate 	 * Otherwise we must be in a group.  If there are objects left in the
165*7c478bd9Sstevel@tonic-gate 	 * group, move onto the next one in the group and return.
166*7c478bd9Sstevel@tonic-gate 	 */
167*7c478bd9Sstevel@tonic-gate 	if (++f->ef_depth[f->ef_ndeep].efd_obj <
168*7c478bd9Sstevel@tonic-gate 	    f->ef_depth[f->ef_ndeep].efd_nobjs) {
169*7c478bd9Sstevel@tonic-gate 		return (1);
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	/*
172*7c478bd9Sstevel@tonic-gate 	 * If we are at the end of a group we need to move backwards up the
173*7c478bd9Sstevel@tonic-gate 	 * stack, consuming the large backskips as we go, until we find a group
174*7c478bd9Sstevel@tonic-gate 	 * that still contains unprocessed items, or until we have unwound back
175*7c478bd9Sstevel@tonic-gate 	 * off the bottom of the stack (i.e. out of all the groups).
176*7c478bd9Sstevel@tonic-gate 	 */
177*7c478bd9Sstevel@tonic-gate 	} else {
178*7c478bd9Sstevel@tonic-gate 		while (f->ef_ndeep >= 0 &&
179*7c478bd9Sstevel@tonic-gate 		    ++f->ef_depth[f->ef_ndeep].efd_obj >=
180*7c478bd9Sstevel@tonic-gate 		    f->ef_depth[f->ef_ndeep].efd_nobjs) {
181*7c478bd9Sstevel@tonic-gate 			/* Read the large backskip. */
182*7c478bd9Sstevel@tonic-gate 			f->ef_ndeep--;
183*7c478bd9Sstevel@tonic-gate 			if (xread(f, &scratch32, sizeof (scratch32)) !=
184*7c478bd9Sstevel@tonic-gate 			    sizeof (scratch32)) {
185*7c478bd9Sstevel@tonic-gate 				EXACCT_SET_ERR(EXR_CORRUPT_FILE);
186*7c478bd9Sstevel@tonic-gate 				return (-1);
187*7c478bd9Sstevel@tonic-gate 			}
188*7c478bd9Sstevel@tonic-gate 		}
189*7c478bd9Sstevel@tonic-gate 		return (0);
190*7c478bd9Sstevel@tonic-gate 	}
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate /*
194*7c478bd9Sstevel@tonic-gate  * Step backwards along the objects within the current group.  If we are still
195*7c478bd9Sstevel@tonic-gate  * within a group, return 1.  If we have reached the end of the current group,
196*7c478bd9Sstevel@tonic-gate  * unwind the stack back up to the enclosing group and return 0.
197*7c478bd9Sstevel@tonic-gate  */
198*7c478bd9Sstevel@tonic-gate static int stack_previous_object(ea_file_impl_t *f)
199*7c478bd9Sstevel@tonic-gate {
200*7c478bd9Sstevel@tonic-gate 	/*
201*7c478bd9Sstevel@tonic-gate 	 * If the stack is empty we are not in a group, so there will be no
202*7c478bd9Sstevel@tonic-gate 	 * stack manipulation to do.
203*7c478bd9Sstevel@tonic-gate 	 */
204*7c478bd9Sstevel@tonic-gate 	if (f->ef_ndeep < 0) {
205*7c478bd9Sstevel@tonic-gate 		return (0);
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 	/*
209*7c478bd9Sstevel@tonic-gate 	 * Otherwise we must be in a group.  If there are objects left in the
210*7c478bd9Sstevel@tonic-gate 	 * group, move onto the previous one in the group and return.
211*7c478bd9Sstevel@tonic-gate 	 */
212*7c478bd9Sstevel@tonic-gate 	if (--f->ef_depth[f->ef_ndeep].efd_obj >= 0) {
213*7c478bd9Sstevel@tonic-gate 		return (1);
214*7c478bd9Sstevel@tonic-gate 
215*7c478bd9Sstevel@tonic-gate 	/* Otherwise, step one level back up the group stack. */
216*7c478bd9Sstevel@tonic-gate 	} else {
217*7c478bd9Sstevel@tonic-gate 		f->ef_ndeep--;
218*7c478bd9Sstevel@tonic-gate 		return (0);
219*7c478bd9Sstevel@tonic-gate 	}
220*7c478bd9Sstevel@tonic-gate }
221*7c478bd9Sstevel@tonic-gate 
222*7c478bd9Sstevel@tonic-gate /*
223*7c478bd9Sstevel@tonic-gate  * read/seek/pos virtualisation wrappers.  Because objects can come either from
224*7c478bd9Sstevel@tonic-gate  * a file or memory, the read/seek/pos functions need to be wrapped to allow
225*7c478bd9Sstevel@tonic-gate  * them to be used on either a file handle or a memory buffer.
226*7c478bd9Sstevel@tonic-gate  */
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate static size_t
229*7c478bd9Sstevel@tonic-gate fread_wrapper(ea_file_impl_t *f, void *buf, size_t sz)
230*7c478bd9Sstevel@tonic-gate {
231*7c478bd9Sstevel@tonic-gate 	size_t retval;
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	retval = fread(buf, 1, sz, f->ef_fp);
234*7c478bd9Sstevel@tonic-gate 	if (retval == 0 && ferror(f->ef_fp)) {
235*7c478bd9Sstevel@tonic-gate 		retval = (size_t)-1;
236*7c478bd9Sstevel@tonic-gate 	}
237*7c478bd9Sstevel@tonic-gate 	return (retval);
238*7c478bd9Sstevel@tonic-gate }
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate static size_t
241*7c478bd9Sstevel@tonic-gate bufread_wrapper(ea_file_impl_t *f, void *buf, size_t sz)
242*7c478bd9Sstevel@tonic-gate {
243*7c478bd9Sstevel@tonic-gate 	if (f->ef_bufsize == 0 && sz != 0)
244*7c478bd9Sstevel@tonic-gate 		return ((size_t)0);
245*7c478bd9Sstevel@tonic-gate 
246*7c478bd9Sstevel@tonic-gate 	if (f->ef_bufsize < sz)
247*7c478bd9Sstevel@tonic-gate 		sz = f->ef_bufsize;
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 	bcopy(f->ef_buf, buf, sz);
250*7c478bd9Sstevel@tonic-gate 	f->ef_buf += sz;
251*7c478bd9Sstevel@tonic-gate 	f->ef_bufsize -= sz;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	return (sz);
254*7c478bd9Sstevel@tonic-gate }
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate static off_t
257*7c478bd9Sstevel@tonic-gate fseek_wrapper(ea_file_impl_t *f, off_t adv)
258*7c478bd9Sstevel@tonic-gate {
259*7c478bd9Sstevel@tonic-gate 	return (fseeko(f->ef_fp, adv, SEEK_CUR));
260*7c478bd9Sstevel@tonic-gate }
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate static off_t
263*7c478bd9Sstevel@tonic-gate bufseek_wrapper(ea_file_impl_t *f, off_t adv)
264*7c478bd9Sstevel@tonic-gate {
265*7c478bd9Sstevel@tonic-gate 	if (f->ef_bufsize == 0 && adv != 0)
266*7c478bd9Sstevel@tonic-gate 		return (-1);
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	if (f->ef_bufsize < adv)
269*7c478bd9Sstevel@tonic-gate 		adv = f->ef_bufsize;
270*7c478bd9Sstevel@tonic-gate 
271*7c478bd9Sstevel@tonic-gate 	f->ef_buf += adv;
272*7c478bd9Sstevel@tonic-gate 	f->ef_bufsize -= adv;
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	return (0);
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
278*7c478bd9Sstevel@tonic-gate static void *
279*7c478bd9Sstevel@tonic-gate fpos_wrapper(ea_file_impl_t *f)
280*7c478bd9Sstevel@tonic-gate {
281*7c478bd9Sstevel@tonic-gate 	return (NULL);
282*7c478bd9Sstevel@tonic-gate }
283*7c478bd9Sstevel@tonic-gate 
284*7c478bd9Sstevel@tonic-gate static void *
285*7c478bd9Sstevel@tonic-gate bufpos_wrapper(ea_file_impl_t *f)
286*7c478bd9Sstevel@tonic-gate {
287*7c478bd9Sstevel@tonic-gate 	return (f->ef_buf);
288*7c478bd9Sstevel@tonic-gate }
289*7c478bd9Sstevel@tonic-gate 
290*7c478bd9Sstevel@tonic-gate /*
291*7c478bd9Sstevel@tonic-gate  * Public API
292*7c478bd9Sstevel@tonic-gate  */
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate void
295*7c478bd9Sstevel@tonic-gate exacct_seterr(int errval)
296*7c478bd9Sstevel@tonic-gate {
297*7c478bd9Sstevel@tonic-gate 	if (thr_main()) {
298*7c478bd9Sstevel@tonic-gate 		exacct_errval = errval;
299*7c478bd9Sstevel@tonic-gate 		return;
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 	if (keyonce == 0) {
302*7c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&keylock);
303*7c478bd9Sstevel@tonic-gate 		if (keyonce == 0) {
304*7c478bd9Sstevel@tonic-gate 			(void) thr_keycreate(&errkey, 0);
305*7c478bd9Sstevel@tonic-gate 			keyonce++;
306*7c478bd9Sstevel@tonic-gate 		}
307*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&keylock);
308*7c478bd9Sstevel@tonic-gate 	}
309*7c478bd9Sstevel@tonic-gate 	(void) thr_setspecific(errkey, (void *)(intptr_t)errval);
310*7c478bd9Sstevel@tonic-gate }
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate int
313*7c478bd9Sstevel@tonic-gate ea_error(void)
314*7c478bd9Sstevel@tonic-gate {
315*7c478bd9Sstevel@tonic-gate 	intptr_t errvalp;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	if (thr_main())
318*7c478bd9Sstevel@tonic-gate 		return (exacct_errval);
319*7c478bd9Sstevel@tonic-gate 	if (keyonce == 0)
320*7c478bd9Sstevel@tonic-gate 		return (EXR_OK);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	(void) thr_getspecific(errkey, (void**)&errvalp);
323*7c478bd9Sstevel@tonic-gate 	return ((int)errvalp);
324*7c478bd9Sstevel@tonic-gate }
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate /*
327*7c478bd9Sstevel@tonic-gate  * ea_next_object(), ea_previous_object(), and ea_get_object() are written such
328*7c478bd9Sstevel@tonic-gate  * that the file cursor is always located on an object boundary.
329*7c478bd9Sstevel@tonic-gate  */
330*7c478bd9Sstevel@tonic-gate ea_object_type_t
331*7c478bd9Sstevel@tonic-gate ea_next_object(ea_file_t *ef, ea_object_t *obj)
332*7c478bd9Sstevel@tonic-gate {
333*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
334*7c478bd9Sstevel@tonic-gate 	ea_size_t len;
335*7c478bd9Sstevel@tonic-gate 	off_t backup;
336*7c478bd9Sstevel@tonic-gate 	size_t ret;
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	/*
339*7c478bd9Sstevel@tonic-gate 	 * If ef_advance is zero, then we are executing after a get or previous
340*7c478bd9Sstevel@tonic-gate 	 * operation and do not move to the next or previous object.  Otherwise,
341*7c478bd9Sstevel@tonic-gate 	 * advance to the next available item.  Note that ef_advance does NOT
342*7c478bd9Sstevel@tonic-gate 	 * include the large backskip at the end of a object, this being dealt
343*7c478bd9Sstevel@tonic-gate 	 * with by the depth stack handling in stack_next_object.
344*7c478bd9Sstevel@tonic-gate 	 */
345*7c478bd9Sstevel@tonic-gate 	if (f->ef_advance != 0) {
346*7c478bd9Sstevel@tonic-gate 		if (fseeko(f->ef_fp, (off_t)f->ef_advance, SEEK_CUR) == -1) {
347*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
348*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
349*7c478bd9Sstevel@tonic-gate 		}
350*7c478bd9Sstevel@tonic-gate 		if (stack_next_object(f, fread_wrapper) == -1) {
351*7c478bd9Sstevel@tonic-gate 			/* exacct_error set above. */
352*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
353*7c478bd9Sstevel@tonic-gate 		}
354*7c478bd9Sstevel@tonic-gate 	}
355*7c478bd9Sstevel@tonic-gate 	f->ef_advance = 0;
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 	/* Read the catalog tag */
358*7c478bd9Sstevel@tonic-gate 	ret = fread(&obj->eo_catalog, 1, sizeof (ea_catalog_t), f->ef_fp);
359*7c478bd9Sstevel@tonic-gate 	if (ret == 0) {
360*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_EOF);
361*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
362*7c478bd9Sstevel@tonic-gate 	} else if (ret < sizeof (ea_catalog_t)) {
363*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
364*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
365*7c478bd9Sstevel@tonic-gate 	}
366*7c478bd9Sstevel@tonic-gate 	exacct_order32(&obj->eo_catalog);
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	backup = sizeof (ea_catalog_t);
369*7c478bd9Sstevel@tonic-gate 	obj->eo_type = EO_ITEM;
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	/* Figure out the offset to just before the large backskip. */
372*7c478bd9Sstevel@tonic-gate 	switch (obj->eo_catalog & EXT_TYPE_MASK) {
373*7c478bd9Sstevel@tonic-gate 	case EXT_GROUP:
374*7c478bd9Sstevel@tonic-gate 		obj->eo_type = EO_GROUP;
375*7c478bd9Sstevel@tonic-gate 		f->ef_advance = sizeof (uint32_t);
376*7c478bd9Sstevel@tonic-gate 	/* FALLTHROUGH */
377*7c478bd9Sstevel@tonic-gate 	case EXT_STRING:
378*7c478bd9Sstevel@tonic-gate 	case EXT_EXACCT_OBJECT:
379*7c478bd9Sstevel@tonic-gate 	case EXT_RAW:
380*7c478bd9Sstevel@tonic-gate 		if (fread(&len, 1, sizeof (ea_size_t), f->ef_fp)
381*7c478bd9Sstevel@tonic-gate 		    < sizeof (ea_size_t)) {
382*7c478bd9Sstevel@tonic-gate 			obj->eo_type = EO_NONE;
383*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
384*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 		exacct_order64(&len);
387*7c478bd9Sstevel@tonic-gate 		/* Note: len already includes the size of the backskip. */
388*7c478bd9Sstevel@tonic-gate 		f->ef_advance += sizeof (ea_catalog_t) +
389*7c478bd9Sstevel@tonic-gate 		    sizeof (ea_size_t) + len;
390*7c478bd9Sstevel@tonic-gate 		backup += sizeof (ea_size_t);
391*7c478bd9Sstevel@tonic-gate 		break;
392*7c478bd9Sstevel@tonic-gate 	case EXT_UINT8:
393*7c478bd9Sstevel@tonic-gate 		f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint8_t) +
394*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t);
395*7c478bd9Sstevel@tonic-gate 		break;
396*7c478bd9Sstevel@tonic-gate 	case EXT_UINT16:
397*7c478bd9Sstevel@tonic-gate 		f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint16_t) +
398*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t);
399*7c478bd9Sstevel@tonic-gate 		break;
400*7c478bd9Sstevel@tonic-gate 	case EXT_UINT32:
401*7c478bd9Sstevel@tonic-gate 		f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint32_t) +
402*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t);
403*7c478bd9Sstevel@tonic-gate 		break;
404*7c478bd9Sstevel@tonic-gate 	case EXT_UINT64:
405*7c478bd9Sstevel@tonic-gate 		f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint64_t) +
406*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t);
407*7c478bd9Sstevel@tonic-gate 		break;
408*7c478bd9Sstevel@tonic-gate 	case EXT_DOUBLE:
409*7c478bd9Sstevel@tonic-gate 		f->ef_advance = sizeof (ea_catalog_t) + sizeof (double) +
410*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t);
411*7c478bd9Sstevel@tonic-gate 		break;
412*7c478bd9Sstevel@tonic-gate 	default:
413*7c478bd9Sstevel@tonic-gate 		obj->eo_type = EO_NONE;
414*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
415*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
416*7c478bd9Sstevel@tonic-gate 	}
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	/* Reposition to the start of this object. */
419*7c478bd9Sstevel@tonic-gate 	if (fseeko(f->ef_fp, -backup, SEEK_CUR) == -1) {
420*7c478bd9Sstevel@tonic-gate 		obj->eo_type = EO_NONE;
421*7c478bd9Sstevel@tonic-gate 		f->ef_advance = 0;
422*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
423*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
424*7c478bd9Sstevel@tonic-gate 	}
425*7c478bd9Sstevel@tonic-gate 
426*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
427*7c478bd9Sstevel@tonic-gate 	return (obj->eo_type);
428*7c478bd9Sstevel@tonic-gate }
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate ea_object_type_t
431*7c478bd9Sstevel@tonic-gate ea_previous_object(ea_file_t *ef, ea_object_t *obj)
432*7c478bd9Sstevel@tonic-gate {
433*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
434*7c478bd9Sstevel@tonic-gate 	uint32_t bkskip;
435*7c478bd9Sstevel@tonic-gate 	int r;
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 	if (fseeko(f->ef_fp, -((off_t)sizeof (uint32_t)), SEEK_CUR) == -1) {
438*7c478bd9Sstevel@tonic-gate 		if (errno == EINVAL) {
439*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_EOF);
440*7c478bd9Sstevel@tonic-gate 		} else {
441*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
442*7c478bd9Sstevel@tonic-gate 		}
443*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
444*7c478bd9Sstevel@tonic-gate 	}
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	if ((r = fread(&bkskip, 1, sizeof (uint32_t), f->ef_fp)) !=
447*7c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t)) {
448*7c478bd9Sstevel@tonic-gate 		if (r == 0) {
449*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_EOF);
450*7c478bd9Sstevel@tonic-gate 		} else {
451*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
452*7c478bd9Sstevel@tonic-gate 		}
453*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
454*7c478bd9Sstevel@tonic-gate 	}
455*7c478bd9Sstevel@tonic-gate 	exacct_order32(&bkskip);
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 	/*
458*7c478bd9Sstevel@tonic-gate 	 * A backskip of 0 means that the current record can't be skipped over.
459*7c478bd9Sstevel@tonic-gate 	 * This will be true for the header record, and for records longer than
460*7c478bd9Sstevel@tonic-gate 	 * 2^32.
461*7c478bd9Sstevel@tonic-gate 	 */
462*7c478bd9Sstevel@tonic-gate 	if (bkskip == 0) {
463*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_EOF);
464*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
465*7c478bd9Sstevel@tonic-gate 	}
466*7c478bd9Sstevel@tonic-gate 	(void) stack_previous_object(f);
467*7c478bd9Sstevel@tonic-gate 
468*7c478bd9Sstevel@tonic-gate 	if (fseeko(f->ef_fp, -((off_t)bkskip), SEEK_CUR) == -1) {
469*7c478bd9Sstevel@tonic-gate 		if (errno == EINVAL) {
470*7c478bd9Sstevel@tonic-gate 			/*
471*7c478bd9Sstevel@tonic-gate 			 * If we attempted to seek past BOF, then the file was
472*7c478bd9Sstevel@tonic-gate 			 * corrupt, as we can only trust the backskip we read.
473*7c478bd9Sstevel@tonic-gate 			 */
474*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
475*7c478bd9Sstevel@tonic-gate 		} else {
476*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
477*7c478bd9Sstevel@tonic-gate 		}
478*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
479*7c478bd9Sstevel@tonic-gate 	}
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	f->ef_advance = 0;
482*7c478bd9Sstevel@tonic-gate 	return (ea_next_object(ef, obj));
483*7c478bd9Sstevel@tonic-gate }
484*7c478bd9Sstevel@tonic-gate 
485*7c478bd9Sstevel@tonic-gate /*
486*7c478bd9Sstevel@tonic-gate  * xget_object() contains the logic for extracting an individual object from a
487*7c478bd9Sstevel@tonic-gate  * packed buffer, which it consumes using xread() and xseek() operations
488*7c478bd9Sstevel@tonic-gate  * provided by the caller.  flags may be set to either EUP_ALLOC, in which case
489*7c478bd9Sstevel@tonic-gate  * new memory is allocated for the variable length items unpacked, or
490*7c478bd9Sstevel@tonic-gate  * EUP_NOALLOC, in which case item data pointer indicate locations within the
491*7c478bd9Sstevel@tonic-gate  * buffer, using the provided xpos() function.  EUP_NOALLOC is generally not
492*7c478bd9Sstevel@tonic-gate  * useful for callers representing interaction with actual file streams, and
493*7c478bd9Sstevel@tonic-gate  * should not be specified thereby.
494*7c478bd9Sstevel@tonic-gate  */
495*7c478bd9Sstevel@tonic-gate static ea_object_type_t
496*7c478bd9Sstevel@tonic-gate xget_object(
497*7c478bd9Sstevel@tonic-gate     ea_file_impl_t *f,
498*7c478bd9Sstevel@tonic-gate     ea_object_t *obj,
499*7c478bd9Sstevel@tonic-gate     size_t (*xread)(ea_file_impl_t *, void *, size_t),
500*7c478bd9Sstevel@tonic-gate     off_t (*xseek)(ea_file_impl_t *, off_t),
501*7c478bd9Sstevel@tonic-gate     void *(*xpos)(ea_file_impl_t *),
502*7c478bd9Sstevel@tonic-gate     int flags)
503*7c478bd9Sstevel@tonic-gate {
504*7c478bd9Sstevel@tonic-gate 	ea_size_t sz;
505*7c478bd9Sstevel@tonic-gate 	uint32_t gp_backskip, scratch32;
506*7c478bd9Sstevel@tonic-gate 	void *buf;
507*7c478bd9Sstevel@tonic-gate 	size_t r;
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 	/* Read the catalog tag. */
510*7c478bd9Sstevel@tonic-gate 	if ((r = xread(f, &obj->eo_catalog, sizeof (ea_catalog_t))) == 0) {
511*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_EOF);
512*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
513*7c478bd9Sstevel@tonic-gate 	} else if (r != sizeof (ea_catalog_t)) {
514*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
515*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
516*7c478bd9Sstevel@tonic-gate 	}
517*7c478bd9Sstevel@tonic-gate 	exacct_order32(&obj->eo_catalog);
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	/*
520*7c478bd9Sstevel@tonic-gate 	 * If this is a record group, we treat it separately:  only record
521*7c478bd9Sstevel@tonic-gate 	 * groups cause us to allocate new depth frames.
522*7c478bd9Sstevel@tonic-gate 	 */
523*7c478bd9Sstevel@tonic-gate 	if ((obj->eo_catalog & EXT_TYPE_MASK) == EXT_GROUP) {
524*7c478bd9Sstevel@tonic-gate 		obj->eo_type = EO_GROUP;
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 		/* Read size field, and number of objects. */
527*7c478bd9Sstevel@tonic-gate 		if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) {
528*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
529*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
530*7c478bd9Sstevel@tonic-gate 		}
531*7c478bd9Sstevel@tonic-gate 		exacct_order64(&sz);
532*7c478bd9Sstevel@tonic-gate 		if (xread(f, &obj->eo_group.eg_nobjs, sizeof (uint32_t)) !=
533*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t)) {
534*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
535*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
536*7c478bd9Sstevel@tonic-gate 		}
537*7c478bd9Sstevel@tonic-gate 		exacct_order32(&obj->eo_group.eg_nobjs);
538*7c478bd9Sstevel@tonic-gate 
539*7c478bd9Sstevel@tonic-gate 		/* Now read the group's small backskip. */
540*7c478bd9Sstevel@tonic-gate 		if (xread(f, &gp_backskip, sizeof (uint32_t)) !=
541*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t)) {
542*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
543*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
544*7c478bd9Sstevel@tonic-gate 		}
545*7c478bd9Sstevel@tonic-gate 
546*7c478bd9Sstevel@tonic-gate 		/* Push a new depth stack frame. */
547*7c478bd9Sstevel@tonic-gate 		if (stack_new_group(f, obj->eo_group.eg_nobjs) != 0) {
548*7c478bd9Sstevel@tonic-gate 			/* exacct_error set above */
549*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
550*7c478bd9Sstevel@tonic-gate 		}
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate 		/*
553*7c478bd9Sstevel@tonic-gate 		 * If the group has no items, we now need to position to the
554*7c478bd9Sstevel@tonic-gate 		 * end of the group, because there will be no subsequent calls
555*7c478bd9Sstevel@tonic-gate 		 * to process the group, it being empty.
556*7c478bd9Sstevel@tonic-gate 		 */
557*7c478bd9Sstevel@tonic-gate 		if (obj->eo_group.eg_nobjs == 0) {
558*7c478bd9Sstevel@tonic-gate 			if (stack_next_object(f, xread) == -1) {
559*7c478bd9Sstevel@tonic-gate 				/* exacct_error set above. */
560*7c478bd9Sstevel@tonic-gate 				return (EO_ERROR);
561*7c478bd9Sstevel@tonic-gate 			}
562*7c478bd9Sstevel@tonic-gate 		}
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 		f->ef_advance = 0;
565*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_OK);
566*7c478bd9Sstevel@tonic-gate 		return (obj->eo_type);
567*7c478bd9Sstevel@tonic-gate 	}
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	/*
570*7c478bd9Sstevel@tonic-gate 	 * Otherwise we are reading an item.
571*7c478bd9Sstevel@tonic-gate 	 */
572*7c478bd9Sstevel@tonic-gate 	obj->eo_type = EO_ITEM;
573*7c478bd9Sstevel@tonic-gate 	switch (obj->eo_catalog & EXT_TYPE_MASK) {
574*7c478bd9Sstevel@tonic-gate 	case EXT_STRING:
575*7c478bd9Sstevel@tonic-gate 	case EXT_EXACCT_OBJECT:
576*7c478bd9Sstevel@tonic-gate 	case EXT_RAW:
577*7c478bd9Sstevel@tonic-gate 		if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) {
578*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
579*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
580*7c478bd9Sstevel@tonic-gate 		}
581*7c478bd9Sstevel@tonic-gate 		exacct_order64(&sz);
582*7c478bd9Sstevel@tonic-gate 		/*
583*7c478bd9Sstevel@tonic-gate 		 * Subtract backskip value from size.
584*7c478bd9Sstevel@tonic-gate 		 */
585*7c478bd9Sstevel@tonic-gate 		sz -= sizeof (uint32_t);
586*7c478bd9Sstevel@tonic-gate 		if ((flags & EUP_ALLOC_MASK) == EUP_NOALLOC) {
587*7c478bd9Sstevel@tonic-gate 			buf = xpos(f);
588*7c478bd9Sstevel@tonic-gate 			if (xseek(f, sz) == -1) {
589*7c478bd9Sstevel@tonic-gate 				EXACCT_SET_ERR(EXR_CORRUPT_FILE);
590*7c478bd9Sstevel@tonic-gate 				return (EO_ERROR);
591*7c478bd9Sstevel@tonic-gate 			}
592*7c478bd9Sstevel@tonic-gate 		} else {
593*7c478bd9Sstevel@tonic-gate 			if ((buf = ea_alloc(sz)) == NULL)
594*7c478bd9Sstevel@tonic-gate 				/* exacct_error set above. */
595*7c478bd9Sstevel@tonic-gate 				return (EO_ERROR);
596*7c478bd9Sstevel@tonic-gate 			if (xread(f, buf, sz) != sz) {
597*7c478bd9Sstevel@tonic-gate 				EXACCT_SET_ERR(EXR_CORRUPT_FILE);
598*7c478bd9Sstevel@tonic-gate 				return (EO_ERROR);
599*7c478bd9Sstevel@tonic-gate 			}
600*7c478bd9Sstevel@tonic-gate 		}
601*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_string = buf;
602*7c478bd9Sstevel@tonic-gate 		/*
603*7c478bd9Sstevel@tonic-gate 		 * Maintain our consistent convention that string lengths
604*7c478bd9Sstevel@tonic-gate 		 * include the terminating NULL character.
605*7c478bd9Sstevel@tonic-gate 		 */
606*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_size = sz;
607*7c478bd9Sstevel@tonic-gate 		break;
608*7c478bd9Sstevel@tonic-gate 	case EXT_UINT8:
609*7c478bd9Sstevel@tonic-gate 		if (xread(f, &obj->eo_item.ei_uint8, sizeof (uint8_t)) !=
610*7c478bd9Sstevel@tonic-gate 		    sizeof (uint8_t)) {
611*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
612*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
613*7c478bd9Sstevel@tonic-gate 		}
614*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_size = sizeof (uint8_t);
615*7c478bd9Sstevel@tonic-gate 		break;
616*7c478bd9Sstevel@tonic-gate 	case EXT_UINT16:
617*7c478bd9Sstevel@tonic-gate 		if (xread(f, &obj->eo_item.ei_uint16, sizeof (uint16_t)) !=
618*7c478bd9Sstevel@tonic-gate 		    sizeof (uint16_t)) {
619*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
620*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
621*7c478bd9Sstevel@tonic-gate 		}
622*7c478bd9Sstevel@tonic-gate 		exacct_order16(&obj->eo_item.ei_uint16);
623*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_size = sizeof (uint16_t);
624*7c478bd9Sstevel@tonic-gate 		break;
625*7c478bd9Sstevel@tonic-gate 	case EXT_UINT32:
626*7c478bd9Sstevel@tonic-gate 		if (xread(f, &obj->eo_item.ei_uint32, sizeof (uint32_t)) !=
627*7c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t)) {
628*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
629*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
630*7c478bd9Sstevel@tonic-gate 		}
631*7c478bd9Sstevel@tonic-gate 		exacct_order32(&obj->eo_item.ei_uint32);
632*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_size = sizeof (uint32_t);
633*7c478bd9Sstevel@tonic-gate 		break;
634*7c478bd9Sstevel@tonic-gate 	case EXT_UINT64:
635*7c478bd9Sstevel@tonic-gate 		if (xread(f, &obj->eo_item.ei_uint64, sizeof (uint64_t)) !=
636*7c478bd9Sstevel@tonic-gate 		    sizeof (uint64_t)) {
637*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
638*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
639*7c478bd9Sstevel@tonic-gate 		}
640*7c478bd9Sstevel@tonic-gate 		exacct_order64(&obj->eo_item.ei_uint64);
641*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_size = sizeof (uint64_t);
642*7c478bd9Sstevel@tonic-gate 		break;
643*7c478bd9Sstevel@tonic-gate 	case EXT_DOUBLE:
644*7c478bd9Sstevel@tonic-gate 		if (xread(f, &obj->eo_item.ei_double, sizeof (double)) !=
645*7c478bd9Sstevel@tonic-gate 		    sizeof (double)) {
646*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_CORRUPT_FILE);
647*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
648*7c478bd9Sstevel@tonic-gate 		}
649*7c478bd9Sstevel@tonic-gate 		exacct_order64((uint64_t *)&obj->eo_item.ei_double);
650*7c478bd9Sstevel@tonic-gate 		obj->eo_item.ei_size = sizeof (double);
651*7c478bd9Sstevel@tonic-gate 		break;
652*7c478bd9Sstevel@tonic-gate 	default:
653*7c478bd9Sstevel@tonic-gate 		/*
654*7c478bd9Sstevel@tonic-gate 		 * We've encountered an unknown type value.  Flag the error and
655*7c478bd9Sstevel@tonic-gate 		 * exit.
656*7c478bd9Sstevel@tonic-gate 		 */
657*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
658*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
659*7c478bd9Sstevel@tonic-gate 	}
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	/*
662*7c478bd9Sstevel@tonic-gate 	 * Advance over current large backskip value,
663*7c478bd9Sstevel@tonic-gate 	 * and position at the start of the next object.
664*7c478bd9Sstevel@tonic-gate 	 */
665*7c478bd9Sstevel@tonic-gate 	if (xread(f, &scratch32, sizeof (scratch32)) != sizeof (scratch32)) {
666*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
667*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
668*7c478bd9Sstevel@tonic-gate 	}
669*7c478bd9Sstevel@tonic-gate 	if (stack_next_object(f, xread) == -1) {
670*7c478bd9Sstevel@tonic-gate 		/* exacct_error set above. */
671*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
672*7c478bd9Sstevel@tonic-gate 	}
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate 	f->ef_advance = 0;
675*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
676*7c478bd9Sstevel@tonic-gate 	return (obj->eo_type);
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate 
679*7c478bd9Sstevel@tonic-gate ea_object_type_t
680*7c478bd9Sstevel@tonic-gate ea_get_object(ea_file_t *ef, ea_object_t *obj)
681*7c478bd9Sstevel@tonic-gate {
682*7c478bd9Sstevel@tonic-gate 	obj->eo_next = NULL;
683*7c478bd9Sstevel@tonic-gate 	return (xget_object((ea_file_impl_t *)ef, obj, fread_wrapper,
684*7c478bd9Sstevel@tonic-gate 		    fseek_wrapper, fpos_wrapper, EUP_ALLOC));
685*7c478bd9Sstevel@tonic-gate }
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate /*
688*7c478bd9Sstevel@tonic-gate  * unpack_group() recursively unpacks record groups from the buffer tucked
689*7c478bd9Sstevel@tonic-gate  * within the passed ea_file, and attaches them to grp.
690*7c478bd9Sstevel@tonic-gate  */
691*7c478bd9Sstevel@tonic-gate static int
692*7c478bd9Sstevel@tonic-gate unpack_group(ea_file_impl_t *f, ea_object_t *grp, int flag)
693*7c478bd9Sstevel@tonic-gate {
694*7c478bd9Sstevel@tonic-gate 	ea_object_t *obj;
695*7c478bd9Sstevel@tonic-gate 	uint_t nobjs = grp->eo_group.eg_nobjs;
696*7c478bd9Sstevel@tonic-gate 	int i;
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	/*
699*7c478bd9Sstevel@tonic-gate 	 * Set the group's object count to zero, as we will rebuild it via the
700*7c478bd9Sstevel@tonic-gate 	 * individual object attachments.
701*7c478bd9Sstevel@tonic-gate 	 */
702*7c478bd9Sstevel@tonic-gate 	grp->eo_group.eg_nobjs = 0;
703*7c478bd9Sstevel@tonic-gate 	grp->eo_group.eg_objs = NULL;
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nobjs; i++) {
706*7c478bd9Sstevel@tonic-gate 		if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) {
707*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
708*7c478bd9Sstevel@tonic-gate 			return (-1);
709*7c478bd9Sstevel@tonic-gate 		}
710*7c478bd9Sstevel@tonic-gate 		obj->eo_next = NULL;
711*7c478bd9Sstevel@tonic-gate 		if (xget_object(f, obj, bufread_wrapper, bufseek_wrapper,
712*7c478bd9Sstevel@tonic-gate 			    bufpos_wrapper, flag) == -1) {
713*7c478bd9Sstevel@tonic-gate 			ea_free(obj, sizeof (ea_object_t));
714*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
715*7c478bd9Sstevel@tonic-gate 			return (-1);
716*7c478bd9Sstevel@tonic-gate 		}
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_to_group(grp, obj);
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 		if (obj->eo_type == EO_GROUP &&
721*7c478bd9Sstevel@tonic-gate 		    unpack_group(f, obj, flag) == -1) {
722*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
723*7c478bd9Sstevel@tonic-gate 			return (-1);
724*7c478bd9Sstevel@tonic-gate 		}
725*7c478bd9Sstevel@tonic-gate 	}
726*7c478bd9Sstevel@tonic-gate 
727*7c478bd9Sstevel@tonic-gate 	if (nobjs != grp->eo_group.eg_nobjs) {
728*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_CORRUPT_FILE);
729*7c478bd9Sstevel@tonic-gate 		return (-1);
730*7c478bd9Sstevel@tonic-gate 	}
731*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
732*7c478bd9Sstevel@tonic-gate 	return (0);
733*7c478bd9Sstevel@tonic-gate }
734*7c478bd9Sstevel@tonic-gate 
735*7c478bd9Sstevel@tonic-gate /*
736*7c478bd9Sstevel@tonic-gate  * ea_unpack_object() can be considered as a finite series of get operations on
737*7c478bd9Sstevel@tonic-gate  * a given buffer, that rebuilds the hierarchy of objects compacted by a pack
738*7c478bd9Sstevel@tonic-gate  * operation.  Because there is complex state associated with the group depth,
739*7c478bd9Sstevel@tonic-gate  * ea_unpack_object() must complete as one operation on a given buffer.
740*7c478bd9Sstevel@tonic-gate  */
741*7c478bd9Sstevel@tonic-gate ea_object_type_t
742*7c478bd9Sstevel@tonic-gate ea_unpack_object(ea_object_t **objp, int flag, void *buf, size_t bufsize)
743*7c478bd9Sstevel@tonic-gate {
744*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t fake;
745*7c478bd9Sstevel@tonic-gate 	ea_object_t *obj;
746*7c478bd9Sstevel@tonic-gate 	ea_object_type_t first_obj_type;
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	*objp = NULL;
749*7c478bd9Sstevel@tonic-gate 	if (buf == NULL) {
750*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_BUF);
751*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
752*7c478bd9Sstevel@tonic-gate 	}
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	/* Set up the structures needed for unpacking */
755*7c478bd9Sstevel@tonic-gate 	bzero(&fake, sizeof (ea_file_impl_t));
756*7c478bd9Sstevel@tonic-gate 	if (stack_check(&fake) == -1) {
757*7c478bd9Sstevel@tonic-gate 		/* exacct_errno set above. */
758*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 	fake.ef_buf = buf;
761*7c478bd9Sstevel@tonic-gate 	fake.ef_bufsize = bufsize;
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 	/* Unpack the first object in the buffer - this should succeed. */
764*7c478bd9Sstevel@tonic-gate 	if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) {
765*7c478bd9Sstevel@tonic-gate 		stack_free(&fake);
766*7c478bd9Sstevel@tonic-gate 		/* exacct_errno set above. */
767*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
768*7c478bd9Sstevel@tonic-gate 	}
769*7c478bd9Sstevel@tonic-gate 	obj->eo_next = NULL;
770*7c478bd9Sstevel@tonic-gate 	if ((first_obj_type = xget_object(&fake, obj, bufread_wrapper,
771*7c478bd9Sstevel@tonic-gate 	    bufseek_wrapper, bufpos_wrapper, flag)) == -1) {
772*7c478bd9Sstevel@tonic-gate 		stack_free(&fake);
773*7c478bd9Sstevel@tonic-gate 		ea_free(obj, sizeof (ea_object_t));
774*7c478bd9Sstevel@tonic-gate 		/* exacct_errno set above. */
775*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
776*7c478bd9Sstevel@tonic-gate 	}
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	if (obj->eo_type == EO_GROUP && unpack_group(&fake, obj, flag) == -1) {
779*7c478bd9Sstevel@tonic-gate 		stack_free(&fake);
780*7c478bd9Sstevel@tonic-gate 		ea_free_object(obj, flag);
781*7c478bd9Sstevel@tonic-gate 		/* exacct_errno set above. */
782*7c478bd9Sstevel@tonic-gate 		return (EO_ERROR);
783*7c478bd9Sstevel@tonic-gate 	}
784*7c478bd9Sstevel@tonic-gate 	*objp = obj;
785*7c478bd9Sstevel@tonic-gate 
786*7c478bd9Sstevel@tonic-gate 	/*
787*7c478bd9Sstevel@tonic-gate 	 * There may be other objects in the buffer - if so, chain them onto
788*7c478bd9Sstevel@tonic-gate 	 * the end of the list.  We have reached the end of the list when
789*7c478bd9Sstevel@tonic-gate 	 * xget_object() returns -1 with exacct_error set to EXR_EOF.
790*7c478bd9Sstevel@tonic-gate 	 */
791*7c478bd9Sstevel@tonic-gate 	for (;;) {
792*7c478bd9Sstevel@tonic-gate 		if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) {
793*7c478bd9Sstevel@tonic-gate 			stack_free(&fake);
794*7c478bd9Sstevel@tonic-gate 			ea_free_object(*objp, flag);
795*7c478bd9Sstevel@tonic-gate 			*objp = NULL;
796*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
797*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
798*7c478bd9Sstevel@tonic-gate 		}
799*7c478bd9Sstevel@tonic-gate 		obj->eo_next = NULL;
800*7c478bd9Sstevel@tonic-gate 		if (xget_object(&fake, obj, bufread_wrapper, bufseek_wrapper,
801*7c478bd9Sstevel@tonic-gate 			    bufpos_wrapper, flag) == -1) {
802*7c478bd9Sstevel@tonic-gate 			stack_free(&fake);
803*7c478bd9Sstevel@tonic-gate 			ea_free(obj, sizeof (ea_object_t));
804*7c478bd9Sstevel@tonic-gate 			if (ea_error() == EXR_EOF) {
805*7c478bd9Sstevel@tonic-gate 				EXACCT_SET_ERR(EXR_OK);
806*7c478bd9Sstevel@tonic-gate 				return (first_obj_type);
807*7c478bd9Sstevel@tonic-gate 			} else {
808*7c478bd9Sstevel@tonic-gate 				ea_free_object(*objp, flag);
809*7c478bd9Sstevel@tonic-gate 				*objp = NULL;
810*7c478bd9Sstevel@tonic-gate 				/* exacct_error set above. */
811*7c478bd9Sstevel@tonic-gate 				return (EO_ERROR);
812*7c478bd9Sstevel@tonic-gate 			}
813*7c478bd9Sstevel@tonic-gate 		}
814*7c478bd9Sstevel@tonic-gate 
815*7c478bd9Sstevel@tonic-gate 		(void) ea_attach_to_object(*objp, obj);
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 		if (obj->eo_type == EO_GROUP &&
818*7c478bd9Sstevel@tonic-gate 		    unpack_group(&fake, obj, flag) == -1) {
819*7c478bd9Sstevel@tonic-gate 			stack_free(&fake);
820*7c478bd9Sstevel@tonic-gate 			ea_free(obj, sizeof (ea_object_t));
821*7c478bd9Sstevel@tonic-gate 			ea_free_object(*objp, flag);
822*7c478bd9Sstevel@tonic-gate 			*objp = NULL;
823*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
824*7c478bd9Sstevel@tonic-gate 			return (EO_ERROR);
825*7c478bd9Sstevel@tonic-gate 		}
826*7c478bd9Sstevel@tonic-gate 	}
827*7c478bd9Sstevel@tonic-gate }
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate int
830*7c478bd9Sstevel@tonic-gate ea_write_object(ea_file_t *ef, ea_object_t *obj)
831*7c478bd9Sstevel@tonic-gate {
832*7c478bd9Sstevel@tonic-gate 	ea_size_t sz;
833*7c478bd9Sstevel@tonic-gate 	void *buf;
834*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 	/*
837*7c478bd9Sstevel@tonic-gate 	 * If we weren't opened for writing, this call fails.
838*7c478bd9Sstevel@tonic-gate 	 */
839*7c478bd9Sstevel@tonic-gate 	if ((f->ef_oflags & O_RDWR) == 0 &&
840*7c478bd9Sstevel@tonic-gate 	    (f->ef_oflags & O_WRONLY) == 0) {
841*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_NOTSUPP);
842*7c478bd9Sstevel@tonic-gate 		return (-1);
843*7c478bd9Sstevel@tonic-gate 	}
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 	/* Pack with a null buffer to get the size. */
846*7c478bd9Sstevel@tonic-gate 	sz = ea_pack_object(obj, NULL, 0);
847*7c478bd9Sstevel@tonic-gate 	if (sz == -1 || (buf = ea_alloc(sz)) == NULL) {
848*7c478bd9Sstevel@tonic-gate 		/* exacct_error set above. */
849*7c478bd9Sstevel@tonic-gate 		return (-1);
850*7c478bd9Sstevel@tonic-gate 	}
851*7c478bd9Sstevel@tonic-gate 	if (ea_pack_object(obj, buf, sz) == (size_t)-1) {
852*7c478bd9Sstevel@tonic-gate 		ea_free(buf, sz);
853*7c478bd9Sstevel@tonic-gate 		/* exacct_error set above. */
854*7c478bd9Sstevel@tonic-gate 		return (-1);
855*7c478bd9Sstevel@tonic-gate 	}
856*7c478bd9Sstevel@tonic-gate 	if (fwrite(buf, sizeof (char), sz, f->ef_fp) != sz) {
857*7c478bd9Sstevel@tonic-gate 		ea_free(buf, sz);
858*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
859*7c478bd9Sstevel@tonic-gate 		return (-1);
860*7c478bd9Sstevel@tonic-gate 	}
861*7c478bd9Sstevel@tonic-gate 	ea_free(buf, sz);
862*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
863*7c478bd9Sstevel@tonic-gate 	return (0);
864*7c478bd9Sstevel@tonic-gate }
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate /*
867*7c478bd9Sstevel@tonic-gate  * validate_header() must be kept in sync with write_header(), given below, and
868*7c478bd9Sstevel@tonic-gate  * exacct_create_header(), in uts/common/os/exacct.c.
869*7c478bd9Sstevel@tonic-gate  */
870*7c478bd9Sstevel@tonic-gate static int
871*7c478bd9Sstevel@tonic-gate validate_header(ea_file_t *ef, const char *creator)
872*7c478bd9Sstevel@tonic-gate {
873*7c478bd9Sstevel@tonic-gate 	ea_object_t hdr_grp;
874*7c478bd9Sstevel@tonic-gate 	ea_object_t scratch_obj;
875*7c478bd9Sstevel@tonic-gate 	int error = EXR_OK;
876*7c478bd9Sstevel@tonic-gate 	int saw_creator = 0;
877*7c478bd9Sstevel@tonic-gate 	int saw_version = 0;
878*7c478bd9Sstevel@tonic-gate 	int saw_type = 0;
879*7c478bd9Sstevel@tonic-gate 	int saw_hostname = 0;
880*7c478bd9Sstevel@tonic-gate 	int n;
881*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
882*7c478bd9Sstevel@tonic-gate 
883*7c478bd9Sstevel@tonic-gate 	bzero(&hdr_grp, sizeof (ea_object_t));
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	if (ea_get_object(ef, &hdr_grp) != EO_GROUP) {
886*7c478bd9Sstevel@tonic-gate 		error = ea_error();
887*7c478bd9Sstevel@tonic-gate 		goto error_case;
888*7c478bd9Sstevel@tonic-gate 	}
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate 	if (hdr_grp.eo_catalog !=
891*7c478bd9Sstevel@tonic-gate 	    (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER)) {
892*7c478bd9Sstevel@tonic-gate 		error = EXR_CORRUPT_FILE;
893*7c478bd9Sstevel@tonic-gate 		goto error_case;
894*7c478bd9Sstevel@tonic-gate 	}
895*7c478bd9Sstevel@tonic-gate 
896*7c478bd9Sstevel@tonic-gate 	for (n = 0; n < hdr_grp.eo_group.eg_nobjs; n++) {
897*7c478bd9Sstevel@tonic-gate 		bzero(&scratch_obj, sizeof (ea_object_t));
898*7c478bd9Sstevel@tonic-gate 		if (ea_get_object(ef, &scratch_obj) == -1) {
899*7c478bd9Sstevel@tonic-gate 			error = ea_error();
900*7c478bd9Sstevel@tonic-gate 			goto error_case;
901*7c478bd9Sstevel@tonic-gate 		}
902*7c478bd9Sstevel@tonic-gate 
903*7c478bd9Sstevel@tonic-gate 		switch (scratch_obj.eo_catalog) {
904*7c478bd9Sstevel@tonic-gate 		case EXT_UINT32 | EXC_DEFAULT | EXD_VERSION:
905*7c478bd9Sstevel@tonic-gate 			if (scratch_obj.eo_item.ei_uint32 != EXACCT_VERSION) {
906*7c478bd9Sstevel@tonic-gate 				error = EXR_UNKN_VERSION;
907*7c478bd9Sstevel@tonic-gate 				goto error_case;
908*7c478bd9Sstevel@tonic-gate 			}
909*7c478bd9Sstevel@tonic-gate 			saw_version++;
910*7c478bd9Sstevel@tonic-gate 			break;
911*7c478bd9Sstevel@tonic-gate 		case EXT_STRING | EXC_DEFAULT | EXD_FILETYPE:
912*7c478bd9Sstevel@tonic-gate 			if (strcmp(scratch_obj.eo_item.ei_string,
913*7c478bd9Sstevel@tonic-gate 			    EXACCT_HDR_STR) != 0) {
914*7c478bd9Sstevel@tonic-gate 				error = EXR_CORRUPT_FILE;
915*7c478bd9Sstevel@tonic-gate 				goto error_case;
916*7c478bd9Sstevel@tonic-gate 			}
917*7c478bd9Sstevel@tonic-gate 			saw_type++;
918*7c478bd9Sstevel@tonic-gate 			break;
919*7c478bd9Sstevel@tonic-gate 		case EXT_STRING | EXC_DEFAULT | EXD_CREATOR:
920*7c478bd9Sstevel@tonic-gate 			f->ef_creator =
921*7c478bd9Sstevel@tonic-gate 			    ea_strdup(scratch_obj.eo_item.ei_string);
922*7c478bd9Sstevel@tonic-gate 			if (f->ef_creator == NULL) {
923*7c478bd9Sstevel@tonic-gate 				error = ea_error();
924*7c478bd9Sstevel@tonic-gate 				goto error_case;
925*7c478bd9Sstevel@tonic-gate 			}
926*7c478bd9Sstevel@tonic-gate 			saw_creator++;
927*7c478bd9Sstevel@tonic-gate 			break;
928*7c478bd9Sstevel@tonic-gate 		/* The hostname is an optional field. */
929*7c478bd9Sstevel@tonic-gate 		case EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME:
930*7c478bd9Sstevel@tonic-gate 			f->ef_hostname =
931*7c478bd9Sstevel@tonic-gate 			    ea_strdup(scratch_obj.eo_item.ei_string);
932*7c478bd9Sstevel@tonic-gate 			if (f->ef_hostname == NULL) {
933*7c478bd9Sstevel@tonic-gate 				error = ea_error();
934*7c478bd9Sstevel@tonic-gate 				goto error_case;
935*7c478bd9Sstevel@tonic-gate 			}
936*7c478bd9Sstevel@tonic-gate 			saw_hostname++;
937*7c478bd9Sstevel@tonic-gate 			break;
938*7c478bd9Sstevel@tonic-gate 		default:
939*7c478bd9Sstevel@tonic-gate 			/* ignore unrecognized header members */
940*7c478bd9Sstevel@tonic-gate 			break;
941*7c478bd9Sstevel@tonic-gate 		}
942*7c478bd9Sstevel@tonic-gate 		(void) ea_free_item(&scratch_obj, EUP_ALLOC);
943*7c478bd9Sstevel@tonic-gate 	}
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	if (saw_version && saw_type && saw_creator) {
946*7c478bd9Sstevel@tonic-gate 		if (creator && strcmp(f->ef_creator, creator) != 0) {
947*7c478bd9Sstevel@tonic-gate 			error = EXR_NO_CREATOR;
948*7c478bd9Sstevel@tonic-gate 			goto error_case;
949*7c478bd9Sstevel@tonic-gate 		}
950*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_OK);
951*7c478bd9Sstevel@tonic-gate 		return (0);
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate error_case:
955*7c478bd9Sstevel@tonic-gate 	(void) ea_free_item(&scratch_obj, EUP_ALLOC);
956*7c478bd9Sstevel@tonic-gate 	if (saw_hostname)
957*7c478bd9Sstevel@tonic-gate 		ea_strfree(f->ef_hostname);
958*7c478bd9Sstevel@tonic-gate 	if (saw_creator)
959*7c478bd9Sstevel@tonic-gate 		ea_strfree(f->ef_creator);
960*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(error);
961*7c478bd9Sstevel@tonic-gate 	return (-1);
962*7c478bd9Sstevel@tonic-gate }
963*7c478bd9Sstevel@tonic-gate 
964*7c478bd9Sstevel@tonic-gate static int
965*7c478bd9Sstevel@tonic-gate write_header(ea_file_t *ef)
966*7c478bd9Sstevel@tonic-gate {
967*7c478bd9Sstevel@tonic-gate 	ea_object_t hdr_grp;
968*7c478bd9Sstevel@tonic-gate 	ea_object_t vers_obj;
969*7c478bd9Sstevel@tonic-gate 	ea_object_t creator_obj;
970*7c478bd9Sstevel@tonic-gate 	ea_object_t filetype_obj;
971*7c478bd9Sstevel@tonic-gate 	ea_object_t hostname_obj;
972*7c478bd9Sstevel@tonic-gate 	uint32_t bskip;
973*7c478bd9Sstevel@tonic-gate 	const uint32_t version = EXACCT_VERSION;
974*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
975*7c478bd9Sstevel@tonic-gate 	void *buf;
976*7c478bd9Sstevel@tonic-gate 	size_t bufsize;
977*7c478bd9Sstevel@tonic-gate 	char hostbuf[SYSINFO_BUFSIZE];
978*7c478bd9Sstevel@tonic-gate 	int error = EXR_OK;
979*7c478bd9Sstevel@tonic-gate 
980*7c478bd9Sstevel@tonic-gate 	bzero(&hdr_grp, sizeof (ea_object_t));
981*7c478bd9Sstevel@tonic-gate 	bzero(&vers_obj, sizeof (ea_object_t));
982*7c478bd9Sstevel@tonic-gate 	bzero(&creator_obj, sizeof (ea_object_t));
983*7c478bd9Sstevel@tonic-gate 	bzero(&filetype_obj, sizeof (ea_object_t));
984*7c478bd9Sstevel@tonic-gate 	bzero(&hostname_obj, sizeof (ea_object_t));
985*7c478bd9Sstevel@tonic-gate 	bzero(hostbuf, SYSINFO_BUFSIZE);
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	(void) sysinfo(SI_HOSTNAME, hostbuf, SYSINFO_BUFSIZE);
988*7c478bd9Sstevel@tonic-gate 
989*7c478bd9Sstevel@tonic-gate 	if (ea_set_item(&vers_obj, EXT_UINT32 | EXC_DEFAULT | EXD_VERSION,
990*7c478bd9Sstevel@tonic-gate 		    (void *)&version, 0) == -1 ||
991*7c478bd9Sstevel@tonic-gate 	    ea_set_item(&creator_obj, EXT_STRING | EXC_DEFAULT | EXD_CREATOR,
992*7c478bd9Sstevel@tonic-gate 		    f->ef_creator, strlen(f->ef_creator)) == -1 ||
993*7c478bd9Sstevel@tonic-gate 	    ea_set_item(&filetype_obj, EXT_STRING | EXC_DEFAULT | EXD_FILETYPE,
994*7c478bd9Sstevel@tonic-gate 		    EXACCT_HDR_STR, strlen(EXACCT_HDR_STR)) == -1 ||
995*7c478bd9Sstevel@tonic-gate 	    ea_set_item(&hostname_obj, EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME,
996*7c478bd9Sstevel@tonic-gate 		    hostbuf, strlen(hostbuf)) == -1) {
997*7c478bd9Sstevel@tonic-gate 		error = ea_error();
998*7c478bd9Sstevel@tonic-gate 		goto cleanup1;
999*7c478bd9Sstevel@tonic-gate 	}
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	(void) ea_set_group(&hdr_grp,
1002*7c478bd9Sstevel@tonic-gate 	    EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER);
1003*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_to_group(&hdr_grp, &vers_obj);
1004*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_to_group(&hdr_grp, &creator_obj);
1005*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_to_group(&hdr_grp, &filetype_obj);
1006*7c478bd9Sstevel@tonic-gate 	(void) ea_attach_to_group(&hdr_grp, &hostname_obj);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	/* Get the required size by passing a null buffer. */
1009*7c478bd9Sstevel@tonic-gate 	bufsize = ea_pack_object(&hdr_grp, NULL, 0);
1010*7c478bd9Sstevel@tonic-gate 	if ((buf = ea_alloc(bufsize)) == NULL) {
1011*7c478bd9Sstevel@tonic-gate 		error = ea_error();
1012*7c478bd9Sstevel@tonic-gate 		goto cleanup1;
1013*7c478bd9Sstevel@tonic-gate 	}
1014*7c478bd9Sstevel@tonic-gate 
1015*7c478bd9Sstevel@tonic-gate 	if (ea_pack_object(&hdr_grp, buf, bufsize) == (size_t)-1) {
1016*7c478bd9Sstevel@tonic-gate 		error = ea_error();
1017*7c478bd9Sstevel@tonic-gate 		goto cleanup2;
1018*7c478bd9Sstevel@tonic-gate 	}
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	/*
1021*7c478bd9Sstevel@tonic-gate 	 * To prevent reading the header when reading the file backwards,
1022*7c478bd9Sstevel@tonic-gate 	 * set the large backskip of the header group to 0 (last 4 bytes).
1023*7c478bd9Sstevel@tonic-gate 	 */
1024*7c478bd9Sstevel@tonic-gate 	bskip = 0;
1025*7c478bd9Sstevel@tonic-gate 	exacct_order32(&bskip);
1026*7c478bd9Sstevel@tonic-gate 	bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip),
1027*7c478bd9Sstevel@tonic-gate 	    sizeof (bskip));
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	if (fwrite(buf, sizeof (char), bufsize, f->ef_fp) != bufsize ||
1030*7c478bd9Sstevel@tonic-gate 	    fflush(f->ef_fp) == EOF) {
1031*7c478bd9Sstevel@tonic-gate 		error = EXR_SYSCALL_FAIL;
1032*7c478bd9Sstevel@tonic-gate 		goto cleanup2;
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate cleanup2:
1036*7c478bd9Sstevel@tonic-gate 	ea_free(buf, bufsize);
1037*7c478bd9Sstevel@tonic-gate cleanup1:
1038*7c478bd9Sstevel@tonic-gate 	(void) ea_free_item(&vers_obj, EUP_ALLOC);
1039*7c478bd9Sstevel@tonic-gate 	(void) ea_free_item(&creator_obj, EUP_ALLOC);
1040*7c478bd9Sstevel@tonic-gate 	(void) ea_free_item(&filetype_obj, EUP_ALLOC);
1041*7c478bd9Sstevel@tonic-gate 	(void) ea_free_item(&hostname_obj, EUP_ALLOC);
1042*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(error);
1043*7c478bd9Sstevel@tonic-gate 	return (error == EXR_OK ? 0 : -1);
1044*7c478bd9Sstevel@tonic-gate }
1045*7c478bd9Sstevel@tonic-gate 
1046*7c478bd9Sstevel@tonic-gate const char *
1047*7c478bd9Sstevel@tonic-gate ea_get_creator(ea_file_t *ef)
1048*7c478bd9Sstevel@tonic-gate {
1049*7c478bd9Sstevel@tonic-gate 	return ((const char *)((ea_file_impl_t *)ef)->ef_creator);
1050*7c478bd9Sstevel@tonic-gate }
1051*7c478bd9Sstevel@tonic-gate 
1052*7c478bd9Sstevel@tonic-gate const char *
1053*7c478bd9Sstevel@tonic-gate ea_get_hostname(ea_file_t *ef)
1054*7c478bd9Sstevel@tonic-gate {
1055*7c478bd9Sstevel@tonic-gate 	return ((const char *)((ea_file_impl_t *)ef)->ef_hostname);
1056*7c478bd9Sstevel@tonic-gate }
1057*7c478bd9Sstevel@tonic-gate 
1058*7c478bd9Sstevel@tonic-gate int
1059*7c478bd9Sstevel@tonic-gate ea_fdopen(ea_file_t *ef, int fd, const char *creator, int aflags, int oflags)
1060*7c478bd9Sstevel@tonic-gate {
1061*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 	bzero(f, sizeof (*f));
1064*7c478bd9Sstevel@tonic-gate 	f->ef_oflags = oflags;
1065*7c478bd9Sstevel@tonic-gate 	f->ef_fd = fd;
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 	/* Initialize depth stack. */
1068*7c478bd9Sstevel@tonic-gate 	if (stack_check(f) == -1) {
1069*7c478bd9Sstevel@tonic-gate 		/* exacct_error set above. */
1070*7c478bd9Sstevel@tonic-gate 		goto error1;
1071*7c478bd9Sstevel@tonic-gate 	}
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	/*
1074*7c478bd9Sstevel@tonic-gate 	 * 1.  If we are O_CREAT, then we will need to write a header
1075*7c478bd9Sstevel@tonic-gate 	 * after opening name.
1076*7c478bd9Sstevel@tonic-gate 	 */
1077*7c478bd9Sstevel@tonic-gate 	if (oflags & O_CREAT) {
1078*7c478bd9Sstevel@tonic-gate 		if (creator == NULL) {
1079*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_NO_CREATOR);
1080*7c478bd9Sstevel@tonic-gate 			goto error2;
1081*7c478bd9Sstevel@tonic-gate 		}
1082*7c478bd9Sstevel@tonic-gate 		if ((f->ef_creator = ea_strdup(creator)) == NULL) {
1083*7c478bd9Sstevel@tonic-gate 			/* exacct_error set above. */
1084*7c478bd9Sstevel@tonic-gate 			goto error2;
1085*7c478bd9Sstevel@tonic-gate 		}
1086*7c478bd9Sstevel@tonic-gate 		if ((f->ef_fp = fdopen(f->ef_fd, "w")) == NULL) {
1087*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1088*7c478bd9Sstevel@tonic-gate 			goto error3;
1089*7c478bd9Sstevel@tonic-gate 		}
1090*7c478bd9Sstevel@tonic-gate 		if (write_header(ef) == -1) {
1091*7c478bd9Sstevel@tonic-gate 			/* exacct_error set above. */
1092*7c478bd9Sstevel@tonic-gate 			goto error3;
1093*7c478bd9Sstevel@tonic-gate 		}
1094*7c478bd9Sstevel@tonic-gate 
1095*7c478bd9Sstevel@tonic-gate 	/*
1096*7c478bd9Sstevel@tonic-gate 	 * 2.  If we are not O_CREAT, but are RDWR or WRONLY, we need to
1097*7c478bd9Sstevel@tonic-gate 	 * seek to EOF so that appends will succeed.
1098*7c478bd9Sstevel@tonic-gate 	 */
1099*7c478bd9Sstevel@tonic-gate 	} else if (oflags & O_RDWR || oflags & O_WRONLY) {
1100*7c478bd9Sstevel@tonic-gate 		if ((f->ef_fp = fdopen(f->ef_fd, "r+")) == NULL) {
1101*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1102*7c478bd9Sstevel@tonic-gate 			goto error2;
1103*7c478bd9Sstevel@tonic-gate 		}
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 		if ((aflags & EO_VALIDATE_MSK) == EO_VALID_HDR) {
1106*7c478bd9Sstevel@tonic-gate 			if (validate_header(ef, creator) < 0) {
1107*7c478bd9Sstevel@tonic-gate 				/* exacct_error set above. */
1108*7c478bd9Sstevel@tonic-gate 				goto error2;
1109*7c478bd9Sstevel@tonic-gate 			}
1110*7c478bd9Sstevel@tonic-gate 		}
1111*7c478bd9Sstevel@tonic-gate 
1112*7c478bd9Sstevel@tonic-gate 		if (fseeko(f->ef_fp, 0, SEEK_END) == -1) {
1113*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1114*7c478bd9Sstevel@tonic-gate 			goto error2;
1115*7c478bd9Sstevel@tonic-gate 		}
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate 	/*
1118*7c478bd9Sstevel@tonic-gate 	 * 3. This is an undefined manner for opening an exacct file.
1119*7c478bd9Sstevel@tonic-gate 	 */
1120*7c478bd9Sstevel@tonic-gate 	} else if (oflags != O_RDONLY) {
1121*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_NOTSUPP);
1122*7c478bd9Sstevel@tonic-gate 		goto error2;
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 	/*
1125*7c478bd9Sstevel@tonic-gate 	 * 4a.  If we are RDONLY, then we are in a position such that
1126*7c478bd9Sstevel@tonic-gate 	 * either a ea_get_object or an ea_next_object will succeed.  If
1127*7c478bd9Sstevel@tonic-gate 	 * aflags was set to EO_TAIL, seek to the end of the file.
1128*7c478bd9Sstevel@tonic-gate 	 */
1129*7c478bd9Sstevel@tonic-gate 	} else {
1130*7c478bd9Sstevel@tonic-gate 		if ((f->ef_fp = fdopen(f->ef_fd, "r")) == NULL) {
1131*7c478bd9Sstevel@tonic-gate 			EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1132*7c478bd9Sstevel@tonic-gate 			goto error2;
1133*7c478bd9Sstevel@tonic-gate 		}
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate 		if ((aflags & EO_VALIDATE_MSK) == EO_VALID_HDR) {
1136*7c478bd9Sstevel@tonic-gate 			if (validate_header(ef, creator) == -1) {
1137*7c478bd9Sstevel@tonic-gate 				/* exacct_error set above. */
1138*7c478bd9Sstevel@tonic-gate 				goto error2;
1139*7c478bd9Sstevel@tonic-gate 			}
1140*7c478bd9Sstevel@tonic-gate 		}
1141*7c478bd9Sstevel@tonic-gate 
1142*7c478bd9Sstevel@tonic-gate 		/*
1143*7c478bd9Sstevel@tonic-gate 		 * 4b.  Handle the "open at end" option, for consumers who want
1144*7c478bd9Sstevel@tonic-gate 		 * to go backwards through the file (i.e. lastcomm).
1145*7c478bd9Sstevel@tonic-gate 		 */
1146*7c478bd9Sstevel@tonic-gate 		if ((aflags & EO_POSN_MSK) == EO_TAIL) {
1147*7c478bd9Sstevel@tonic-gate 			if (fseeko(f->ef_fp, 0, SEEK_END) < 0) {
1148*7c478bd9Sstevel@tonic-gate 				EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1149*7c478bd9Sstevel@tonic-gate 				goto error2;
1150*7c478bd9Sstevel@tonic-gate 			}
1151*7c478bd9Sstevel@tonic-gate 		}
1152*7c478bd9Sstevel@tonic-gate 	}
1153*7c478bd9Sstevel@tonic-gate 
1154*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
1155*7c478bd9Sstevel@tonic-gate 	return (0);
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	/* Error cleanup code */
1158*7c478bd9Sstevel@tonic-gate error3:
1159*7c478bd9Sstevel@tonic-gate 	ea_strfree(f->ef_creator);
1160*7c478bd9Sstevel@tonic-gate error2:
1161*7c478bd9Sstevel@tonic-gate 	stack_free(f);
1162*7c478bd9Sstevel@tonic-gate error1:
1163*7c478bd9Sstevel@tonic-gate 	bzero(f, sizeof (*f));
1164*7c478bd9Sstevel@tonic-gate 	return (-1);
1165*7c478bd9Sstevel@tonic-gate }
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate int
1168*7c478bd9Sstevel@tonic-gate ea_open(ea_file_t *ef, const char *name, const char *creator,
1169*7c478bd9Sstevel@tonic-gate     int aflags, int oflags, mode_t mode)
1170*7c478bd9Sstevel@tonic-gate {
1171*7c478bd9Sstevel@tonic-gate 	int fd;
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate 	/*
1174*7c478bd9Sstevel@tonic-gate 	 * If overwriting an existing file, make sure to truncate it
1175*7c478bd9Sstevel@tonic-gate 	 * to prevent the file being created corrupt.
1176*7c478bd9Sstevel@tonic-gate 	 */
1177*7c478bd9Sstevel@tonic-gate 	if (oflags & O_CREAT)
1178*7c478bd9Sstevel@tonic-gate 		oflags |= O_TRUNC;
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	if ((fd = open(name, oflags, mode)) == -1) {
1181*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1182*7c478bd9Sstevel@tonic-gate 		return (-1);
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate 
1185*7c478bd9Sstevel@tonic-gate 	if (ea_fdopen(ef, fd, creator, aflags, oflags) == -1) {
1186*7c478bd9Sstevel@tonic-gate 		(void) close(fd);
1187*7c478bd9Sstevel@tonic-gate 		return (-1);
1188*7c478bd9Sstevel@tonic-gate 	}
1189*7c478bd9Sstevel@tonic-gate 
1190*7c478bd9Sstevel@tonic-gate 	return (0);
1191*7c478bd9Sstevel@tonic-gate }
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate /*
1194*7c478bd9Sstevel@tonic-gate  * ea_close() performs all appropriate close operations on the open exacct file,
1195*7c478bd9Sstevel@tonic-gate  * including releasing any memory allocated while parsing the file.
1196*7c478bd9Sstevel@tonic-gate  */
1197*7c478bd9Sstevel@tonic-gate int
1198*7c478bd9Sstevel@tonic-gate ea_close(ea_file_t *ef)
1199*7c478bd9Sstevel@tonic-gate {
1200*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
1201*7c478bd9Sstevel@tonic-gate 
1202*7c478bd9Sstevel@tonic-gate 	if (f->ef_creator != NULL)
1203*7c478bd9Sstevel@tonic-gate 		ea_strfree(f->ef_creator);
1204*7c478bd9Sstevel@tonic-gate 	if (f->ef_hostname != NULL)
1205*7c478bd9Sstevel@tonic-gate 		ea_strfree(f->ef_hostname);
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate 	ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t));
1208*7c478bd9Sstevel@tonic-gate 
1209*7c478bd9Sstevel@tonic-gate 	if (fclose(f->ef_fp)) {
1210*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
1211*7c478bd9Sstevel@tonic-gate 		return (-1);
1212*7c478bd9Sstevel@tonic-gate 	}
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
1215*7c478bd9Sstevel@tonic-gate 	return (0);
1216*7c478bd9Sstevel@tonic-gate }
1217*7c478bd9Sstevel@tonic-gate 
1218*7c478bd9Sstevel@tonic-gate /*
1219*7c478bd9Sstevel@tonic-gate  * Empty the input buffer and clear any underlying EOF or error bits set on the
1220*7c478bd9Sstevel@tonic-gate  * underlying FILE.  This can be used by any library clients who wish to handle
1221*7c478bd9Sstevel@tonic-gate  * files that are in motion or who wish to seek the underlying file descriptor.
1222*7c478bd9Sstevel@tonic-gate  */
1223*7c478bd9Sstevel@tonic-gate void
1224*7c478bd9Sstevel@tonic-gate ea_clear(ea_file_t *ef)
1225*7c478bd9Sstevel@tonic-gate {
1226*7c478bd9Sstevel@tonic-gate 	ea_file_impl_t *f = (ea_file_impl_t *)ef;
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	(void) fflush(f->ef_fp);
1229*7c478bd9Sstevel@tonic-gate 	clearerr(f->ef_fp);
1230*7c478bd9Sstevel@tonic-gate }
1231*7c478bd9Sstevel@tonic-gate 
1232*7c478bd9Sstevel@tonic-gate /*
1233*7c478bd9Sstevel@tonic-gate  * Copy an ea_object_t.  Note that in the case of a group, just the group
1234*7c478bd9Sstevel@tonic-gate  * object will be copied, and not its list of members.  To recursively copy
1235*7c478bd9Sstevel@tonic-gate  * a group or a list of items use ea_copy_tree().
1236*7c478bd9Sstevel@tonic-gate  */
1237*7c478bd9Sstevel@tonic-gate ea_object_t *
1238*7c478bd9Sstevel@tonic-gate ea_copy_object(const ea_object_t *src)
1239*7c478bd9Sstevel@tonic-gate {
1240*7c478bd9Sstevel@tonic-gate 	ea_object_t *dst;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	/* Allocate a new object and copy to it. */
1243*7c478bd9Sstevel@tonic-gate 	if ((dst = ea_alloc(sizeof (ea_object_t))) == NULL) {
1244*7c478bd9Sstevel@tonic-gate 		return (NULL);
1245*7c478bd9Sstevel@tonic-gate 	}
1246*7c478bd9Sstevel@tonic-gate 	bcopy(src, dst, sizeof (ea_object_t));
1247*7c478bd9Sstevel@tonic-gate 	dst->eo_next = NULL;
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	switch (src->eo_type) {
1250*7c478bd9Sstevel@tonic-gate 	case EO_GROUP:
1251*7c478bd9Sstevel@tonic-gate 		dst->eo_group.eg_nobjs = 0;
1252*7c478bd9Sstevel@tonic-gate 		dst->eo_group.eg_objs = NULL;
1253*7c478bd9Sstevel@tonic-gate 		break;
1254*7c478bd9Sstevel@tonic-gate 	case EO_ITEM:
1255*7c478bd9Sstevel@tonic-gate 		/* Items containing pointers need special treatment. */
1256*7c478bd9Sstevel@tonic-gate 		switch (src->eo_catalog & EXT_TYPE_MASK) {
1257*7c478bd9Sstevel@tonic-gate 		case EXT_STRING:
1258*7c478bd9Sstevel@tonic-gate 			if (src->eo_item.ei_string != NULL) {
1259*7c478bd9Sstevel@tonic-gate 				dst->eo_item.ei_string =
1260*7c478bd9Sstevel@tonic-gate 				    ea_strdup(src->eo_item.ei_string);
1261*7c478bd9Sstevel@tonic-gate 				if (dst->eo_item.ei_string == NULL) {
1262*7c478bd9Sstevel@tonic-gate 					ea_free_object(dst, EUP_ALLOC);
1263*7c478bd9Sstevel@tonic-gate 					return (NULL);
1264*7c478bd9Sstevel@tonic-gate 				}
1265*7c478bd9Sstevel@tonic-gate 			}
1266*7c478bd9Sstevel@tonic-gate 			break;
1267*7c478bd9Sstevel@tonic-gate 		case EXT_RAW:
1268*7c478bd9Sstevel@tonic-gate 			if (src->eo_item.ei_raw != NULL) {
1269*7c478bd9Sstevel@tonic-gate 				dst->eo_item.ei_raw =
1270*7c478bd9Sstevel@tonic-gate 				    ea_alloc(src->eo_item.ei_size);
1271*7c478bd9Sstevel@tonic-gate 				if (dst->eo_item.ei_raw == NULL) {
1272*7c478bd9Sstevel@tonic-gate 					ea_free_object(dst, EUP_ALLOC);
1273*7c478bd9Sstevel@tonic-gate 					return (NULL);
1274*7c478bd9Sstevel@tonic-gate 				}
1275*7c478bd9Sstevel@tonic-gate 				bcopy(src->eo_item.ei_raw, dst->eo_item.ei_raw,
1276*7c478bd9Sstevel@tonic-gate 				    (size_t)src->eo_item.ei_size);
1277*7c478bd9Sstevel@tonic-gate 			}
1278*7c478bd9Sstevel@tonic-gate 			break;
1279*7c478bd9Sstevel@tonic-gate 		case EXT_EXACCT_OBJECT:
1280*7c478bd9Sstevel@tonic-gate 			if (src->eo_item.ei_object != NULL) {
1281*7c478bd9Sstevel@tonic-gate 				dst->eo_item.ei_object =
1282*7c478bd9Sstevel@tonic-gate 				    ea_alloc(src->eo_item.ei_size);
1283*7c478bd9Sstevel@tonic-gate 				if (dst->eo_item.ei_object == NULL) {
1284*7c478bd9Sstevel@tonic-gate 					ea_free_object(dst, EUP_ALLOC);
1285*7c478bd9Sstevel@tonic-gate 					return (NULL);
1286*7c478bd9Sstevel@tonic-gate 				}
1287*7c478bd9Sstevel@tonic-gate 				bcopy(src->eo_item.ei_raw, dst->eo_item.ei_raw,
1288*7c478bd9Sstevel@tonic-gate 				    (size_t)src->eo_item.ei_size);
1289*7c478bd9Sstevel@tonic-gate 			}
1290*7c478bd9Sstevel@tonic-gate 			break;
1291*7c478bd9Sstevel@tonic-gate 		default:
1292*7c478bd9Sstevel@tonic-gate 			/* Other item types require no special handling. */
1293*7c478bd9Sstevel@tonic-gate 			break;
1294*7c478bd9Sstevel@tonic-gate 		}
1295*7c478bd9Sstevel@tonic-gate 		break;
1296*7c478bd9Sstevel@tonic-gate 	default:
1297*7c478bd9Sstevel@tonic-gate 		ea_free_object(dst, EUP_ALLOC);
1298*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
1299*7c478bd9Sstevel@tonic-gate 		return (NULL);
1300*7c478bd9Sstevel@tonic-gate 	}
1301*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
1302*7c478bd9Sstevel@tonic-gate 	return (dst);
1303*7c478bd9Sstevel@tonic-gate }
1304*7c478bd9Sstevel@tonic-gate 
1305*7c478bd9Sstevel@tonic-gate /*
1306*7c478bd9Sstevel@tonic-gate  * Recursively copy a list of ea_object_t.  All the elements in the eo_next
1307*7c478bd9Sstevel@tonic-gate  * list will be copied, and any group objects will be recursively copied.
1308*7c478bd9Sstevel@tonic-gate  */
1309*7c478bd9Sstevel@tonic-gate ea_object_t *
1310*7c478bd9Sstevel@tonic-gate ea_copy_object_tree(const ea_object_t *src)
1311*7c478bd9Sstevel@tonic-gate {
1312*7c478bd9Sstevel@tonic-gate 	ea_object_t *ret_obj, *dst, *last;
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	for (ret_obj = last = NULL; src != NULL;
1315*7c478bd9Sstevel@tonic-gate 	    last = dst, src = src->eo_next) {
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 		/* Allocate a new object and copy to it. */
1318*7c478bd9Sstevel@tonic-gate 		if ((dst = ea_copy_object(src)) == NULL) {
1319*7c478bd9Sstevel@tonic-gate 			ea_free_object(ret_obj, EUP_ALLOC);
1320*7c478bd9Sstevel@tonic-gate 			return (NULL);
1321*7c478bd9Sstevel@tonic-gate 		}
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate 		/* Groups need the object list copying. */
1324*7c478bd9Sstevel@tonic-gate 		if (src->eo_type == EO_GROUP) {
1325*7c478bd9Sstevel@tonic-gate 			dst->eo_group.eg_objs =
1326*7c478bd9Sstevel@tonic-gate 			    ea_copy_object_tree(src->eo_group.eg_objs);
1327*7c478bd9Sstevel@tonic-gate 			if (dst->eo_group.eg_objs == NULL) {
1328*7c478bd9Sstevel@tonic-gate 				ea_free_object(ret_obj, EUP_ALLOC);
1329*7c478bd9Sstevel@tonic-gate 				return (NULL);
1330*7c478bd9Sstevel@tonic-gate 			}
1331*7c478bd9Sstevel@tonic-gate 			dst->eo_group.eg_nobjs = src->eo_group.eg_nobjs;
1332*7c478bd9Sstevel@tonic-gate 		}
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 		/* Remember the list head the first time round. */
1335*7c478bd9Sstevel@tonic-gate 		if (ret_obj == NULL) {
1336*7c478bd9Sstevel@tonic-gate 			ret_obj = dst;
1337*7c478bd9Sstevel@tonic-gate 		}
1338*7c478bd9Sstevel@tonic-gate 
1339*7c478bd9Sstevel@tonic-gate 		/* Link together if not at the list head. */
1340*7c478bd9Sstevel@tonic-gate 		if (last != NULL) {
1341*7c478bd9Sstevel@tonic-gate 			last->eo_next = dst;
1342*7c478bd9Sstevel@tonic-gate 		}
1343*7c478bd9Sstevel@tonic-gate 	}
1344*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
1345*7c478bd9Sstevel@tonic-gate 	return (ret_obj);
1346*7c478bd9Sstevel@tonic-gate }
1347*7c478bd9Sstevel@tonic-gate 
1348*7c478bd9Sstevel@tonic-gate /*
1349*7c478bd9Sstevel@tonic-gate  * Read in the specified number of objects, returning the same data
1350*7c478bd9Sstevel@tonic-gate  * structure that would have originally been passed to ea_write().
1351*7c478bd9Sstevel@tonic-gate  */
1352*7c478bd9Sstevel@tonic-gate ea_object_t *
1353*7c478bd9Sstevel@tonic-gate ea_get_object_tree(ea_file_t *ef, uint32_t nobj)
1354*7c478bd9Sstevel@tonic-gate {
1355*7c478bd9Sstevel@tonic-gate 	ea_object_t *first_obj, *prev_obj, *obj;
1356*7c478bd9Sstevel@tonic-gate 
1357*7c478bd9Sstevel@tonic-gate 	first_obj = prev_obj = NULL;
1358*7c478bd9Sstevel@tonic-gate 	while (nobj--) {
1359*7c478bd9Sstevel@tonic-gate 		/* Allocate space for the new object. */
1360*7c478bd9Sstevel@tonic-gate 		obj = ea_alloc(sizeof (ea_object_t));
1361*7c478bd9Sstevel@tonic-gate 		bzero(obj, sizeof (*obj));
1362*7c478bd9Sstevel@tonic-gate 
1363*7c478bd9Sstevel@tonic-gate 		/* Read it in. */
1364*7c478bd9Sstevel@tonic-gate 		if (ea_get_object(ef, obj) == -1) {
1365*7c478bd9Sstevel@tonic-gate 			ea_free(obj, sizeof (ea_object_t));
1366*7c478bd9Sstevel@tonic-gate 			if (first_obj != NULL) {
1367*7c478bd9Sstevel@tonic-gate 				ea_free_object(first_obj, EUP_ALLOC);
1368*7c478bd9Sstevel@tonic-gate 			}
1369*7c478bd9Sstevel@tonic-gate 			return (NULL);
1370*7c478bd9Sstevel@tonic-gate 		}
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 		/* Link it into the list. */
1373*7c478bd9Sstevel@tonic-gate 		if (first_obj == NULL) {
1374*7c478bd9Sstevel@tonic-gate 			first_obj = obj;
1375*7c478bd9Sstevel@tonic-gate 		}
1376*7c478bd9Sstevel@tonic-gate 		if (prev_obj != NULL) {
1377*7c478bd9Sstevel@tonic-gate 			prev_obj->eo_next = obj;
1378*7c478bd9Sstevel@tonic-gate 		}
1379*7c478bd9Sstevel@tonic-gate 		prev_obj = obj;
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 		/* Recurse if the object is a group with contents. */
1382*7c478bd9Sstevel@tonic-gate 		if (obj->eo_type == EO_GROUP && obj->eo_group.eg_nobjs > 0) {
1383*7c478bd9Sstevel@tonic-gate 			if ((obj->eo_group.eg_objs = ea_get_object_tree(ef,
1384*7c478bd9Sstevel@tonic-gate 			    obj->eo_group.eg_nobjs)) == NULL) {
1385*7c478bd9Sstevel@tonic-gate 				/* exacct_error set above. */
1386*7c478bd9Sstevel@tonic-gate 				ea_free_object(first_obj, EUP_ALLOC);
1387*7c478bd9Sstevel@tonic-gate 				return (NULL);
1388*7c478bd9Sstevel@tonic-gate 			}
1389*7c478bd9Sstevel@tonic-gate 		}
1390*7c478bd9Sstevel@tonic-gate 	}
1391*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
1392*7c478bd9Sstevel@tonic-gate 	return (first_obj);
1393*7c478bd9Sstevel@tonic-gate }
1394