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