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 #include <sys/types.h>
28*7c478bd9Sstevel@tonic-gate #include <sys/exacct.h>
29*7c478bd9Sstevel@tonic-gate #include <sys/exacct_catalog.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/exacct_impl.h>
31*7c478bd9Sstevel@tonic-gate 
32*7c478bd9Sstevel@tonic-gate #ifndef	_KERNEL
33*7c478bd9Sstevel@tonic-gate #include <limits.h>
34*7c478bd9Sstevel@tonic-gate #include <errno.h>
35*7c478bd9Sstevel@tonic-gate #include <poll.h>
36*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
37*7c478bd9Sstevel@tonic-gate #include <strings.h>
38*7c478bd9Sstevel@tonic-gate #else
39*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
40*7c478bd9Sstevel@tonic-gate #endif
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * extended accounting file core routines
44*7c478bd9Sstevel@tonic-gate  *
45*7c478bd9Sstevel@tonic-gate  *   Routines shared by libexacct and the kernel for the definition,
46*7c478bd9Sstevel@tonic-gate  *   construction and packing of extended accounting (exacct) records.
47*7c478bd9Sstevel@tonic-gate  *
48*7c478bd9Sstevel@tonic-gate  * Locking
49*7c478bd9Sstevel@tonic-gate  *   All routines in this file use ea_alloc(), which is a malloc() wrapper
50*7c478bd9Sstevel@tonic-gate  *   in userland and a kmem_alloc(..., KM_SLEEP) wrapper in the kernel.
51*7c478bd9Sstevel@tonic-gate  *   Accordingly, all routines require a context suitable for KM_SLEEP
52*7c478bd9Sstevel@tonic-gate  *   allocations.
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate #define	DEFAULT_ENTRIES 4
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  * ea_alloc() and ea_free() provide a wrapper for the common
59*7c478bd9Sstevel@tonic-gate  * exacct code offering access to either the kmem allocator, or to libc's
60*7c478bd9Sstevel@tonic-gate  * malloc.
61*7c478bd9Sstevel@tonic-gate  */
62*7c478bd9Sstevel@tonic-gate void *
ea_alloc(size_t size)63*7c478bd9Sstevel@tonic-gate ea_alloc(size_t size)
64*7c478bd9Sstevel@tonic-gate {
65*7c478bd9Sstevel@tonic-gate #ifndef _KERNEL
66*7c478bd9Sstevel@tonic-gate 	void *p;
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	while ((p = malloc(size)) == NULL && errno == EAGAIN)
69*7c478bd9Sstevel@tonic-gate 		(void) poll(NULL, 0, 10 * MILLISEC);
70*7c478bd9Sstevel@tonic-gate 	if (p == NULL) {
71*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
72*7c478bd9Sstevel@tonic-gate 	} else {
73*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_OK);
74*7c478bd9Sstevel@tonic-gate 	}
75*7c478bd9Sstevel@tonic-gate 	return (p);
76*7c478bd9Sstevel@tonic-gate #else
77*7c478bd9Sstevel@tonic-gate 	return (kmem_alloc(size, KM_SLEEP));
78*7c478bd9Sstevel@tonic-gate #endif
79*7c478bd9Sstevel@tonic-gate }
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate #ifndef _KERNEL
82*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
83*7c478bd9Sstevel@tonic-gate #endif
84*7c478bd9Sstevel@tonic-gate void
ea_free(void * ptr,size_t size)85*7c478bd9Sstevel@tonic-gate ea_free(void *ptr, size_t size)
86*7c478bd9Sstevel@tonic-gate {
87*7c478bd9Sstevel@tonic-gate #ifndef _KERNEL
88*7c478bd9Sstevel@tonic-gate 	free(ptr);
89*7c478bd9Sstevel@tonic-gate #else
90*7c478bd9Sstevel@tonic-gate 	kmem_free(ptr, size);
91*7c478bd9Sstevel@tonic-gate #endif
92*7c478bd9Sstevel@tonic-gate }
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /*
95*7c478bd9Sstevel@tonic-gate  * ea_strdup() returns a pointer that, if non-NULL, must be freed using
96*7c478bd9Sstevel@tonic-gate  * ea_strfree() once its useful life ends.
97*7c478bd9Sstevel@tonic-gate  */
98*7c478bd9Sstevel@tonic-gate char *
ea_strdup(const char * ptr)99*7c478bd9Sstevel@tonic-gate ea_strdup(const char *ptr)
100*7c478bd9Sstevel@tonic-gate {
101*7c478bd9Sstevel@tonic-gate 	/* Sets exacct_errno. */
102*7c478bd9Sstevel@tonic-gate 	char *p = ea_alloc(strlen(ptr) + 1);
103*7c478bd9Sstevel@tonic-gate 	if (p != NULL) {
104*7c478bd9Sstevel@tonic-gate 		bcopy(ptr, p, strlen(ptr) + 1);
105*7c478bd9Sstevel@tonic-gate 	}
106*7c478bd9Sstevel@tonic-gate 	return (p);
107*7c478bd9Sstevel@tonic-gate }
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /*
110*7c478bd9Sstevel@tonic-gate  * ea_strfree() frees a string allocated with ea_strdup().
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate void
ea_strfree(char * ptr)113*7c478bd9Sstevel@tonic-gate ea_strfree(char *ptr)
114*7c478bd9Sstevel@tonic-gate {
115*7c478bd9Sstevel@tonic-gate #ifndef _KERNEL
116*7c478bd9Sstevel@tonic-gate 	free(ptr);
117*7c478bd9Sstevel@tonic-gate #else
118*7c478bd9Sstevel@tonic-gate 	kmem_free(ptr, strlen(ptr) + 1);
119*7c478bd9Sstevel@tonic-gate #endif
120*7c478bd9Sstevel@tonic-gate }
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * ea_cond_memcpy_at_offset() provides a simple conditional memcpy() that allows
124*7c478bd9Sstevel@tonic-gate  * us to write a pack routine that returns a valid buffer size, copying only in
125*7c478bd9Sstevel@tonic-gate  * the case that a non-NULL buffer is provided.
126*7c478bd9Sstevel@tonic-gate  */
127*7c478bd9Sstevel@tonic-gate static void
ea_cond_memcpy_at_offset(void * dst,size_t offset,size_t dstsize,void * src,size_t size)128*7c478bd9Sstevel@tonic-gate ea_cond_memcpy_at_offset(void *dst, size_t offset, size_t dstsize, void *src,
129*7c478bd9Sstevel@tonic-gate     size_t size)
130*7c478bd9Sstevel@tonic-gate {
131*7c478bd9Sstevel@tonic-gate 	char *cdst = dst;
132*7c478bd9Sstevel@tonic-gate 	char *csrc = src;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 	if (dst == NULL || src == NULL || size == 0 || offset + size > dstsize)
135*7c478bd9Sstevel@tonic-gate 		return;
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 	bcopy(csrc, cdst + offset, size);
138*7c478bd9Sstevel@tonic-gate }
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate /*
141*7c478bd9Sstevel@tonic-gate  * exacct_order{16,32,64}() are byte-swapping routines that place the native
142*7c478bd9Sstevel@tonic-gate  * data indicated by the input pointer in big-endian order.  Each exacct_order
143*7c478bd9Sstevel@tonic-gate  * function is its own inverse.
144*7c478bd9Sstevel@tonic-gate  */
145*7c478bd9Sstevel@tonic-gate #ifndef _LITTLE_ENDIAN
146*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
147*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
148*7c478bd9Sstevel@tonic-gate void
exacct_order16(uint16_t * in)149*7c478bd9Sstevel@tonic-gate exacct_order16(uint16_t *in)
150*7c478bd9Sstevel@tonic-gate {
151*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
152*7c478bd9Sstevel@tonic-gate 	uint8_t s;
153*7c478bd9Sstevel@tonic-gate 	union {
154*7c478bd9Sstevel@tonic-gate 		uint16_t agg;
155*7c478bd9Sstevel@tonic-gate 		uint8_t arr[2];
156*7c478bd9Sstevel@tonic-gate 	} t;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	t.agg = *in;
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	s = t.arr[0];
161*7c478bd9Sstevel@tonic-gate 	t.arr[0] = t.arr[1];
162*7c478bd9Sstevel@tonic-gate 	t.arr[1] = s;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	*in = t.agg;
165*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
166*7c478bd9Sstevel@tonic-gate }
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate #ifndef _LITTLE_ENDIAN
169*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
170*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
171*7c478bd9Sstevel@tonic-gate void
exacct_order32(uint32_t * in)172*7c478bd9Sstevel@tonic-gate exacct_order32(uint32_t *in)
173*7c478bd9Sstevel@tonic-gate {
174*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
175*7c478bd9Sstevel@tonic-gate 	uint16_t s;
176*7c478bd9Sstevel@tonic-gate 	union {
177*7c478bd9Sstevel@tonic-gate 		uint32_t agg;
178*7c478bd9Sstevel@tonic-gate 		uint16_t arr[2];
179*7c478bd9Sstevel@tonic-gate 	} t;
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 	t.agg = *in;
182*7c478bd9Sstevel@tonic-gate 	exacct_order16(&t.arr[0]);
183*7c478bd9Sstevel@tonic-gate 	exacct_order16(&t.arr[1]);
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate 	s = t.arr[0];
186*7c478bd9Sstevel@tonic-gate 	t.arr[0] = t.arr[1];
187*7c478bd9Sstevel@tonic-gate 	t.arr[1] = s;
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 	*in = t.agg;
190*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate #ifndef _LITTLE_ENDIAN
194*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
195*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
196*7c478bd9Sstevel@tonic-gate void
exacct_order64(uint64_t * in)197*7c478bd9Sstevel@tonic-gate exacct_order64(uint64_t *in)
198*7c478bd9Sstevel@tonic-gate {
199*7c478bd9Sstevel@tonic-gate #ifdef _LITTLE_ENDIAN
200*7c478bd9Sstevel@tonic-gate 	uint32_t s;
201*7c478bd9Sstevel@tonic-gate 	union {
202*7c478bd9Sstevel@tonic-gate 		uint64_t agg;
203*7c478bd9Sstevel@tonic-gate 		uint32_t arr[2];
204*7c478bd9Sstevel@tonic-gate 	} t;
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	t.agg = *in;
207*7c478bd9Sstevel@tonic-gate 	exacct_order32(&t.arr[0]);
208*7c478bd9Sstevel@tonic-gate 	exacct_order32(&t.arr[1]);
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	s = t.arr[0];
211*7c478bd9Sstevel@tonic-gate 	t.arr[0] = t.arr[1];
212*7c478bd9Sstevel@tonic-gate 	t.arr[1] = s;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	*in = t.agg;
215*7c478bd9Sstevel@tonic-gate #endif /* _LITTLE_ENDIAN */
216*7c478bd9Sstevel@tonic-gate }
217*7c478bd9Sstevel@tonic-gate 
218*7c478bd9Sstevel@tonic-gate int
ea_match_object_catalog(ea_object_t * obj,ea_catalog_t catmask)219*7c478bd9Sstevel@tonic-gate ea_match_object_catalog(ea_object_t *obj, ea_catalog_t catmask)
220*7c478bd9Sstevel@tonic-gate {
221*7c478bd9Sstevel@tonic-gate 	ea_catalog_t catval = obj->eo_catalog;
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate #define	EM_MATCH(v, m, M)	((m & M) == 0 || (v & M) == (m & M))
224*7c478bd9Sstevel@tonic-gate 	return (EM_MATCH(catval, catmask, EXT_TYPE_MASK) &&
225*7c478bd9Sstevel@tonic-gate 	    EM_MATCH(catval, catmask, EXC_CATALOG_MASK) &&
226*7c478bd9Sstevel@tonic-gate 	    EM_MATCH(catval, catmask, EXD_DATA_MASK));
227*7c478bd9Sstevel@tonic-gate #undef EM_MATCH
228*7c478bd9Sstevel@tonic-gate }
229*7c478bd9Sstevel@tonic-gate 
230*7c478bd9Sstevel@tonic-gate int
ea_set_item(ea_object_t * obj,ea_catalog_t tag,const void * value,size_t valsize)231*7c478bd9Sstevel@tonic-gate ea_set_item(ea_object_t *obj, ea_catalog_t tag,
232*7c478bd9Sstevel@tonic-gate     const void *value, size_t valsize)
233*7c478bd9Sstevel@tonic-gate {
234*7c478bd9Sstevel@tonic-gate 	ea_item_t *item = &obj->eo_item;
235*7c478bd9Sstevel@tonic-gate 
236*7c478bd9Sstevel@tonic-gate 	if ((tag & EXT_TYPE_MASK) == EXT_GROUP) {
237*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
238*7c478bd9Sstevel@tonic-gate 		return (-1);
239*7c478bd9Sstevel@tonic-gate 	}
240*7c478bd9Sstevel@tonic-gate 
241*7c478bd9Sstevel@tonic-gate 	bzero(obj, sizeof (ea_object_t));
242*7c478bd9Sstevel@tonic-gate 	obj->eo_type = EO_ITEM;
243*7c478bd9Sstevel@tonic-gate 	obj->eo_catalog = tag;
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	switch (obj->eo_catalog & EXT_TYPE_MASK) {
246*7c478bd9Sstevel@tonic-gate 	case EXT_UINT8:
247*7c478bd9Sstevel@tonic-gate 		item->ei_u.ei_u_uint8 = *(uint8_t *)value;
248*7c478bd9Sstevel@tonic-gate 		item->ei_size = sizeof (uint8_t);
249*7c478bd9Sstevel@tonic-gate 		break;
250*7c478bd9Sstevel@tonic-gate 	case EXT_UINT16:
251*7c478bd9Sstevel@tonic-gate 		item->ei_u.ei_u_uint16 = *(uint16_t *)value;
252*7c478bd9Sstevel@tonic-gate 		item->ei_size = sizeof (uint16_t);
253*7c478bd9Sstevel@tonic-gate 		break;
254*7c478bd9Sstevel@tonic-gate 	case EXT_UINT32:
255*7c478bd9Sstevel@tonic-gate 		item->ei_u.ei_u_uint32 = *(uint32_t *)value;
256*7c478bd9Sstevel@tonic-gate 		item->ei_size = sizeof (uint32_t);
257*7c478bd9Sstevel@tonic-gate 		break;
258*7c478bd9Sstevel@tonic-gate 	case EXT_UINT64:
259*7c478bd9Sstevel@tonic-gate 		item->ei_u.ei_u_uint64 = *(uint64_t *)value;
260*7c478bd9Sstevel@tonic-gate 		item->ei_size = sizeof (uint64_t);
261*7c478bd9Sstevel@tonic-gate 		break;
262*7c478bd9Sstevel@tonic-gate 	case EXT_DOUBLE:
263*7c478bd9Sstevel@tonic-gate 		item->ei_u.ei_u_double = *(double *)value;
264*7c478bd9Sstevel@tonic-gate 		item->ei_size = sizeof (double);
265*7c478bd9Sstevel@tonic-gate 		break;
266*7c478bd9Sstevel@tonic-gate 	case EXT_STRING:
267*7c478bd9Sstevel@tonic-gate 		if ((item->ei_string = ea_strdup((char *)value)) == NULL) {
268*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
269*7c478bd9Sstevel@tonic-gate 			return (-1);
270*7c478bd9Sstevel@tonic-gate 		}
271*7c478bd9Sstevel@tonic-gate 		item->ei_size = strlen(item->ei_string) + 1;
272*7c478bd9Sstevel@tonic-gate 		break;
273*7c478bd9Sstevel@tonic-gate 	case EXT_EXACCT_OBJECT:
274*7c478bd9Sstevel@tonic-gate 		if ((item->ei_object = ea_alloc(valsize)) == NULL) {
275*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
276*7c478bd9Sstevel@tonic-gate 			return (-1);
277*7c478bd9Sstevel@tonic-gate 		}
278*7c478bd9Sstevel@tonic-gate 		bcopy(value, item->ei_object, valsize);
279*7c478bd9Sstevel@tonic-gate 		item->ei_size = valsize;
280*7c478bd9Sstevel@tonic-gate 		break;
281*7c478bd9Sstevel@tonic-gate 	case EXT_RAW:
282*7c478bd9Sstevel@tonic-gate 		if ((item->ei_raw = ea_alloc(valsize)) == NULL) {
283*7c478bd9Sstevel@tonic-gate 			/* exacct_errno set above. */
284*7c478bd9Sstevel@tonic-gate 			return (-1);
285*7c478bd9Sstevel@tonic-gate 		}
286*7c478bd9Sstevel@tonic-gate 		bcopy(value, item->ei_raw, valsize);
287*7c478bd9Sstevel@tonic-gate 		item->ei_size = valsize;
288*7c478bd9Sstevel@tonic-gate 		break;
289*7c478bd9Sstevel@tonic-gate 	default:
290*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
291*7c478bd9Sstevel@tonic-gate 		return (-1);
292*7c478bd9Sstevel@tonic-gate 	}
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
295*7c478bd9Sstevel@tonic-gate 	return (0);
296*7c478bd9Sstevel@tonic-gate }
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate int
ea_set_group(ea_object_t * obj,ea_catalog_t tag)299*7c478bd9Sstevel@tonic-gate ea_set_group(ea_object_t *obj, ea_catalog_t tag)
300*7c478bd9Sstevel@tonic-gate {
301*7c478bd9Sstevel@tonic-gate 	if ((tag & EXT_TYPE_MASK) != EXT_GROUP) {
302*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
303*7c478bd9Sstevel@tonic-gate 		return (-1);
304*7c478bd9Sstevel@tonic-gate 	}
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	bzero(obj, sizeof (ea_object_t));
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	obj->eo_type = EO_GROUP;
309*7c478bd9Sstevel@tonic-gate 	obj->eo_catalog = tag;
310*7c478bd9Sstevel@tonic-gate 	obj->eo_u.eo_u_group.eg_nobjs = 0;
311*7c478bd9Sstevel@tonic-gate 	obj->eo_u.eo_u_group.eg_objs = NULL;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
314*7c478bd9Sstevel@tonic-gate 	return (0);
315*7c478bd9Sstevel@tonic-gate }
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate void
ea_free_object(ea_object_t * obj,int flag)318*7c478bd9Sstevel@tonic-gate ea_free_object(ea_object_t *obj, int flag)
319*7c478bd9Sstevel@tonic-gate {
320*7c478bd9Sstevel@tonic-gate 	ea_object_t *next = obj;
321*7c478bd9Sstevel@tonic-gate 	ea_object_t *save;
322*7c478bd9Sstevel@tonic-gate 
323*7c478bd9Sstevel@tonic-gate 	while (next != NULL) {
324*7c478bd9Sstevel@tonic-gate 		if (next->eo_type == EO_GROUP) {
325*7c478bd9Sstevel@tonic-gate 			ea_free_object(next->eo_group.eg_objs, flag);
326*7c478bd9Sstevel@tonic-gate 		} else if (next->eo_type == EO_ITEM) {
327*7c478bd9Sstevel@tonic-gate 			switch (next->eo_catalog & EXT_TYPE_MASK) {
328*7c478bd9Sstevel@tonic-gate 			case EXT_STRING:
329*7c478bd9Sstevel@tonic-gate 				if (flag == EUP_ALLOC)
330*7c478bd9Sstevel@tonic-gate 					ea_strfree(next->eo_item.ei_string);
331*7c478bd9Sstevel@tonic-gate 				break;
332*7c478bd9Sstevel@tonic-gate 			case EXT_RAW:
333*7c478bd9Sstevel@tonic-gate 			case EXT_EXACCT_OBJECT:
334*7c478bd9Sstevel@tonic-gate 				if (flag == EUP_ALLOC)
335*7c478bd9Sstevel@tonic-gate 					ea_free(next->eo_item.ei_raw,
336*7c478bd9Sstevel@tonic-gate 					    next->eo_item.ei_size);
337*7c478bd9Sstevel@tonic-gate 				break;
338*7c478bd9Sstevel@tonic-gate 			default:
339*7c478bd9Sstevel@tonic-gate 				/* No action required for other types. */
340*7c478bd9Sstevel@tonic-gate 				break;
341*7c478bd9Sstevel@tonic-gate 			}
342*7c478bd9Sstevel@tonic-gate 		}
343*7c478bd9Sstevel@tonic-gate 		/* No action required for EO_NONE. */
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 		save = next;
346*7c478bd9Sstevel@tonic-gate 		next = next->eo_next;
347*7c478bd9Sstevel@tonic-gate #ifdef _KERNEL
348*7c478bd9Sstevel@tonic-gate 		kmem_cache_free(exacct_object_cache, save);
349*7c478bd9Sstevel@tonic-gate #else
350*7c478bd9Sstevel@tonic-gate 		ea_free(save, sizeof (ea_object_t));
351*7c478bd9Sstevel@tonic-gate #endif /* _KERNEL */
352*7c478bd9Sstevel@tonic-gate 	}
353*7c478bd9Sstevel@tonic-gate }
354*7c478bd9Sstevel@tonic-gate 
355*7c478bd9Sstevel@tonic-gate int
ea_free_item(ea_object_t * obj,int flag)356*7c478bd9Sstevel@tonic-gate ea_free_item(ea_object_t *obj, int flag)
357*7c478bd9Sstevel@tonic-gate {
358*7c478bd9Sstevel@tonic-gate 	if (obj->eo_type != EO_ITEM) {
359*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
360*7c478bd9Sstevel@tonic-gate 		return (-1);
361*7c478bd9Sstevel@tonic-gate 	}
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 	switch (obj->eo_catalog & EXT_TYPE_MASK) {
364*7c478bd9Sstevel@tonic-gate 	case EXT_STRING:
365*7c478bd9Sstevel@tonic-gate 		if (flag == EUP_ALLOC)
366*7c478bd9Sstevel@tonic-gate 			ea_strfree(obj->eo_item.ei_string);
367*7c478bd9Sstevel@tonic-gate 		break;
368*7c478bd9Sstevel@tonic-gate 	case EXT_RAW:
369*7c478bd9Sstevel@tonic-gate 	case EXT_EXACCT_OBJECT:
370*7c478bd9Sstevel@tonic-gate 		if (flag == EUP_ALLOC)
371*7c478bd9Sstevel@tonic-gate 			ea_free(obj->eo_item.ei_raw, obj->eo_item.ei_size);
372*7c478bd9Sstevel@tonic-gate 		break;
373*7c478bd9Sstevel@tonic-gate 	default:
374*7c478bd9Sstevel@tonic-gate 		/* No action required for other types. */
375*7c478bd9Sstevel@tonic-gate 		break;
376*7c478bd9Sstevel@tonic-gate 	}
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	obj->eo_catalog = 0;
379*7c478bd9Sstevel@tonic-gate 	obj->eo_type = EO_NONE;
380*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
381*7c478bd9Sstevel@tonic-gate 	return (0);
382*7c478bd9Sstevel@tonic-gate }
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate static void
ea_attach_object(ea_object_t ** objp,ea_object_t * obj)385*7c478bd9Sstevel@tonic-gate ea_attach_object(ea_object_t **objp, ea_object_t *obj)
386*7c478bd9Sstevel@tonic-gate {
387*7c478bd9Sstevel@tonic-gate 	ea_object_t *tp;
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	tp = *objp;
390*7c478bd9Sstevel@tonic-gate 	*objp = obj;
391*7c478bd9Sstevel@tonic-gate 	obj->eo_next = tp;
392*7c478bd9Sstevel@tonic-gate }
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate int
ea_attach_to_object(ea_object_t * root,ea_object_t * obj)395*7c478bd9Sstevel@tonic-gate ea_attach_to_object(ea_object_t *root, ea_object_t *obj)
396*7c478bd9Sstevel@tonic-gate {
397*7c478bd9Sstevel@tonic-gate 	if (obj->eo_type == EO_GROUP || obj->eo_type == EO_ITEM) {
398*7c478bd9Sstevel@tonic-gate 		ea_attach_object(&root->eo_next, obj);
399*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_OK);
400*7c478bd9Sstevel@tonic-gate 		return (0);
401*7c478bd9Sstevel@tonic-gate 	} else {
402*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
403*7c478bd9Sstevel@tonic-gate 		return (-1);
404*7c478bd9Sstevel@tonic-gate 	}
405*7c478bd9Sstevel@tonic-gate }
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate /*
408*7c478bd9Sstevel@tonic-gate  * ea_attach_to_group() takes a group object and an additional exacct object and
409*7c478bd9Sstevel@tonic-gate  * attaches the latter to the object list of the former.  The attached exacct
410*7c478bd9Sstevel@tonic-gate  * object can be the head of a chain of objects.  If group isn't actually an
411*7c478bd9Sstevel@tonic-gate  * object of type EO_GROUP, do nothing, such that we don't destroy its contents.
412*7c478bd9Sstevel@tonic-gate  */
413*7c478bd9Sstevel@tonic-gate int
ea_attach_to_group(ea_object_t * group,ea_object_t * obj)414*7c478bd9Sstevel@tonic-gate ea_attach_to_group(ea_object_t *group, ea_object_t *obj)
415*7c478bd9Sstevel@tonic-gate {
416*7c478bd9Sstevel@tonic-gate 	uint_t n = 0;
417*7c478bd9Sstevel@tonic-gate 	ea_object_t *next;
418*7c478bd9Sstevel@tonic-gate 	ea_object_t **nextp;
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	if (group->eo_type != EO_GROUP) {
421*7c478bd9Sstevel@tonic-gate 		EXACCT_SET_ERR(EXR_INVALID_OBJ);
422*7c478bd9Sstevel@tonic-gate 		return (-1);
423*7c478bd9Sstevel@tonic-gate 	}
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	for (next = obj; next != NULL; next = next->eo_next)
426*7c478bd9Sstevel@tonic-gate 		n++;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	group->eo_group.eg_nobjs += n;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	for (nextp = &group->eo_group.eg_objs; *nextp != NULL;
431*7c478bd9Sstevel@tonic-gate 	    nextp = &(*nextp)->eo_next)
432*7c478bd9Sstevel@tonic-gate 		continue;
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	ea_attach_object(nextp, obj);
435*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
436*7c478bd9Sstevel@tonic-gate 	return (0);
437*7c478bd9Sstevel@tonic-gate }
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate /*
440*7c478bd9Sstevel@tonic-gate  * ea_pack_object takes the given exacct object series beginning with obj and
441*7c478bd9Sstevel@tonic-gate  * places it in buf.  Since ea_pack_object needs to be runnable in kernel
442*7c478bd9Sstevel@tonic-gate  * context, we construct it to use its own stack of state.  Specifically, we
443*7c478bd9Sstevel@tonic-gate  * store the locations of the sizes of open records (records whose construction
444*7c478bd9Sstevel@tonic-gate  * is in progress).  curr_frame is used to indicate the current frame.  Just
445*7c478bd9Sstevel@tonic-gate  * prior to decrementing curr_frame, we must ensure that the correct size for
446*7c478bd9Sstevel@tonic-gate  * that frame is placed in the given offset.
447*7c478bd9Sstevel@tonic-gate  */
448*7c478bd9Sstevel@tonic-gate struct es_frame {
449*7c478bd9Sstevel@tonic-gate 	ea_object_t	*esf_obj;
450*7c478bd9Sstevel@tonic-gate 	ea_size_t	esf_size;
451*7c478bd9Sstevel@tonic-gate 	ea_size_t	esf_bksize;
452*7c478bd9Sstevel@tonic-gate 	ea_size_t	esf_offset;
453*7c478bd9Sstevel@tonic-gate };
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate static void
incr_parent_frames(struct es_frame * base,int n,size_t amt)456*7c478bd9Sstevel@tonic-gate incr_parent_frames(struct es_frame *base, int n, size_t amt)
457*7c478bd9Sstevel@tonic-gate {
458*7c478bd9Sstevel@tonic-gate 	int i;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= n; i++) {
461*7c478bd9Sstevel@tonic-gate 		base[i].esf_size += amt;
462*7c478bd9Sstevel@tonic-gate 		base[i].esf_bksize += amt;
463*7c478bd9Sstevel@tonic-gate 	}
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate size_t
ea_pack_object(ea_object_t * obj,void * buf,size_t bufsize)467*7c478bd9Sstevel@tonic-gate ea_pack_object(ea_object_t *obj, void *buf, size_t bufsize)
468*7c478bd9Sstevel@tonic-gate {
469*7c478bd9Sstevel@tonic-gate 	struct es_frame *estack;
470*7c478bd9Sstevel@tonic-gate 	uint_t neframes;
471*7c478bd9Sstevel@tonic-gate 	ea_object_t *curr_obj = obj;
472*7c478bd9Sstevel@tonic-gate 	int curr_frame = 0;
473*7c478bd9Sstevel@tonic-gate 	size_t curr_pos = 0;
474*7c478bd9Sstevel@tonic-gate 	ea_size_t placeholder = 0;
475*7c478bd9Sstevel@tonic-gate 	int end_of_group = 0;
476*7c478bd9Sstevel@tonic-gate 	uint32_t gp_backskip = sizeof (ea_catalog_t) + sizeof (ea_size_t) +
477*7c478bd9Sstevel@tonic-gate 	    sizeof (uint32_t) + sizeof (uint32_t);
478*7c478bd9Sstevel@tonic-gate 	uint32_t lge_backskip;
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	exacct_order32(&gp_backskip);
481*7c478bd9Sstevel@tonic-gate 	estack = ea_alloc(sizeof (struct es_frame) * DEFAULT_ENTRIES);
482*7c478bd9Sstevel@tonic-gate 	if (estack == NULL) {
483*7c478bd9Sstevel@tonic-gate 		/* exacct_errno set above. */
484*7c478bd9Sstevel@tonic-gate 		return ((size_t)-1);
485*7c478bd9Sstevel@tonic-gate 	}
486*7c478bd9Sstevel@tonic-gate 	bzero(estack, sizeof (struct es_frame) * DEFAULT_ENTRIES);
487*7c478bd9Sstevel@tonic-gate 	neframes = DEFAULT_ENTRIES;
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate 	/*
490*7c478bd9Sstevel@tonic-gate 	 * 1.  Start with the current object.
491*7c478bd9Sstevel@tonic-gate 	 */
492*7c478bd9Sstevel@tonic-gate 	for (;;) {
493*7c478bd9Sstevel@tonic-gate 		void *src;
494*7c478bd9Sstevel@tonic-gate 		size_t size;
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 		/*
497*7c478bd9Sstevel@tonic-gate 		 * 1a.  If at the bottom of the stack, we are done.
498*7c478bd9Sstevel@tonic-gate 		 * If at the end of a group, place the correct size at the head
499*7c478bd9Sstevel@tonic-gate 		 * of the chain, the correct backskip amount in the next
500*7c478bd9Sstevel@tonic-gate 		 * position in the buffer, and retreat to the previous frame.
501*7c478bd9Sstevel@tonic-gate 		 */
502*7c478bd9Sstevel@tonic-gate 		if (end_of_group) {
503*7c478bd9Sstevel@tonic-gate 			if (--curr_frame < 0) {
504*7c478bd9Sstevel@tonic-gate 				break;
505*7c478bd9Sstevel@tonic-gate 			}
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 			exacct_order64(&estack[curr_frame].esf_size);
508*7c478bd9Sstevel@tonic-gate 			ea_cond_memcpy_at_offset(buf,
509*7c478bd9Sstevel@tonic-gate 			    estack[curr_frame].esf_offset, bufsize,
510*7c478bd9Sstevel@tonic-gate 			    &estack[curr_frame].esf_size, sizeof (ea_size_t));
511*7c478bd9Sstevel@tonic-gate 			exacct_order64(&estack[curr_frame].esf_size);
512*7c478bd9Sstevel@tonic-gate 
513*7c478bd9Sstevel@tonic-gate 			/*
514*7c478bd9Sstevel@tonic-gate 			 * Note that the large backskip is only 32 bits, whereas
515*7c478bd9Sstevel@tonic-gate 			 * an object can be up to 2^64 bytes long.  If an object
516*7c478bd9Sstevel@tonic-gate 			 * is greater than 2^32 bytes long set the large
517*7c478bd9Sstevel@tonic-gate 			 * backskip to 0.  This will  prevent the file being
518*7c478bd9Sstevel@tonic-gate 			 * read backwards by causing EOF to be returned when the
519*7c478bd9Sstevel@tonic-gate 			 * big object is encountered, but reading forwards will
520*7c478bd9Sstevel@tonic-gate 			 * still be OK as it ignores the large backskip field.
521*7c478bd9Sstevel@tonic-gate 			 */
522*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_bksize += sizeof (uint32_t);
523*7c478bd9Sstevel@tonic-gate 
524*7c478bd9Sstevel@tonic-gate 			lge_backskip =
525*7c478bd9Sstevel@tonic-gate 			    estack[curr_frame].esf_bksize > UINT_MAX
526*7c478bd9Sstevel@tonic-gate 			    ? 0 : (uint32_t)estack[curr_frame].esf_bksize;
527*7c478bd9Sstevel@tonic-gate 			exacct_order32(&lge_backskip);
528*7c478bd9Sstevel@tonic-gate 			ea_cond_memcpy_at_offset(buf, curr_pos, bufsize,
529*7c478bd9Sstevel@tonic-gate 			    &lge_backskip, sizeof (lge_backskip));
530*7c478bd9Sstevel@tonic-gate 
531*7c478bd9Sstevel@tonic-gate 			curr_pos += sizeof (uint32_t);
532*7c478bd9Sstevel@tonic-gate 			incr_parent_frames(estack, curr_frame,
533*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t));
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 			if ((curr_obj = estack[curr_frame].esf_obj) != NULL) {
536*7c478bd9Sstevel@tonic-gate 				end_of_group = 0;
537*7c478bd9Sstevel@tonic-gate 				estack[curr_frame].esf_obj = NULL;
538*7c478bd9Sstevel@tonic-gate 				estack[curr_frame].esf_size = 0;
539*7c478bd9Sstevel@tonic-gate 				estack[curr_frame].esf_bksize = 0;
540*7c478bd9Sstevel@tonic-gate 			} else {
541*7c478bd9Sstevel@tonic-gate 				continue;
542*7c478bd9Sstevel@tonic-gate 			}
543*7c478bd9Sstevel@tonic-gate 		}
544*7c478bd9Sstevel@tonic-gate 
545*7c478bd9Sstevel@tonic-gate 		/*
546*7c478bd9Sstevel@tonic-gate 		 * 2.  Write the catalog tag.
547*7c478bd9Sstevel@tonic-gate 		 */
548*7c478bd9Sstevel@tonic-gate 		exacct_order32(&curr_obj->eo_catalog);
549*7c478bd9Sstevel@tonic-gate 		ea_cond_memcpy_at_offset(buf, curr_pos, bufsize,
550*7c478bd9Sstevel@tonic-gate 		    &curr_obj->eo_catalog, sizeof (ea_catalog_t));
551*7c478bd9Sstevel@tonic-gate 		exacct_order32(&curr_obj->eo_catalog);
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 		incr_parent_frames(estack, curr_frame, sizeof (ea_catalog_t));
554*7c478bd9Sstevel@tonic-gate 		estack[curr_frame].esf_size -= sizeof (ea_catalog_t);
555*7c478bd9Sstevel@tonic-gate 		curr_pos += sizeof (ea_catalog_t);
556*7c478bd9Sstevel@tonic-gate 		estack[curr_frame].esf_offset = curr_pos;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 		/*
559*7c478bd9Sstevel@tonic-gate 		 * 2a. If this type is of variable size, reserve space for the
560*7c478bd9Sstevel@tonic-gate 		 * size field.
561*7c478bd9Sstevel@tonic-gate 		 */
562*7c478bd9Sstevel@tonic-gate 		switch (curr_obj->eo_catalog & EXT_TYPE_MASK) {
563*7c478bd9Sstevel@tonic-gate 		case EXT_GROUP:
564*7c478bd9Sstevel@tonic-gate 		case EXT_STRING:
565*7c478bd9Sstevel@tonic-gate 		case EXT_EXACCT_OBJECT:
566*7c478bd9Sstevel@tonic-gate 		case EXT_RAW:
567*7c478bd9Sstevel@tonic-gate 			exacct_order64(&placeholder);
568*7c478bd9Sstevel@tonic-gate 			ea_cond_memcpy_at_offset(buf, curr_pos, bufsize,
569*7c478bd9Sstevel@tonic-gate 			    &placeholder, sizeof (ea_size_t));
570*7c478bd9Sstevel@tonic-gate 			exacct_order64(&placeholder);
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 			incr_parent_frames(estack, curr_frame,
573*7c478bd9Sstevel@tonic-gate 			    sizeof (ea_size_t));
574*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_size -= sizeof (ea_size_t);
575*7c478bd9Sstevel@tonic-gate 			curr_pos += sizeof (ea_size_t);
576*7c478bd9Sstevel@tonic-gate 			break;
577*7c478bd9Sstevel@tonic-gate 		default:
578*7c478bd9Sstevel@tonic-gate 			break;
579*7c478bd9Sstevel@tonic-gate 		}
580*7c478bd9Sstevel@tonic-gate 
581*7c478bd9Sstevel@tonic-gate 		if (curr_obj->eo_type == EO_GROUP) {
582*7c478bd9Sstevel@tonic-gate 			/*
583*7c478bd9Sstevel@tonic-gate 			 * 3A.  If it's a group put its next pointer, size, and
584*7c478bd9Sstevel@tonic-gate 			 * size position on the stack, add 1 to the stack,
585*7c478bd9Sstevel@tonic-gate 			 * set the current object to eg_objs, and goto 1.
586*7c478bd9Sstevel@tonic-gate 			 */
587*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_obj = curr_obj->eo_next;
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 			/*
590*7c478bd9Sstevel@tonic-gate 			 * 3Aa. Insert the number of objects in the group.
591*7c478bd9Sstevel@tonic-gate 			 */
592*7c478bd9Sstevel@tonic-gate 			exacct_order32(&curr_obj->eo_group.eg_nobjs);
593*7c478bd9Sstevel@tonic-gate 			ea_cond_memcpy_at_offset(buf, curr_pos, bufsize,
594*7c478bd9Sstevel@tonic-gate 			    &curr_obj->eo_group.eg_nobjs,
595*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t));
596*7c478bd9Sstevel@tonic-gate 			exacct_order32(&curr_obj->eo_group.eg_nobjs);
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 			incr_parent_frames(estack, curr_frame,
599*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t));
600*7c478bd9Sstevel@tonic-gate 			curr_pos += sizeof (uint32_t);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 			/*
603*7c478bd9Sstevel@tonic-gate 			 * 3Ab. Insert a backskip of the appropriate size.
604*7c478bd9Sstevel@tonic-gate 			 */
605*7c478bd9Sstevel@tonic-gate 			ea_cond_memcpy_at_offset(buf, curr_pos, bufsize,
606*7c478bd9Sstevel@tonic-gate 			    &gp_backskip, sizeof (uint32_t));
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 			incr_parent_frames(estack, curr_frame,
609*7c478bd9Sstevel@tonic-gate 			    sizeof (uint32_t));
610*7c478bd9Sstevel@tonic-gate 			curr_pos += sizeof (uint32_t);
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 			curr_frame++;
613*7c478bd9Sstevel@tonic-gate 
614*7c478bd9Sstevel@tonic-gate 			if (curr_frame >= neframes) {
615*7c478bd9Sstevel@tonic-gate 				/*
616*7c478bd9Sstevel@tonic-gate 				 * Expand the eframe stack to handle the
617*7c478bd9Sstevel@tonic-gate 				 * requested depth.
618*7c478bd9Sstevel@tonic-gate 				 */
619*7c478bd9Sstevel@tonic-gate 				uint_t new_neframes = 2 * neframes;
620*7c478bd9Sstevel@tonic-gate 				struct es_frame *new_estack =
621*7c478bd9Sstevel@tonic-gate 				    ea_alloc(new_neframes *
622*7c478bd9Sstevel@tonic-gate 				    sizeof (struct es_frame));
623*7c478bd9Sstevel@tonic-gate 				if (new_estack == NULL) {
624*7c478bd9Sstevel@tonic-gate 					ea_free(estack, neframes *
625*7c478bd9Sstevel@tonic-gate 					    sizeof (struct es_frame));
626*7c478bd9Sstevel@tonic-gate 					/* exacct_errno set above. */
627*7c478bd9Sstevel@tonic-gate 					return ((size_t)-1);
628*7c478bd9Sstevel@tonic-gate 				}
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 				bzero(new_estack, new_neframes *
631*7c478bd9Sstevel@tonic-gate 				    sizeof (struct es_frame));
632*7c478bd9Sstevel@tonic-gate 				bcopy(estack, new_estack, neframes *
633*7c478bd9Sstevel@tonic-gate 				    sizeof (struct es_frame));
634*7c478bd9Sstevel@tonic-gate 
635*7c478bd9Sstevel@tonic-gate 				ea_free(estack, neframes *
636*7c478bd9Sstevel@tonic-gate 				    sizeof (struct es_frame));
637*7c478bd9Sstevel@tonic-gate 				estack = new_estack;
638*7c478bd9Sstevel@tonic-gate 				neframes = new_neframes;
639*7c478bd9Sstevel@tonic-gate 			} else {
640*7c478bd9Sstevel@tonic-gate 				bzero(&estack[curr_frame],
641*7c478bd9Sstevel@tonic-gate 				    sizeof (struct es_frame));
642*7c478bd9Sstevel@tonic-gate 			}
643*7c478bd9Sstevel@tonic-gate 
644*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_offset = curr_pos;
645*7c478bd9Sstevel@tonic-gate 			if ((curr_obj = curr_obj->eo_group.eg_objs) == NULL) {
646*7c478bd9Sstevel@tonic-gate 				end_of_group = 1;
647*7c478bd9Sstevel@tonic-gate 			}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 			continue;
650*7c478bd9Sstevel@tonic-gate 		}
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate 		/*
653*7c478bd9Sstevel@tonic-gate 		 * 3B. Otherwise we're considering an item: add its ei_size to
654*7c478bd9Sstevel@tonic-gate 		 * all sizes on the stack, and copy its size into position.
655*7c478bd9Sstevel@tonic-gate 		 */
656*7c478bd9Sstevel@tonic-gate 		switch (curr_obj->eo_catalog & EXT_TYPE_MASK) {
657*7c478bd9Sstevel@tonic-gate 		case EXT_UINT8:
658*7c478bd9Sstevel@tonic-gate 			src = &curr_obj->eo_item.ei_uint8;
659*7c478bd9Sstevel@tonic-gate 			size = sizeof (uint8_t);
660*7c478bd9Sstevel@tonic-gate 			break;
661*7c478bd9Sstevel@tonic-gate 		case EXT_UINT16:
662*7c478bd9Sstevel@tonic-gate 			src = &curr_obj->eo_item.ei_uint16;
663*7c478bd9Sstevel@tonic-gate 			size = sizeof (uint16_t);
664*7c478bd9Sstevel@tonic-gate 			exacct_order16(src);
665*7c478bd9Sstevel@tonic-gate 			break;
666*7c478bd9Sstevel@tonic-gate 		case EXT_UINT32:
667*7c478bd9Sstevel@tonic-gate 			src = &curr_obj->eo_item.ei_uint32;
668*7c478bd9Sstevel@tonic-gate 			size = sizeof (uint32_t);
669*7c478bd9Sstevel@tonic-gate 			exacct_order32(src);
670*7c478bd9Sstevel@tonic-gate 			break;
671*7c478bd9Sstevel@tonic-gate 		case EXT_UINT64:
672*7c478bd9Sstevel@tonic-gate 			src = &curr_obj->eo_item.ei_uint64;
673*7c478bd9Sstevel@tonic-gate 			size = sizeof (uint64_t);
674*7c478bd9Sstevel@tonic-gate 			exacct_order64(src);
675*7c478bd9Sstevel@tonic-gate 			break;
676*7c478bd9Sstevel@tonic-gate 		case EXT_DOUBLE:
677*7c478bd9Sstevel@tonic-gate 			src = &curr_obj->eo_item.ei_double;
678*7c478bd9Sstevel@tonic-gate 			size = sizeof (double);
679*7c478bd9Sstevel@tonic-gate 			exacct_order64((uint64_t *)src);
680*7c478bd9Sstevel@tonic-gate 			break;
681*7c478bd9Sstevel@tonic-gate 		case EXT_STRING:
682*7c478bd9Sstevel@tonic-gate 			src = curr_obj->eo_item.ei_string;
683*7c478bd9Sstevel@tonic-gate 			size = curr_obj->eo_item.ei_size;
684*7c478bd9Sstevel@tonic-gate 			break;
685*7c478bd9Sstevel@tonic-gate 		case EXT_EXACCT_OBJECT:
686*7c478bd9Sstevel@tonic-gate 			src = curr_obj->eo_item.ei_object;
687*7c478bd9Sstevel@tonic-gate 			size = curr_obj->eo_item.ei_size;
688*7c478bd9Sstevel@tonic-gate 			break;
689*7c478bd9Sstevel@tonic-gate 		case EXT_RAW:
690*7c478bd9Sstevel@tonic-gate 			src = curr_obj->eo_item.ei_raw;
691*7c478bd9Sstevel@tonic-gate 			size = curr_obj->eo_item.ei_size;
692*7c478bd9Sstevel@tonic-gate 			break;
693*7c478bd9Sstevel@tonic-gate 		case EXT_NONE:
694*7c478bd9Sstevel@tonic-gate 		default:
695*7c478bd9Sstevel@tonic-gate 			src = NULL;
696*7c478bd9Sstevel@tonic-gate 			size = 0;
697*7c478bd9Sstevel@tonic-gate 			break;
698*7c478bd9Sstevel@tonic-gate 		}
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 		ea_cond_memcpy_at_offset(buf, curr_pos, bufsize, src, size);
701*7c478bd9Sstevel@tonic-gate 		incr_parent_frames(estack, curr_frame, size);
702*7c478bd9Sstevel@tonic-gate 		curr_pos += size;
703*7c478bd9Sstevel@tonic-gate 
704*7c478bd9Sstevel@tonic-gate 		/*
705*7c478bd9Sstevel@tonic-gate 		 * 4. Write the large backskip amount into the buffer.
706*7c478bd9Sstevel@tonic-gate 		 * See above for note about why this may be set to 0.
707*7c478bd9Sstevel@tonic-gate 		 */
708*7c478bd9Sstevel@tonic-gate 		incr_parent_frames(estack, curr_frame, sizeof (uint32_t));
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 		lge_backskip = estack[curr_frame].esf_bksize > UINT_MAX
711*7c478bd9Sstevel@tonic-gate 		    ? 0 : (uint32_t)estack[curr_frame].esf_bksize;
712*7c478bd9Sstevel@tonic-gate 		exacct_order32(&lge_backskip);
713*7c478bd9Sstevel@tonic-gate 		ea_cond_memcpy_at_offset(buf, curr_pos, bufsize,
714*7c478bd9Sstevel@tonic-gate 		    &lge_backskip, sizeof (lge_backskip));
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 		curr_pos += sizeof (uint32_t);
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 		switch (curr_obj->eo_catalog & EXT_TYPE_MASK) {
719*7c478bd9Sstevel@tonic-gate 		case EXT_RAW:
720*7c478bd9Sstevel@tonic-gate 		case EXT_STRING:
721*7c478bd9Sstevel@tonic-gate 		case EXT_EXACCT_OBJECT:
722*7c478bd9Sstevel@tonic-gate 			exacct_order64(&estack[curr_frame].esf_size);
723*7c478bd9Sstevel@tonic-gate 			ea_cond_memcpy_at_offset(buf,
724*7c478bd9Sstevel@tonic-gate 			    estack[curr_frame].esf_offset, bufsize,
725*7c478bd9Sstevel@tonic-gate 			    &estack[curr_frame].esf_size, sizeof (ea_size_t));
726*7c478bd9Sstevel@tonic-gate 			exacct_order64(&estack[curr_frame].esf_size);
727*7c478bd9Sstevel@tonic-gate 			break;
728*7c478bd9Sstevel@tonic-gate 		case EXT_UINT16:
729*7c478bd9Sstevel@tonic-gate 			exacct_order16(src);
730*7c478bd9Sstevel@tonic-gate 			break;
731*7c478bd9Sstevel@tonic-gate 		case EXT_UINT32:
732*7c478bd9Sstevel@tonic-gate 			exacct_order32(src);
733*7c478bd9Sstevel@tonic-gate 			break;
734*7c478bd9Sstevel@tonic-gate 		case EXT_UINT64:
735*7c478bd9Sstevel@tonic-gate 			exacct_order64(src);
736*7c478bd9Sstevel@tonic-gate 			break;
737*7c478bd9Sstevel@tonic-gate 		case EXT_DOUBLE:
738*7c478bd9Sstevel@tonic-gate 			exacct_order64((uint64_t *)src);
739*7c478bd9Sstevel@tonic-gate 			break;
740*7c478bd9Sstevel@tonic-gate 		default:
741*7c478bd9Sstevel@tonic-gate 			break;
742*7c478bd9Sstevel@tonic-gate 		}
743*7c478bd9Sstevel@tonic-gate 
744*7c478bd9Sstevel@tonic-gate 		/*
745*7c478bd9Sstevel@tonic-gate 		 * 5.  If ei_next is NULL, we are at the end of a group.a  If
746*7c478bd9Sstevel@tonic-gate 		 * not, move on to the next item on the list.
747*7c478bd9Sstevel@tonic-gate 		 */
748*7c478bd9Sstevel@tonic-gate 		if (curr_obj->eo_next == NULL) {
749*7c478bd9Sstevel@tonic-gate 			end_of_group = 1;
750*7c478bd9Sstevel@tonic-gate 		} else {
751*7c478bd9Sstevel@tonic-gate 			curr_obj = curr_obj->eo_next;
752*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_obj = NULL;
753*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_size = 0;
754*7c478bd9Sstevel@tonic-gate 			estack[curr_frame].esf_bksize = 0;
755*7c478bd9Sstevel@tonic-gate 		}
756*7c478bd9Sstevel@tonic-gate 	}
757*7c478bd9Sstevel@tonic-gate 
758*7c478bd9Sstevel@tonic-gate 	ea_free(estack, neframes * sizeof (struct es_frame));
759*7c478bd9Sstevel@tonic-gate 	EXACCT_SET_ERR(EXR_OK);
760*7c478bd9Sstevel@tonic-gate 	return (curr_pos);
761*7c478bd9Sstevel@tonic-gate }
762