17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*cb620785Sraf * Common Development and Distribution License (the "License"). 6*cb620785Sraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*cb620785Sraf 227c478bd9Sstevel@tonic-gate /* 23*cb620785Sraf * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h> 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <exacct.h> 327c478bd9Sstevel@tonic-gate #include <exacct_impl.h> 337c478bd9Sstevel@tonic-gate #include <sys/exacct_impl.h> 347c478bd9Sstevel@tonic-gate #include <fcntl.h> 357c478bd9Sstevel@tonic-gate #include <unistd.h> 367c478bd9Sstevel@tonic-gate #include <strings.h> 377c478bd9Sstevel@tonic-gate #include <stdlib.h> 387c478bd9Sstevel@tonic-gate #include <stdio.h> 397c478bd9Sstevel@tonic-gate #include <errno.h> 407c478bd9Sstevel@tonic-gate #include <thread.h> 41*cb620785Sraf #include <pthread.h> 427c478bd9Sstevel@tonic-gate 437c478bd9Sstevel@tonic-gate #define EXACCT_HDR_STR "exacct" 447c478bd9Sstevel@tonic-gate #define EXACCT_HDR_LEN 7 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #define DEFAULT_ENTRIES 4 477c478bd9Sstevel@tonic-gate #define SYSINFO_BUFSIZE 256 487c478bd9Sstevel@tonic-gate 49*cb620785Sraf static thread_key_t errkey = THR_ONCE_KEY; 507c478bd9Sstevel@tonic-gate static int exacct_errval = 0; 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * extended accounting file access routines 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * exacct_ops.c implements the library-specific routines of libexacct: the 567c478bd9Sstevel@tonic-gate * operations associated with file access and record traversal. (The 577c478bd9Sstevel@tonic-gate * complementary routines which permit hierarchy building and record packing 587c478bd9Sstevel@tonic-gate * are provided in exacct_core.c, which is used by both libexacct and the 597c478bd9Sstevel@tonic-gate * kernel.) At its heart are the unpack, get, and next routines, which 607c478bd9Sstevel@tonic-gate * navigate the packed records produced by ea_pack_object. 617c478bd9Sstevel@tonic-gate */ 627c478bd9Sstevel@tonic-gate 637c478bd9Sstevel@tonic-gate /* 647c478bd9Sstevel@tonic-gate * Group stack manipulation code. As groups can be nested, we need a mechanism 657c478bd9Sstevel@tonic-gate * for saving and restoring the current position within the outer groups. This 667c478bd9Sstevel@tonic-gate * state stack is stored within the ea_file_impl_t structure, in the ef_depth, 677c478bd9Sstevel@tonic-gate * ef_ndeep and ef_mxdeep members. On error all these functions set 687c478bd9Sstevel@tonic-gate * exacct_error and return -1. 697c478bd9Sstevel@tonic-gate */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate /* 727c478bd9Sstevel@tonic-gate * If the stack is NULL, create and initialise it. 737c478bd9Sstevel@tonic-gate * If is is not NULL, check it still has space - if not, double its size. 747c478bd9Sstevel@tonic-gate */ 757c478bd9Sstevel@tonic-gate static int stack_check(ea_file_impl_t *f) 767c478bd9Sstevel@tonic-gate { 777c478bd9Sstevel@tonic-gate if (f->ef_depth == NULL) { 787c478bd9Sstevel@tonic-gate if ((f->ef_depth = 797c478bd9Sstevel@tonic-gate ea_alloc(DEFAULT_ENTRIES * sizeof (ea_file_depth_t))) 807c478bd9Sstevel@tonic-gate == NULL) { 817c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 827c478bd9Sstevel@tonic-gate return (-1); 837c478bd9Sstevel@tonic-gate } 847c478bd9Sstevel@tonic-gate bzero(f->ef_depth, DEFAULT_ENTRIES * sizeof (ea_file_depth_t)); 857c478bd9Sstevel@tonic-gate f->ef_mxdeep = DEFAULT_ENTRIES; 867c478bd9Sstevel@tonic-gate f->ef_ndeep = -1; 877c478bd9Sstevel@tonic-gate } else if (f->ef_ndeep + 1 >= f->ef_mxdeep) { 887c478bd9Sstevel@tonic-gate ea_file_depth_t *newstack; 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate if ((newstack = 917c478bd9Sstevel@tonic-gate ea_alloc(f->ef_mxdeep * 2 * sizeof (ea_file_depth_t))) 927c478bd9Sstevel@tonic-gate == NULL) { 937c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 947c478bd9Sstevel@tonic-gate return (-1); 957c478bd9Sstevel@tonic-gate } 967c478bd9Sstevel@tonic-gate bcopy(f->ef_depth, newstack, 977c478bd9Sstevel@tonic-gate f->ef_mxdeep * sizeof (ea_file_depth_t)); 987c478bd9Sstevel@tonic-gate bzero(newstack + f->ef_mxdeep, 997c478bd9Sstevel@tonic-gate f->ef_mxdeep * sizeof (ea_file_depth_t)); 1007c478bd9Sstevel@tonic-gate ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t)); 1017c478bd9Sstevel@tonic-gate f->ef_mxdeep *= 2; 1027c478bd9Sstevel@tonic-gate f->ef_depth = newstack; 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate return (0); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Free a stack. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate static void stack_free(ea_file_impl_t *f) 1117c478bd9Sstevel@tonic-gate { 1127c478bd9Sstevel@tonic-gate if (f->ef_depth != NULL) { 1137c478bd9Sstevel@tonic-gate ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t)); 1147c478bd9Sstevel@tonic-gate f->ef_depth = NULL; 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate f->ef_mxdeep = 0; 1177c478bd9Sstevel@tonic-gate f->ef_ndeep = -1; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * Add a new group onto the stack, pushing down one frame. nobj is the number 1227c478bd9Sstevel@tonic-gate * of items in the group. We have to read this many objects before popping 1237c478bd9Sstevel@tonic-gate * back up to an enclosing group - see next_object() and previous_object() 1247c478bd9Sstevel@tonic-gate * below. 1257c478bd9Sstevel@tonic-gate */ 1267c478bd9Sstevel@tonic-gate static int stack_new_group(ea_file_impl_t *f, int nobjs) 1277c478bd9Sstevel@tonic-gate { 1287c478bd9Sstevel@tonic-gate if (stack_check(f) != 0) { 1297c478bd9Sstevel@tonic-gate stack_free(f); 1307c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 1317c478bd9Sstevel@tonic-gate return (-1); 1327c478bd9Sstevel@tonic-gate } 1337c478bd9Sstevel@tonic-gate f->ef_ndeep++; 1347c478bd9Sstevel@tonic-gate f->ef_depth[f->ef_ndeep].efd_obj = 0; 1357c478bd9Sstevel@tonic-gate f->ef_depth[f->ef_ndeep].efd_nobjs = nobjs; 1367c478bd9Sstevel@tonic-gate return (0); 1377c478bd9Sstevel@tonic-gate } 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Step forwards along the objects within the current group. If we are still 1417c478bd9Sstevel@tonic-gate * within a group, return 1. If we have reached the end of the current group, 1427c478bd9Sstevel@tonic-gate * unwind the stack back up to the nearest enclosing group that still has 1437c478bd9Sstevel@tonic-gate * unprocessed objects and return 0. On EOF or error, set exacct_error 1447c478bd9Sstevel@tonic-gate * accordingly and return -1. xread() is required so that this function can 1457c478bd9Sstevel@tonic-gate * work either on files or memory buffers. 1467c478bd9Sstevel@tonic-gate */ 1477c478bd9Sstevel@tonic-gate static int 1487c478bd9Sstevel@tonic-gate stack_next_object( 1497c478bd9Sstevel@tonic-gate ea_file_impl_t *f, 1507c478bd9Sstevel@tonic-gate size_t (*xread)(ea_file_impl_t *, void *, size_t)) 1517c478bd9Sstevel@tonic-gate { 1527c478bd9Sstevel@tonic-gate uint32_t scratch32; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * If the stack is empty we are not in a group, so there will be no 1567c478bd9Sstevel@tonic-gate * stack manipulation to do and no large backskips to step over. 1577c478bd9Sstevel@tonic-gate */ 1587c478bd9Sstevel@tonic-gate if (f->ef_ndeep < 0) { 1597c478bd9Sstevel@tonic-gate return (0); 1607c478bd9Sstevel@tonic-gate } 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate /* 1637c478bd9Sstevel@tonic-gate * Otherwise we must be in a group. If there are objects left in the 1647c478bd9Sstevel@tonic-gate * group, move onto the next one in the group and return. 1657c478bd9Sstevel@tonic-gate */ 1667c478bd9Sstevel@tonic-gate if (++f->ef_depth[f->ef_ndeep].efd_obj < 1677c478bd9Sstevel@tonic-gate f->ef_depth[f->ef_ndeep].efd_nobjs) { 1687c478bd9Sstevel@tonic-gate return (1); 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * If we are at the end of a group we need to move backwards up the 1727c478bd9Sstevel@tonic-gate * stack, consuming the large backskips as we go, until we find a group 1737c478bd9Sstevel@tonic-gate * that still contains unprocessed items, or until we have unwound back 1747c478bd9Sstevel@tonic-gate * off the bottom of the stack (i.e. out of all the groups). 1757c478bd9Sstevel@tonic-gate */ 1767c478bd9Sstevel@tonic-gate } else { 1777c478bd9Sstevel@tonic-gate while (f->ef_ndeep >= 0 && 1787c478bd9Sstevel@tonic-gate ++f->ef_depth[f->ef_ndeep].efd_obj >= 1797c478bd9Sstevel@tonic-gate f->ef_depth[f->ef_ndeep].efd_nobjs) { 1807c478bd9Sstevel@tonic-gate /* Read the large backskip. */ 1817c478bd9Sstevel@tonic-gate f->ef_ndeep--; 1827c478bd9Sstevel@tonic-gate if (xread(f, &scratch32, sizeof (scratch32)) != 1837c478bd9Sstevel@tonic-gate sizeof (scratch32)) { 1847c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 1857c478bd9Sstevel@tonic-gate return (-1); 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate } 1887c478bd9Sstevel@tonic-gate return (0); 1897c478bd9Sstevel@tonic-gate } 1907c478bd9Sstevel@tonic-gate } 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * Step backwards along the objects within the current group. If we are still 1947c478bd9Sstevel@tonic-gate * within a group, return 1. If we have reached the end of the current group, 1957c478bd9Sstevel@tonic-gate * unwind the stack back up to the enclosing group and return 0. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate static int stack_previous_object(ea_file_impl_t *f) 1987c478bd9Sstevel@tonic-gate { 1997c478bd9Sstevel@tonic-gate /* 2007c478bd9Sstevel@tonic-gate * If the stack is empty we are not in a group, so there will be no 2017c478bd9Sstevel@tonic-gate * stack manipulation to do. 2027c478bd9Sstevel@tonic-gate */ 2037c478bd9Sstevel@tonic-gate if (f->ef_ndeep < 0) { 2047c478bd9Sstevel@tonic-gate return (0); 2057c478bd9Sstevel@tonic-gate } 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Otherwise we must be in a group. If there are objects left in the 2097c478bd9Sstevel@tonic-gate * group, move onto the previous one in the group and return. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate if (--f->ef_depth[f->ef_ndeep].efd_obj >= 0) { 2127c478bd9Sstevel@tonic-gate return (1); 2137c478bd9Sstevel@tonic-gate 2147c478bd9Sstevel@tonic-gate /* Otherwise, step one level back up the group stack. */ 2157c478bd9Sstevel@tonic-gate } else { 2167c478bd9Sstevel@tonic-gate f->ef_ndeep--; 2177c478bd9Sstevel@tonic-gate return (0); 2187c478bd9Sstevel@tonic-gate } 2197c478bd9Sstevel@tonic-gate } 2207c478bd9Sstevel@tonic-gate 2217c478bd9Sstevel@tonic-gate /* 2227c478bd9Sstevel@tonic-gate * read/seek/pos virtualisation wrappers. Because objects can come either from 2237c478bd9Sstevel@tonic-gate * a file or memory, the read/seek/pos functions need to be wrapped to allow 2247c478bd9Sstevel@tonic-gate * them to be used on either a file handle or a memory buffer. 2257c478bd9Sstevel@tonic-gate */ 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate static size_t 2287c478bd9Sstevel@tonic-gate fread_wrapper(ea_file_impl_t *f, void *buf, size_t sz) 2297c478bd9Sstevel@tonic-gate { 2307c478bd9Sstevel@tonic-gate size_t retval; 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate retval = fread(buf, 1, sz, f->ef_fp); 2337c478bd9Sstevel@tonic-gate if (retval == 0 && ferror(f->ef_fp)) { 2347c478bd9Sstevel@tonic-gate retval = (size_t)-1; 2357c478bd9Sstevel@tonic-gate } 2367c478bd9Sstevel@tonic-gate return (retval); 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate static size_t 2407c478bd9Sstevel@tonic-gate bufread_wrapper(ea_file_impl_t *f, void *buf, size_t sz) 2417c478bd9Sstevel@tonic-gate { 2427c478bd9Sstevel@tonic-gate if (f->ef_bufsize == 0 && sz != 0) 2437c478bd9Sstevel@tonic-gate return ((size_t)0); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (f->ef_bufsize < sz) 2467c478bd9Sstevel@tonic-gate sz = f->ef_bufsize; 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate bcopy(f->ef_buf, buf, sz); 2497c478bd9Sstevel@tonic-gate f->ef_buf += sz; 2507c478bd9Sstevel@tonic-gate f->ef_bufsize -= sz; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate return (sz); 2537c478bd9Sstevel@tonic-gate } 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate static off_t 2567c478bd9Sstevel@tonic-gate fseek_wrapper(ea_file_impl_t *f, off_t adv) 2577c478bd9Sstevel@tonic-gate { 2587c478bd9Sstevel@tonic-gate return (fseeko(f->ef_fp, adv, SEEK_CUR)); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate static off_t 2627c478bd9Sstevel@tonic-gate bufseek_wrapper(ea_file_impl_t *f, off_t adv) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate if (f->ef_bufsize == 0 && adv != 0) 2657c478bd9Sstevel@tonic-gate return (-1); 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (f->ef_bufsize < adv) 2687c478bd9Sstevel@tonic-gate adv = f->ef_bufsize; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate f->ef_buf += adv; 2717c478bd9Sstevel@tonic-gate f->ef_bufsize -= adv; 2727c478bd9Sstevel@tonic-gate 2737c478bd9Sstevel@tonic-gate return (0); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate 2767c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2777c478bd9Sstevel@tonic-gate static void * 2787c478bd9Sstevel@tonic-gate fpos_wrapper(ea_file_impl_t *f) 2797c478bd9Sstevel@tonic-gate { 2807c478bd9Sstevel@tonic-gate return (NULL); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate static void * 2847c478bd9Sstevel@tonic-gate bufpos_wrapper(ea_file_impl_t *f) 2857c478bd9Sstevel@tonic-gate { 2867c478bd9Sstevel@tonic-gate return (f->ef_buf); 2877c478bd9Sstevel@tonic-gate } 2887c478bd9Sstevel@tonic-gate 2897c478bd9Sstevel@tonic-gate /* 2907c478bd9Sstevel@tonic-gate * Public API 2917c478bd9Sstevel@tonic-gate */ 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate void 2947c478bd9Sstevel@tonic-gate exacct_seterr(int errval) 2957c478bd9Sstevel@tonic-gate { 2967c478bd9Sstevel@tonic-gate if (thr_main()) { 2977c478bd9Sstevel@tonic-gate exacct_errval = errval; 2987c478bd9Sstevel@tonic-gate return; 2997c478bd9Sstevel@tonic-gate } 300*cb620785Sraf (void) thr_keycreate_once(&errkey, 0); 3017c478bd9Sstevel@tonic-gate (void) thr_setspecific(errkey, (void *)(intptr_t)errval); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate int 3057c478bd9Sstevel@tonic-gate ea_error(void) 3067c478bd9Sstevel@tonic-gate { 3077c478bd9Sstevel@tonic-gate if (thr_main()) 3087c478bd9Sstevel@tonic-gate return (exacct_errval); 309*cb620785Sraf if (errkey == THR_ONCE_KEY) 3107c478bd9Sstevel@tonic-gate return (EXR_OK); 311*cb620785Sraf return ((int)(uintptr_t)pthread_getspecific(errkey)); 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate /* 3157c478bd9Sstevel@tonic-gate * ea_next_object(), ea_previous_object(), and ea_get_object() are written such 3167c478bd9Sstevel@tonic-gate * that the file cursor is always located on an object boundary. 3177c478bd9Sstevel@tonic-gate */ 3187c478bd9Sstevel@tonic-gate ea_object_type_t 3197c478bd9Sstevel@tonic-gate ea_next_object(ea_file_t *ef, ea_object_t *obj) 3207c478bd9Sstevel@tonic-gate { 3217c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 3227c478bd9Sstevel@tonic-gate ea_size_t len; 3237c478bd9Sstevel@tonic-gate off_t backup; 3247c478bd9Sstevel@tonic-gate size_t ret; 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * If ef_advance is zero, then we are executing after a get or previous 3287c478bd9Sstevel@tonic-gate * operation and do not move to the next or previous object. Otherwise, 3297c478bd9Sstevel@tonic-gate * advance to the next available item. Note that ef_advance does NOT 3307c478bd9Sstevel@tonic-gate * include the large backskip at the end of a object, this being dealt 3317c478bd9Sstevel@tonic-gate * with by the depth stack handling in stack_next_object. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate if (f->ef_advance != 0) { 3347c478bd9Sstevel@tonic-gate if (fseeko(f->ef_fp, (off_t)f->ef_advance, SEEK_CUR) == -1) { 3357c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 3367c478bd9Sstevel@tonic-gate return (EO_ERROR); 3377c478bd9Sstevel@tonic-gate } 3387c478bd9Sstevel@tonic-gate if (stack_next_object(f, fread_wrapper) == -1) { 3397c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 3407c478bd9Sstevel@tonic-gate return (EO_ERROR); 3417c478bd9Sstevel@tonic-gate } 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate f->ef_advance = 0; 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* Read the catalog tag */ 3467c478bd9Sstevel@tonic-gate ret = fread(&obj->eo_catalog, 1, sizeof (ea_catalog_t), f->ef_fp); 3477c478bd9Sstevel@tonic-gate if (ret == 0) { 3487c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_EOF); 3497c478bd9Sstevel@tonic-gate return (EO_ERROR); 3507c478bd9Sstevel@tonic-gate } else if (ret < sizeof (ea_catalog_t)) { 3517c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 3527c478bd9Sstevel@tonic-gate return (EO_ERROR); 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate exacct_order32(&obj->eo_catalog); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate backup = sizeof (ea_catalog_t); 3577c478bd9Sstevel@tonic-gate obj->eo_type = EO_ITEM; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* Figure out the offset to just before the large backskip. */ 3607c478bd9Sstevel@tonic-gate switch (obj->eo_catalog & EXT_TYPE_MASK) { 3617c478bd9Sstevel@tonic-gate case EXT_GROUP: 3627c478bd9Sstevel@tonic-gate obj->eo_type = EO_GROUP; 3637c478bd9Sstevel@tonic-gate f->ef_advance = sizeof (uint32_t); 3647c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 3657c478bd9Sstevel@tonic-gate case EXT_STRING: 3667c478bd9Sstevel@tonic-gate case EXT_EXACCT_OBJECT: 3677c478bd9Sstevel@tonic-gate case EXT_RAW: 3687c478bd9Sstevel@tonic-gate if (fread(&len, 1, sizeof (ea_size_t), f->ef_fp) 3697c478bd9Sstevel@tonic-gate < sizeof (ea_size_t)) { 3707c478bd9Sstevel@tonic-gate obj->eo_type = EO_NONE; 3717c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 3727c478bd9Sstevel@tonic-gate return (EO_ERROR); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate exacct_order64(&len); 3757c478bd9Sstevel@tonic-gate /* Note: len already includes the size of the backskip. */ 3767c478bd9Sstevel@tonic-gate f->ef_advance += sizeof (ea_catalog_t) + 3777c478bd9Sstevel@tonic-gate sizeof (ea_size_t) + len; 3787c478bd9Sstevel@tonic-gate backup += sizeof (ea_size_t); 3797c478bd9Sstevel@tonic-gate break; 3807c478bd9Sstevel@tonic-gate case EXT_UINT8: 3817c478bd9Sstevel@tonic-gate f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint8_t) + 3827c478bd9Sstevel@tonic-gate sizeof (uint32_t); 3837c478bd9Sstevel@tonic-gate break; 3847c478bd9Sstevel@tonic-gate case EXT_UINT16: 3857c478bd9Sstevel@tonic-gate f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint16_t) + 3867c478bd9Sstevel@tonic-gate sizeof (uint32_t); 3877c478bd9Sstevel@tonic-gate break; 3887c478bd9Sstevel@tonic-gate case EXT_UINT32: 3897c478bd9Sstevel@tonic-gate f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint32_t) + 3907c478bd9Sstevel@tonic-gate sizeof (uint32_t); 3917c478bd9Sstevel@tonic-gate break; 3927c478bd9Sstevel@tonic-gate case EXT_UINT64: 3937c478bd9Sstevel@tonic-gate f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint64_t) + 3947c478bd9Sstevel@tonic-gate sizeof (uint32_t); 3957c478bd9Sstevel@tonic-gate break; 3967c478bd9Sstevel@tonic-gate case EXT_DOUBLE: 3977c478bd9Sstevel@tonic-gate f->ef_advance = sizeof (ea_catalog_t) + sizeof (double) + 3987c478bd9Sstevel@tonic-gate sizeof (uint32_t); 3997c478bd9Sstevel@tonic-gate break; 4007c478bd9Sstevel@tonic-gate default: 4017c478bd9Sstevel@tonic-gate obj->eo_type = EO_NONE; 4027c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 4037c478bd9Sstevel@tonic-gate return (EO_ERROR); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate /* Reposition to the start of this object. */ 4077c478bd9Sstevel@tonic-gate if (fseeko(f->ef_fp, -backup, SEEK_CUR) == -1) { 4087c478bd9Sstevel@tonic-gate obj->eo_type = EO_NONE; 4097c478bd9Sstevel@tonic-gate f->ef_advance = 0; 4107c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 4117c478bd9Sstevel@tonic-gate return (EO_ERROR); 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 4157c478bd9Sstevel@tonic-gate return (obj->eo_type); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate ea_object_type_t 4197c478bd9Sstevel@tonic-gate ea_previous_object(ea_file_t *ef, ea_object_t *obj) 4207c478bd9Sstevel@tonic-gate { 4217c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 4227c478bd9Sstevel@tonic-gate uint32_t bkskip; 4237c478bd9Sstevel@tonic-gate int r; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate if (fseeko(f->ef_fp, -((off_t)sizeof (uint32_t)), SEEK_CUR) == -1) { 4267c478bd9Sstevel@tonic-gate if (errno == EINVAL) { 4277c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_EOF); 4287c478bd9Sstevel@tonic-gate } else { 4297c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate return (EO_ERROR); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate if ((r = fread(&bkskip, 1, sizeof (uint32_t), f->ef_fp)) != 4357c478bd9Sstevel@tonic-gate sizeof (uint32_t)) { 4367c478bd9Sstevel@tonic-gate if (r == 0) { 4377c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_EOF); 4387c478bd9Sstevel@tonic-gate } else { 4397c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate return (EO_ERROR); 4427c478bd9Sstevel@tonic-gate } 4437c478bd9Sstevel@tonic-gate exacct_order32(&bkskip); 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* 4467c478bd9Sstevel@tonic-gate * A backskip of 0 means that the current record can't be skipped over. 4477c478bd9Sstevel@tonic-gate * This will be true for the header record, and for records longer than 4487c478bd9Sstevel@tonic-gate * 2^32. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate if (bkskip == 0) { 4517c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_EOF); 4527c478bd9Sstevel@tonic-gate return (EO_ERROR); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate (void) stack_previous_object(f); 4557c478bd9Sstevel@tonic-gate 4567c478bd9Sstevel@tonic-gate if (fseeko(f->ef_fp, -((off_t)bkskip), SEEK_CUR) == -1) { 4577c478bd9Sstevel@tonic-gate if (errno == EINVAL) { 4587c478bd9Sstevel@tonic-gate /* 4597c478bd9Sstevel@tonic-gate * If we attempted to seek past BOF, then the file was 4607c478bd9Sstevel@tonic-gate * corrupt, as we can only trust the backskip we read. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 4637c478bd9Sstevel@tonic-gate } else { 4647c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate return (EO_ERROR); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate f->ef_advance = 0; 4707c478bd9Sstevel@tonic-gate return (ea_next_object(ef, obj)); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 4737c478bd9Sstevel@tonic-gate /* 4747c478bd9Sstevel@tonic-gate * xget_object() contains the logic for extracting an individual object from a 4757c478bd9Sstevel@tonic-gate * packed buffer, which it consumes using xread() and xseek() operations 4767c478bd9Sstevel@tonic-gate * provided by the caller. flags may be set to either EUP_ALLOC, in which case 4777c478bd9Sstevel@tonic-gate * new memory is allocated for the variable length items unpacked, or 4787c478bd9Sstevel@tonic-gate * EUP_NOALLOC, in which case item data pointer indicate locations within the 4797c478bd9Sstevel@tonic-gate * buffer, using the provided xpos() function. EUP_NOALLOC is generally not 4807c478bd9Sstevel@tonic-gate * useful for callers representing interaction with actual file streams, and 4817c478bd9Sstevel@tonic-gate * should not be specified thereby. 4827c478bd9Sstevel@tonic-gate */ 4837c478bd9Sstevel@tonic-gate static ea_object_type_t 4847c478bd9Sstevel@tonic-gate xget_object( 4857c478bd9Sstevel@tonic-gate ea_file_impl_t *f, 4867c478bd9Sstevel@tonic-gate ea_object_t *obj, 4877c478bd9Sstevel@tonic-gate size_t (*xread)(ea_file_impl_t *, void *, size_t), 4887c478bd9Sstevel@tonic-gate off_t (*xseek)(ea_file_impl_t *, off_t), 4897c478bd9Sstevel@tonic-gate void *(*xpos)(ea_file_impl_t *), 4907c478bd9Sstevel@tonic-gate int flags) 4917c478bd9Sstevel@tonic-gate { 4927c478bd9Sstevel@tonic-gate ea_size_t sz; 4937c478bd9Sstevel@tonic-gate uint32_t gp_backskip, scratch32; 4947c478bd9Sstevel@tonic-gate void *buf; 4957c478bd9Sstevel@tonic-gate size_t r; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* Read the catalog tag. */ 4987c478bd9Sstevel@tonic-gate if ((r = xread(f, &obj->eo_catalog, sizeof (ea_catalog_t))) == 0) { 4997c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_EOF); 5007c478bd9Sstevel@tonic-gate return (EO_ERROR); 5017c478bd9Sstevel@tonic-gate } else if (r != sizeof (ea_catalog_t)) { 5027c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5037c478bd9Sstevel@tonic-gate return (EO_ERROR); 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate exacct_order32(&obj->eo_catalog); 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate /* 5087c478bd9Sstevel@tonic-gate * If this is a record group, we treat it separately: only record 5097c478bd9Sstevel@tonic-gate * groups cause us to allocate new depth frames. 5107c478bd9Sstevel@tonic-gate */ 5117c478bd9Sstevel@tonic-gate if ((obj->eo_catalog & EXT_TYPE_MASK) == EXT_GROUP) { 5127c478bd9Sstevel@tonic-gate obj->eo_type = EO_GROUP; 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* Read size field, and number of objects. */ 5157c478bd9Sstevel@tonic-gate if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) { 5167c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5177c478bd9Sstevel@tonic-gate return (EO_ERROR); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate exacct_order64(&sz); 5207c478bd9Sstevel@tonic-gate if (xread(f, &obj->eo_group.eg_nobjs, sizeof (uint32_t)) != 5217c478bd9Sstevel@tonic-gate sizeof (uint32_t)) { 5227c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5237c478bd9Sstevel@tonic-gate return (EO_ERROR); 5247c478bd9Sstevel@tonic-gate } 5257c478bd9Sstevel@tonic-gate exacct_order32(&obj->eo_group.eg_nobjs); 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate /* Now read the group's small backskip. */ 5287c478bd9Sstevel@tonic-gate if (xread(f, &gp_backskip, sizeof (uint32_t)) != 5297c478bd9Sstevel@tonic-gate sizeof (uint32_t)) { 5307c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5317c478bd9Sstevel@tonic-gate return (EO_ERROR); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* Push a new depth stack frame. */ 5357c478bd9Sstevel@tonic-gate if (stack_new_group(f, obj->eo_group.eg_nobjs) != 0) { 5367c478bd9Sstevel@tonic-gate /* exacct_error set above */ 5377c478bd9Sstevel@tonic-gate return (EO_ERROR); 5387c478bd9Sstevel@tonic-gate } 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* 5417c478bd9Sstevel@tonic-gate * If the group has no items, we now need to position to the 5427c478bd9Sstevel@tonic-gate * end of the group, because there will be no subsequent calls 5437c478bd9Sstevel@tonic-gate * to process the group, it being empty. 5447c478bd9Sstevel@tonic-gate */ 5457c478bd9Sstevel@tonic-gate if (obj->eo_group.eg_nobjs == 0) { 5467c478bd9Sstevel@tonic-gate if (stack_next_object(f, xread) == -1) { 5477c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 5487c478bd9Sstevel@tonic-gate return (EO_ERROR); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate } 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate f->ef_advance = 0; 5537c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 5547c478bd9Sstevel@tonic-gate return (obj->eo_type); 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Otherwise we are reading an item. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate obj->eo_type = EO_ITEM; 5617c478bd9Sstevel@tonic-gate switch (obj->eo_catalog & EXT_TYPE_MASK) { 5627c478bd9Sstevel@tonic-gate case EXT_STRING: 5637c478bd9Sstevel@tonic-gate case EXT_EXACCT_OBJECT: 5647c478bd9Sstevel@tonic-gate case EXT_RAW: 5657c478bd9Sstevel@tonic-gate if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) { 5667c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5677c478bd9Sstevel@tonic-gate return (EO_ERROR); 5687c478bd9Sstevel@tonic-gate } 5697c478bd9Sstevel@tonic-gate exacct_order64(&sz); 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * Subtract backskip value from size. 5727c478bd9Sstevel@tonic-gate */ 5737c478bd9Sstevel@tonic-gate sz -= sizeof (uint32_t); 5747c478bd9Sstevel@tonic-gate if ((flags & EUP_ALLOC_MASK) == EUP_NOALLOC) { 5757c478bd9Sstevel@tonic-gate buf = xpos(f); 5767c478bd9Sstevel@tonic-gate if (xseek(f, sz) == -1) { 5777c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5787c478bd9Sstevel@tonic-gate return (EO_ERROR); 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate } else { 5817c478bd9Sstevel@tonic-gate if ((buf = ea_alloc(sz)) == NULL) 5827c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 5837c478bd9Sstevel@tonic-gate return (EO_ERROR); 5847c478bd9Sstevel@tonic-gate if (xread(f, buf, sz) != sz) { 5857aec1d6eScindi ea_free(buf, sz); 5867c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 5877c478bd9Sstevel@tonic-gate return (EO_ERROR); 5887c478bd9Sstevel@tonic-gate } 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate obj->eo_item.ei_string = buf; 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * Maintain our consistent convention that string lengths 5937c478bd9Sstevel@tonic-gate * include the terminating NULL character. 5947c478bd9Sstevel@tonic-gate */ 5957c478bd9Sstevel@tonic-gate obj->eo_item.ei_size = sz; 5967c478bd9Sstevel@tonic-gate break; 5977c478bd9Sstevel@tonic-gate case EXT_UINT8: 5987c478bd9Sstevel@tonic-gate if (xread(f, &obj->eo_item.ei_uint8, sizeof (uint8_t)) != 5997c478bd9Sstevel@tonic-gate sizeof (uint8_t)) { 6007c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6017c478bd9Sstevel@tonic-gate return (EO_ERROR); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate obj->eo_item.ei_size = sizeof (uint8_t); 6047c478bd9Sstevel@tonic-gate break; 6057c478bd9Sstevel@tonic-gate case EXT_UINT16: 6067c478bd9Sstevel@tonic-gate if (xread(f, &obj->eo_item.ei_uint16, sizeof (uint16_t)) != 6077c478bd9Sstevel@tonic-gate sizeof (uint16_t)) { 6087c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6097c478bd9Sstevel@tonic-gate return (EO_ERROR); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate exacct_order16(&obj->eo_item.ei_uint16); 6127c478bd9Sstevel@tonic-gate obj->eo_item.ei_size = sizeof (uint16_t); 6137c478bd9Sstevel@tonic-gate break; 6147c478bd9Sstevel@tonic-gate case EXT_UINT32: 6157c478bd9Sstevel@tonic-gate if (xread(f, &obj->eo_item.ei_uint32, sizeof (uint32_t)) != 6167c478bd9Sstevel@tonic-gate sizeof (uint32_t)) { 6177c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6187c478bd9Sstevel@tonic-gate return (EO_ERROR); 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate exacct_order32(&obj->eo_item.ei_uint32); 6217c478bd9Sstevel@tonic-gate obj->eo_item.ei_size = sizeof (uint32_t); 6227c478bd9Sstevel@tonic-gate break; 6237c478bd9Sstevel@tonic-gate case EXT_UINT64: 6247c478bd9Sstevel@tonic-gate if (xread(f, &obj->eo_item.ei_uint64, sizeof (uint64_t)) != 6257c478bd9Sstevel@tonic-gate sizeof (uint64_t)) { 6267c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6277c478bd9Sstevel@tonic-gate return (EO_ERROR); 6287c478bd9Sstevel@tonic-gate } 6297c478bd9Sstevel@tonic-gate exacct_order64(&obj->eo_item.ei_uint64); 6307c478bd9Sstevel@tonic-gate obj->eo_item.ei_size = sizeof (uint64_t); 6317c478bd9Sstevel@tonic-gate break; 6327c478bd9Sstevel@tonic-gate case EXT_DOUBLE: 6337c478bd9Sstevel@tonic-gate if (xread(f, &obj->eo_item.ei_double, sizeof (double)) != 6347c478bd9Sstevel@tonic-gate sizeof (double)) { 6357c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6367c478bd9Sstevel@tonic-gate return (EO_ERROR); 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate exacct_order64((uint64_t *)&obj->eo_item.ei_double); 6397c478bd9Sstevel@tonic-gate obj->eo_item.ei_size = sizeof (double); 6407c478bd9Sstevel@tonic-gate break; 6417c478bd9Sstevel@tonic-gate default: 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * We've encountered an unknown type value. Flag the error and 6447c478bd9Sstevel@tonic-gate * exit. 6457c478bd9Sstevel@tonic-gate */ 6467c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6477c478bd9Sstevel@tonic-gate return (EO_ERROR); 6487c478bd9Sstevel@tonic-gate } 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* 6517c478bd9Sstevel@tonic-gate * Advance over current large backskip value, 6527c478bd9Sstevel@tonic-gate * and position at the start of the next object. 6537c478bd9Sstevel@tonic-gate */ 6547c478bd9Sstevel@tonic-gate if (xread(f, &scratch32, sizeof (scratch32)) != sizeof (scratch32)) { 6557c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 6567c478bd9Sstevel@tonic-gate return (EO_ERROR); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate if (stack_next_object(f, xread) == -1) { 6597c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 6607c478bd9Sstevel@tonic-gate return (EO_ERROR); 6617c478bd9Sstevel@tonic-gate } 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate f->ef_advance = 0; 6647c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 6657c478bd9Sstevel@tonic-gate return (obj->eo_type); 6667c478bd9Sstevel@tonic-gate } 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate ea_object_type_t 6697c478bd9Sstevel@tonic-gate ea_get_object(ea_file_t *ef, ea_object_t *obj) 6707c478bd9Sstevel@tonic-gate { 6717c478bd9Sstevel@tonic-gate obj->eo_next = NULL; 6727c478bd9Sstevel@tonic-gate return (xget_object((ea_file_impl_t *)ef, obj, fread_wrapper, 6737c478bd9Sstevel@tonic-gate fseek_wrapper, fpos_wrapper, EUP_ALLOC)); 6747c478bd9Sstevel@tonic-gate } 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate /* 6777c478bd9Sstevel@tonic-gate * unpack_group() recursively unpacks record groups from the buffer tucked 6787c478bd9Sstevel@tonic-gate * within the passed ea_file, and attaches them to grp. 6797c478bd9Sstevel@tonic-gate */ 6807c478bd9Sstevel@tonic-gate static int 6817c478bd9Sstevel@tonic-gate unpack_group(ea_file_impl_t *f, ea_object_t *grp, int flag) 6827c478bd9Sstevel@tonic-gate { 6837c478bd9Sstevel@tonic-gate ea_object_t *obj; 6847c478bd9Sstevel@tonic-gate uint_t nobjs = grp->eo_group.eg_nobjs; 6857c478bd9Sstevel@tonic-gate int i; 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * Set the group's object count to zero, as we will rebuild it via the 6897c478bd9Sstevel@tonic-gate * individual object attachments. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate grp->eo_group.eg_nobjs = 0; 6927c478bd9Sstevel@tonic-gate grp->eo_group.eg_objs = NULL; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate for (i = 0; i < nobjs; i++) { 6957c478bd9Sstevel@tonic-gate if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) { 6967c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 6977c478bd9Sstevel@tonic-gate return (-1); 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate obj->eo_next = NULL; 7007c478bd9Sstevel@tonic-gate if (xget_object(f, obj, bufread_wrapper, bufseek_wrapper, 7017c478bd9Sstevel@tonic-gate bufpos_wrapper, flag) == -1) { 7027c478bd9Sstevel@tonic-gate ea_free(obj, sizeof (ea_object_t)); 7037c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7047c478bd9Sstevel@tonic-gate return (-1); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 7077c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(grp, obj); 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (obj->eo_type == EO_GROUP && 7107c478bd9Sstevel@tonic-gate unpack_group(f, obj, flag) == -1) { 7117c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7127c478bd9Sstevel@tonic-gate return (-1); 7137c478bd9Sstevel@tonic-gate } 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate if (nobjs != grp->eo_group.eg_nobjs) { 7177c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_CORRUPT_FILE); 7187c478bd9Sstevel@tonic-gate return (-1); 7197c478bd9Sstevel@tonic-gate } 7207c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 7217c478bd9Sstevel@tonic-gate return (0); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate /* 7257c478bd9Sstevel@tonic-gate * ea_unpack_object() can be considered as a finite series of get operations on 7267c478bd9Sstevel@tonic-gate * a given buffer, that rebuilds the hierarchy of objects compacted by a pack 7277c478bd9Sstevel@tonic-gate * operation. Because there is complex state associated with the group depth, 7287c478bd9Sstevel@tonic-gate * ea_unpack_object() must complete as one operation on a given buffer. 7297c478bd9Sstevel@tonic-gate */ 7307c478bd9Sstevel@tonic-gate ea_object_type_t 7317c478bd9Sstevel@tonic-gate ea_unpack_object(ea_object_t **objp, int flag, void *buf, size_t bufsize) 7327c478bd9Sstevel@tonic-gate { 7337c478bd9Sstevel@tonic-gate ea_file_impl_t fake; 7347c478bd9Sstevel@tonic-gate ea_object_t *obj; 7357c478bd9Sstevel@tonic-gate ea_object_type_t first_obj_type; 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate *objp = NULL; 7387c478bd9Sstevel@tonic-gate if (buf == NULL) { 7397c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_INVALID_BUF); 7407c478bd9Sstevel@tonic-gate return (EO_ERROR); 7417c478bd9Sstevel@tonic-gate } 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate /* Set up the structures needed for unpacking */ 7447c478bd9Sstevel@tonic-gate bzero(&fake, sizeof (ea_file_impl_t)); 7457c478bd9Sstevel@tonic-gate if (stack_check(&fake) == -1) { 7467c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7477c478bd9Sstevel@tonic-gate return (EO_ERROR); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate fake.ef_buf = buf; 7507c478bd9Sstevel@tonic-gate fake.ef_bufsize = bufsize; 7517c478bd9Sstevel@tonic-gate 7527c478bd9Sstevel@tonic-gate /* Unpack the first object in the buffer - this should succeed. */ 7537c478bd9Sstevel@tonic-gate if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) { 7547c478bd9Sstevel@tonic-gate stack_free(&fake); 7557c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7567c478bd9Sstevel@tonic-gate return (EO_ERROR); 7577c478bd9Sstevel@tonic-gate } 7587c478bd9Sstevel@tonic-gate obj->eo_next = NULL; 7597c478bd9Sstevel@tonic-gate if ((first_obj_type = xget_object(&fake, obj, bufread_wrapper, 7607c478bd9Sstevel@tonic-gate bufseek_wrapper, bufpos_wrapper, flag)) == -1) { 7617c478bd9Sstevel@tonic-gate stack_free(&fake); 7627c478bd9Sstevel@tonic-gate ea_free(obj, sizeof (ea_object_t)); 7637c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7647c478bd9Sstevel@tonic-gate return (EO_ERROR); 7657c478bd9Sstevel@tonic-gate } 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate if (obj->eo_type == EO_GROUP && unpack_group(&fake, obj, flag) == -1) { 7687c478bd9Sstevel@tonic-gate stack_free(&fake); 7697c478bd9Sstevel@tonic-gate ea_free_object(obj, flag); 7707c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7717c478bd9Sstevel@tonic-gate return (EO_ERROR); 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate *objp = obj; 7747c478bd9Sstevel@tonic-gate 7757c478bd9Sstevel@tonic-gate /* 7767c478bd9Sstevel@tonic-gate * There may be other objects in the buffer - if so, chain them onto 7777c478bd9Sstevel@tonic-gate * the end of the list. We have reached the end of the list when 7787c478bd9Sstevel@tonic-gate * xget_object() returns -1 with exacct_error set to EXR_EOF. 7797c478bd9Sstevel@tonic-gate */ 7807c478bd9Sstevel@tonic-gate for (;;) { 7817c478bd9Sstevel@tonic-gate if ((obj = ea_alloc(sizeof (ea_object_t))) == NULL) { 7827c478bd9Sstevel@tonic-gate stack_free(&fake); 7837c478bd9Sstevel@tonic-gate ea_free_object(*objp, flag); 7847c478bd9Sstevel@tonic-gate *objp = NULL; 7857c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 7867c478bd9Sstevel@tonic-gate return (EO_ERROR); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate obj->eo_next = NULL; 7897c478bd9Sstevel@tonic-gate if (xget_object(&fake, obj, bufread_wrapper, bufseek_wrapper, 7907c478bd9Sstevel@tonic-gate bufpos_wrapper, flag) == -1) { 7917c478bd9Sstevel@tonic-gate stack_free(&fake); 7927c478bd9Sstevel@tonic-gate ea_free(obj, sizeof (ea_object_t)); 7937c478bd9Sstevel@tonic-gate if (ea_error() == EXR_EOF) { 7947c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 7957c478bd9Sstevel@tonic-gate return (first_obj_type); 7967c478bd9Sstevel@tonic-gate } else { 7977c478bd9Sstevel@tonic-gate ea_free_object(*objp, flag); 7987c478bd9Sstevel@tonic-gate *objp = NULL; 7997c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 8007c478bd9Sstevel@tonic-gate return (EO_ERROR); 8017c478bd9Sstevel@tonic-gate } 8027c478bd9Sstevel@tonic-gate } 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate (void) ea_attach_to_object(*objp, obj); 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate if (obj->eo_type == EO_GROUP && 8077c478bd9Sstevel@tonic-gate unpack_group(&fake, obj, flag) == -1) { 8087c478bd9Sstevel@tonic-gate stack_free(&fake); 8097c478bd9Sstevel@tonic-gate ea_free(obj, sizeof (ea_object_t)); 8107c478bd9Sstevel@tonic-gate ea_free_object(*objp, flag); 8117c478bd9Sstevel@tonic-gate *objp = NULL; 8127c478bd9Sstevel@tonic-gate /* exacct_errno set above. */ 8137c478bd9Sstevel@tonic-gate return (EO_ERROR); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate int 8197c478bd9Sstevel@tonic-gate ea_write_object(ea_file_t *ef, ea_object_t *obj) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate ea_size_t sz; 8227c478bd9Sstevel@tonic-gate void *buf; 8237c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 8267c478bd9Sstevel@tonic-gate * If we weren't opened for writing, this call fails. 8277c478bd9Sstevel@tonic-gate */ 8287c478bd9Sstevel@tonic-gate if ((f->ef_oflags & O_RDWR) == 0 && 8297c478bd9Sstevel@tonic-gate (f->ef_oflags & O_WRONLY) == 0) { 8307c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_NOTSUPP); 8317c478bd9Sstevel@tonic-gate return (-1); 8327c478bd9Sstevel@tonic-gate } 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate /* Pack with a null buffer to get the size. */ 8357c478bd9Sstevel@tonic-gate sz = ea_pack_object(obj, NULL, 0); 8367c478bd9Sstevel@tonic-gate if (sz == -1 || (buf = ea_alloc(sz)) == NULL) { 8377c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 8387c478bd9Sstevel@tonic-gate return (-1); 8397c478bd9Sstevel@tonic-gate } 8407c478bd9Sstevel@tonic-gate if (ea_pack_object(obj, buf, sz) == (size_t)-1) { 8417c478bd9Sstevel@tonic-gate ea_free(buf, sz); 8427c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 8437c478bd9Sstevel@tonic-gate return (-1); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate if (fwrite(buf, sizeof (char), sz, f->ef_fp) != sz) { 8467c478bd9Sstevel@tonic-gate ea_free(buf, sz); 8477c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 8487c478bd9Sstevel@tonic-gate return (-1); 8497c478bd9Sstevel@tonic-gate } 8507c478bd9Sstevel@tonic-gate ea_free(buf, sz); 8517c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 8527c478bd9Sstevel@tonic-gate return (0); 8537c478bd9Sstevel@tonic-gate } 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate /* 8567c478bd9Sstevel@tonic-gate * validate_header() must be kept in sync with write_header(), given below, and 8577c478bd9Sstevel@tonic-gate * exacct_create_header(), in uts/common/os/exacct.c. 8587c478bd9Sstevel@tonic-gate */ 8597c478bd9Sstevel@tonic-gate static int 8607c478bd9Sstevel@tonic-gate validate_header(ea_file_t *ef, const char *creator) 8617c478bd9Sstevel@tonic-gate { 8627c478bd9Sstevel@tonic-gate ea_object_t hdr_grp; 8637c478bd9Sstevel@tonic-gate ea_object_t scratch_obj; 8647c478bd9Sstevel@tonic-gate int error = EXR_OK; 8657c478bd9Sstevel@tonic-gate int saw_creator = 0; 8667c478bd9Sstevel@tonic-gate int saw_version = 0; 8677c478bd9Sstevel@tonic-gate int saw_type = 0; 8687c478bd9Sstevel@tonic-gate int saw_hostname = 0; 8697c478bd9Sstevel@tonic-gate int n; 8707c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate bzero(&hdr_grp, sizeof (ea_object_t)); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate if (ea_get_object(ef, &hdr_grp) != EO_GROUP) { 8757c478bd9Sstevel@tonic-gate error = ea_error(); 8767c478bd9Sstevel@tonic-gate goto error_case; 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate if (hdr_grp.eo_catalog != 8807c478bd9Sstevel@tonic-gate (EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER)) { 8817c478bd9Sstevel@tonic-gate error = EXR_CORRUPT_FILE; 8827c478bd9Sstevel@tonic-gate goto error_case; 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate for (n = 0; n < hdr_grp.eo_group.eg_nobjs; n++) { 8867c478bd9Sstevel@tonic-gate bzero(&scratch_obj, sizeof (ea_object_t)); 8877c478bd9Sstevel@tonic-gate if (ea_get_object(ef, &scratch_obj) == -1) { 8887c478bd9Sstevel@tonic-gate error = ea_error(); 8897c478bd9Sstevel@tonic-gate goto error_case; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate switch (scratch_obj.eo_catalog) { 8937c478bd9Sstevel@tonic-gate case EXT_UINT32 | EXC_DEFAULT | EXD_VERSION: 8947c478bd9Sstevel@tonic-gate if (scratch_obj.eo_item.ei_uint32 != EXACCT_VERSION) { 8957c478bd9Sstevel@tonic-gate error = EXR_UNKN_VERSION; 8967c478bd9Sstevel@tonic-gate goto error_case; 8977c478bd9Sstevel@tonic-gate } 8987c478bd9Sstevel@tonic-gate saw_version++; 8997c478bd9Sstevel@tonic-gate break; 9007c478bd9Sstevel@tonic-gate case EXT_STRING | EXC_DEFAULT | EXD_FILETYPE: 9017c478bd9Sstevel@tonic-gate if (strcmp(scratch_obj.eo_item.ei_string, 9027c478bd9Sstevel@tonic-gate EXACCT_HDR_STR) != 0) { 9037c478bd9Sstevel@tonic-gate error = EXR_CORRUPT_FILE; 9047c478bd9Sstevel@tonic-gate goto error_case; 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate saw_type++; 9077c478bd9Sstevel@tonic-gate break; 9087c478bd9Sstevel@tonic-gate case EXT_STRING | EXC_DEFAULT | EXD_CREATOR: 9097c478bd9Sstevel@tonic-gate f->ef_creator = 9107c478bd9Sstevel@tonic-gate ea_strdup(scratch_obj.eo_item.ei_string); 9117c478bd9Sstevel@tonic-gate if (f->ef_creator == NULL) { 9127c478bd9Sstevel@tonic-gate error = ea_error(); 9137c478bd9Sstevel@tonic-gate goto error_case; 9147c478bd9Sstevel@tonic-gate } 9157c478bd9Sstevel@tonic-gate saw_creator++; 9167c478bd9Sstevel@tonic-gate break; 9177c478bd9Sstevel@tonic-gate /* The hostname is an optional field. */ 9187c478bd9Sstevel@tonic-gate case EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME: 9197c478bd9Sstevel@tonic-gate f->ef_hostname = 9207c478bd9Sstevel@tonic-gate ea_strdup(scratch_obj.eo_item.ei_string); 9217c478bd9Sstevel@tonic-gate if (f->ef_hostname == NULL) { 9227c478bd9Sstevel@tonic-gate error = ea_error(); 9237c478bd9Sstevel@tonic-gate goto error_case; 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate saw_hostname++; 9267c478bd9Sstevel@tonic-gate break; 9277c478bd9Sstevel@tonic-gate default: 9287c478bd9Sstevel@tonic-gate /* ignore unrecognized header members */ 9297c478bd9Sstevel@tonic-gate break; 9307c478bd9Sstevel@tonic-gate } 9317c478bd9Sstevel@tonic-gate (void) ea_free_item(&scratch_obj, EUP_ALLOC); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if (saw_version && saw_type && saw_creator) { 9357c478bd9Sstevel@tonic-gate if (creator && strcmp(f->ef_creator, creator) != 0) { 9367c478bd9Sstevel@tonic-gate error = EXR_NO_CREATOR; 9377c478bd9Sstevel@tonic-gate goto error_case; 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 9407c478bd9Sstevel@tonic-gate return (0); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate error_case: 9447c478bd9Sstevel@tonic-gate (void) ea_free_item(&scratch_obj, EUP_ALLOC); 9457c478bd9Sstevel@tonic-gate if (saw_hostname) 9467c478bd9Sstevel@tonic-gate ea_strfree(f->ef_hostname); 9477c478bd9Sstevel@tonic-gate if (saw_creator) 9487c478bd9Sstevel@tonic-gate ea_strfree(f->ef_creator); 9497c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(error); 9507c478bd9Sstevel@tonic-gate return (-1); 9517c478bd9Sstevel@tonic-gate } 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate static int 9547c478bd9Sstevel@tonic-gate write_header(ea_file_t *ef) 9557c478bd9Sstevel@tonic-gate { 9567c478bd9Sstevel@tonic-gate ea_object_t hdr_grp; 9577c478bd9Sstevel@tonic-gate ea_object_t vers_obj; 9587c478bd9Sstevel@tonic-gate ea_object_t creator_obj; 9597c478bd9Sstevel@tonic-gate ea_object_t filetype_obj; 9607c478bd9Sstevel@tonic-gate ea_object_t hostname_obj; 9617c478bd9Sstevel@tonic-gate uint32_t bskip; 9627c478bd9Sstevel@tonic-gate const uint32_t version = EXACCT_VERSION; 9637c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 9647c478bd9Sstevel@tonic-gate void *buf; 9657c478bd9Sstevel@tonic-gate size_t bufsize; 9667c478bd9Sstevel@tonic-gate char hostbuf[SYSINFO_BUFSIZE]; 9677c478bd9Sstevel@tonic-gate int error = EXR_OK; 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate bzero(&hdr_grp, sizeof (ea_object_t)); 9707c478bd9Sstevel@tonic-gate bzero(&vers_obj, sizeof (ea_object_t)); 9717c478bd9Sstevel@tonic-gate bzero(&creator_obj, sizeof (ea_object_t)); 9727c478bd9Sstevel@tonic-gate bzero(&filetype_obj, sizeof (ea_object_t)); 9737c478bd9Sstevel@tonic-gate bzero(&hostname_obj, sizeof (ea_object_t)); 9747c478bd9Sstevel@tonic-gate bzero(hostbuf, SYSINFO_BUFSIZE); 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate (void) sysinfo(SI_HOSTNAME, hostbuf, SYSINFO_BUFSIZE); 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate if (ea_set_item(&vers_obj, EXT_UINT32 | EXC_DEFAULT | EXD_VERSION, 9797c478bd9Sstevel@tonic-gate (void *)&version, 0) == -1 || 9807c478bd9Sstevel@tonic-gate ea_set_item(&creator_obj, EXT_STRING | EXC_DEFAULT | EXD_CREATOR, 9817c478bd9Sstevel@tonic-gate f->ef_creator, strlen(f->ef_creator)) == -1 || 9827c478bd9Sstevel@tonic-gate ea_set_item(&filetype_obj, EXT_STRING | EXC_DEFAULT | EXD_FILETYPE, 9837c478bd9Sstevel@tonic-gate EXACCT_HDR_STR, strlen(EXACCT_HDR_STR)) == -1 || 9847c478bd9Sstevel@tonic-gate ea_set_item(&hostname_obj, EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME, 9857c478bd9Sstevel@tonic-gate hostbuf, strlen(hostbuf)) == -1) { 9867c478bd9Sstevel@tonic-gate error = ea_error(); 9877c478bd9Sstevel@tonic-gate goto cleanup1; 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate (void) ea_set_group(&hdr_grp, 9917c478bd9Sstevel@tonic-gate EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); 9927c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr_grp, &vers_obj); 9937c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr_grp, &creator_obj); 9947c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr_grp, &filetype_obj); 9957c478bd9Sstevel@tonic-gate (void) ea_attach_to_group(&hdr_grp, &hostname_obj); 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate /* Get the required size by passing a null buffer. */ 9987c478bd9Sstevel@tonic-gate bufsize = ea_pack_object(&hdr_grp, NULL, 0); 9997c478bd9Sstevel@tonic-gate if ((buf = ea_alloc(bufsize)) == NULL) { 10007c478bd9Sstevel@tonic-gate error = ea_error(); 10017c478bd9Sstevel@tonic-gate goto cleanup1; 10027c478bd9Sstevel@tonic-gate } 10037c478bd9Sstevel@tonic-gate 10047c478bd9Sstevel@tonic-gate if (ea_pack_object(&hdr_grp, buf, bufsize) == (size_t)-1) { 10057c478bd9Sstevel@tonic-gate error = ea_error(); 10067c478bd9Sstevel@tonic-gate goto cleanup2; 10077c478bd9Sstevel@tonic-gate } 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate /* 10107c478bd9Sstevel@tonic-gate * To prevent reading the header when reading the file backwards, 10117c478bd9Sstevel@tonic-gate * set the large backskip of the header group to 0 (last 4 bytes). 10127c478bd9Sstevel@tonic-gate */ 10137c478bd9Sstevel@tonic-gate bskip = 0; 10147c478bd9Sstevel@tonic-gate exacct_order32(&bskip); 10157c478bd9Sstevel@tonic-gate bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), 10167c478bd9Sstevel@tonic-gate sizeof (bskip)); 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate if (fwrite(buf, sizeof (char), bufsize, f->ef_fp) != bufsize || 10197c478bd9Sstevel@tonic-gate fflush(f->ef_fp) == EOF) { 10207c478bd9Sstevel@tonic-gate error = EXR_SYSCALL_FAIL; 10217c478bd9Sstevel@tonic-gate goto cleanup2; 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate cleanup2: 10257c478bd9Sstevel@tonic-gate ea_free(buf, bufsize); 10267c478bd9Sstevel@tonic-gate cleanup1: 10277c478bd9Sstevel@tonic-gate (void) ea_free_item(&vers_obj, EUP_ALLOC); 10287c478bd9Sstevel@tonic-gate (void) ea_free_item(&creator_obj, EUP_ALLOC); 10297c478bd9Sstevel@tonic-gate (void) ea_free_item(&filetype_obj, EUP_ALLOC); 10307c478bd9Sstevel@tonic-gate (void) ea_free_item(&hostname_obj, EUP_ALLOC); 10317c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(error); 10327c478bd9Sstevel@tonic-gate return (error == EXR_OK ? 0 : -1); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate const char * 10367c478bd9Sstevel@tonic-gate ea_get_creator(ea_file_t *ef) 10377c478bd9Sstevel@tonic-gate { 10387c478bd9Sstevel@tonic-gate return ((const char *)((ea_file_impl_t *)ef)->ef_creator); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate 10417c478bd9Sstevel@tonic-gate const char * 10427c478bd9Sstevel@tonic-gate ea_get_hostname(ea_file_t *ef) 10437c478bd9Sstevel@tonic-gate { 10447c478bd9Sstevel@tonic-gate return ((const char *)((ea_file_impl_t *)ef)->ef_hostname); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate int 10487c478bd9Sstevel@tonic-gate ea_fdopen(ea_file_t *ef, int fd, const char *creator, int aflags, int oflags) 10497c478bd9Sstevel@tonic-gate { 10507c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate bzero(f, sizeof (*f)); 10537c478bd9Sstevel@tonic-gate f->ef_oflags = oflags; 10547c478bd9Sstevel@tonic-gate f->ef_fd = fd; 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* Initialize depth stack. */ 10577c478bd9Sstevel@tonic-gate if (stack_check(f) == -1) { 10587c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 10597c478bd9Sstevel@tonic-gate goto error1; 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate /* 10637c478bd9Sstevel@tonic-gate * 1. If we are O_CREAT, then we will need to write a header 10647c478bd9Sstevel@tonic-gate * after opening name. 10657c478bd9Sstevel@tonic-gate */ 10667c478bd9Sstevel@tonic-gate if (oflags & O_CREAT) { 10677c478bd9Sstevel@tonic-gate if (creator == NULL) { 10687c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_NO_CREATOR); 10697c478bd9Sstevel@tonic-gate goto error2; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate if ((f->ef_creator = ea_strdup(creator)) == NULL) { 10727c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 10737c478bd9Sstevel@tonic-gate goto error2; 10747c478bd9Sstevel@tonic-gate } 10757c478bd9Sstevel@tonic-gate if ((f->ef_fp = fdopen(f->ef_fd, "w")) == NULL) { 10767c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 10777c478bd9Sstevel@tonic-gate goto error3; 10787c478bd9Sstevel@tonic-gate } 10797c478bd9Sstevel@tonic-gate if (write_header(ef) == -1) { 10807c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 10817c478bd9Sstevel@tonic-gate goto error3; 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate /* 10857c478bd9Sstevel@tonic-gate * 2. If we are not O_CREAT, but are RDWR or WRONLY, we need to 10867c478bd9Sstevel@tonic-gate * seek to EOF so that appends will succeed. 10877c478bd9Sstevel@tonic-gate */ 10887c478bd9Sstevel@tonic-gate } else if (oflags & O_RDWR || oflags & O_WRONLY) { 10897c478bd9Sstevel@tonic-gate if ((f->ef_fp = fdopen(f->ef_fd, "r+")) == NULL) { 10907c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 10917c478bd9Sstevel@tonic-gate goto error2; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate if ((aflags & EO_VALIDATE_MSK) == EO_VALID_HDR) { 10957c478bd9Sstevel@tonic-gate if (validate_header(ef, creator) < 0) { 10967c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 10977c478bd9Sstevel@tonic-gate goto error2; 10987c478bd9Sstevel@tonic-gate } 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate if (fseeko(f->ef_fp, 0, SEEK_END) == -1) { 11027c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 11037c478bd9Sstevel@tonic-gate goto error2; 11047c478bd9Sstevel@tonic-gate } 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate /* 11077c478bd9Sstevel@tonic-gate * 3. This is an undefined manner for opening an exacct file. 11087c478bd9Sstevel@tonic-gate */ 11097c478bd9Sstevel@tonic-gate } else if (oflags != O_RDONLY) { 11107c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_NOTSUPP); 11117c478bd9Sstevel@tonic-gate goto error2; 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate /* 11147c478bd9Sstevel@tonic-gate * 4a. If we are RDONLY, then we are in a position such that 11157c478bd9Sstevel@tonic-gate * either a ea_get_object or an ea_next_object will succeed. If 11167c478bd9Sstevel@tonic-gate * aflags was set to EO_TAIL, seek to the end of the file. 11177c478bd9Sstevel@tonic-gate */ 11187c478bd9Sstevel@tonic-gate } else { 11197c478bd9Sstevel@tonic-gate if ((f->ef_fp = fdopen(f->ef_fd, "r")) == NULL) { 11207c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 11217c478bd9Sstevel@tonic-gate goto error2; 11227c478bd9Sstevel@tonic-gate } 11237c478bd9Sstevel@tonic-gate 11247c478bd9Sstevel@tonic-gate if ((aflags & EO_VALIDATE_MSK) == EO_VALID_HDR) { 11257c478bd9Sstevel@tonic-gate if (validate_header(ef, creator) == -1) { 11267c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 11277c478bd9Sstevel@tonic-gate goto error2; 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate } 11307c478bd9Sstevel@tonic-gate 11317c478bd9Sstevel@tonic-gate /* 11327c478bd9Sstevel@tonic-gate * 4b. Handle the "open at end" option, for consumers who want 11337c478bd9Sstevel@tonic-gate * to go backwards through the file (i.e. lastcomm). 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate if ((aflags & EO_POSN_MSK) == EO_TAIL) { 11367c478bd9Sstevel@tonic-gate if (fseeko(f->ef_fp, 0, SEEK_END) < 0) { 11377c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 11387c478bd9Sstevel@tonic-gate goto error2; 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate } 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 11447c478bd9Sstevel@tonic-gate return (0); 11457c478bd9Sstevel@tonic-gate 11467c478bd9Sstevel@tonic-gate /* Error cleanup code */ 11477c478bd9Sstevel@tonic-gate error3: 11487c478bd9Sstevel@tonic-gate ea_strfree(f->ef_creator); 11497c478bd9Sstevel@tonic-gate error2: 11507c478bd9Sstevel@tonic-gate stack_free(f); 11517c478bd9Sstevel@tonic-gate error1: 11527c478bd9Sstevel@tonic-gate bzero(f, sizeof (*f)); 11537c478bd9Sstevel@tonic-gate return (-1); 11547c478bd9Sstevel@tonic-gate } 11557c478bd9Sstevel@tonic-gate 11567c478bd9Sstevel@tonic-gate int 11577c478bd9Sstevel@tonic-gate ea_open(ea_file_t *ef, const char *name, const char *creator, 11587c478bd9Sstevel@tonic-gate int aflags, int oflags, mode_t mode) 11597c478bd9Sstevel@tonic-gate { 11607c478bd9Sstevel@tonic-gate int fd; 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* 11637c478bd9Sstevel@tonic-gate * If overwriting an existing file, make sure to truncate it 11647c478bd9Sstevel@tonic-gate * to prevent the file being created corrupt. 11657c478bd9Sstevel@tonic-gate */ 11667c478bd9Sstevel@tonic-gate if (oflags & O_CREAT) 11677c478bd9Sstevel@tonic-gate oflags |= O_TRUNC; 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate if ((fd = open(name, oflags, mode)) == -1) { 11707c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 11717c478bd9Sstevel@tonic-gate return (-1); 11727c478bd9Sstevel@tonic-gate } 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate if (ea_fdopen(ef, fd, creator, aflags, oflags) == -1) { 11757c478bd9Sstevel@tonic-gate (void) close(fd); 11767c478bd9Sstevel@tonic-gate return (-1); 11777c478bd9Sstevel@tonic-gate } 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate return (0); 11807c478bd9Sstevel@tonic-gate } 11817c478bd9Sstevel@tonic-gate 11827c478bd9Sstevel@tonic-gate /* 11837c478bd9Sstevel@tonic-gate * ea_close() performs all appropriate close operations on the open exacct file, 11847c478bd9Sstevel@tonic-gate * including releasing any memory allocated while parsing the file. 11857c478bd9Sstevel@tonic-gate */ 11867c478bd9Sstevel@tonic-gate int 11877c478bd9Sstevel@tonic-gate ea_close(ea_file_t *ef) 11887c478bd9Sstevel@tonic-gate { 11897c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 11907c478bd9Sstevel@tonic-gate 11917c478bd9Sstevel@tonic-gate if (f->ef_creator != NULL) 11927c478bd9Sstevel@tonic-gate ea_strfree(f->ef_creator); 11937c478bd9Sstevel@tonic-gate if (f->ef_hostname != NULL) 11947c478bd9Sstevel@tonic-gate ea_strfree(f->ef_hostname); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate ea_free(f->ef_depth, f->ef_mxdeep * sizeof (ea_file_depth_t)); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate if (fclose(f->ef_fp)) { 11997c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_SYSCALL_FAIL); 12007c478bd9Sstevel@tonic-gate return (-1); 12017c478bd9Sstevel@tonic-gate } 12027c478bd9Sstevel@tonic-gate 12037c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 12047c478bd9Sstevel@tonic-gate return (0); 12057c478bd9Sstevel@tonic-gate } 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate /* 12087c478bd9Sstevel@tonic-gate * Empty the input buffer and clear any underlying EOF or error bits set on the 12097c478bd9Sstevel@tonic-gate * underlying FILE. This can be used by any library clients who wish to handle 12107c478bd9Sstevel@tonic-gate * files that are in motion or who wish to seek the underlying file descriptor. 12117c478bd9Sstevel@tonic-gate */ 12127c478bd9Sstevel@tonic-gate void 12137c478bd9Sstevel@tonic-gate ea_clear(ea_file_t *ef) 12147c478bd9Sstevel@tonic-gate { 12157c478bd9Sstevel@tonic-gate ea_file_impl_t *f = (ea_file_impl_t *)ef; 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate (void) fflush(f->ef_fp); 12187c478bd9Sstevel@tonic-gate clearerr(f->ef_fp); 12197c478bd9Sstevel@tonic-gate } 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate /* 12227c478bd9Sstevel@tonic-gate * Copy an ea_object_t. Note that in the case of a group, just the group 12237c478bd9Sstevel@tonic-gate * object will be copied, and not its list of members. To recursively copy 12247c478bd9Sstevel@tonic-gate * a group or a list of items use ea_copy_tree(). 12257c478bd9Sstevel@tonic-gate */ 12267c478bd9Sstevel@tonic-gate ea_object_t * 12277c478bd9Sstevel@tonic-gate ea_copy_object(const ea_object_t *src) 12287c478bd9Sstevel@tonic-gate { 12297c478bd9Sstevel@tonic-gate ea_object_t *dst; 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate /* Allocate a new object and copy to it. */ 12327c478bd9Sstevel@tonic-gate if ((dst = ea_alloc(sizeof (ea_object_t))) == NULL) { 12337c478bd9Sstevel@tonic-gate return (NULL); 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate bcopy(src, dst, sizeof (ea_object_t)); 12367c478bd9Sstevel@tonic-gate dst->eo_next = NULL; 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate switch (src->eo_type) { 12397c478bd9Sstevel@tonic-gate case EO_GROUP: 12407c478bd9Sstevel@tonic-gate dst->eo_group.eg_nobjs = 0; 12417c478bd9Sstevel@tonic-gate dst->eo_group.eg_objs = NULL; 12427c478bd9Sstevel@tonic-gate break; 12437c478bd9Sstevel@tonic-gate case EO_ITEM: 12447c478bd9Sstevel@tonic-gate /* Items containing pointers need special treatment. */ 12457c478bd9Sstevel@tonic-gate switch (src->eo_catalog & EXT_TYPE_MASK) { 12467c478bd9Sstevel@tonic-gate case EXT_STRING: 12477c478bd9Sstevel@tonic-gate if (src->eo_item.ei_string != NULL) { 12487c478bd9Sstevel@tonic-gate dst->eo_item.ei_string = 12497c478bd9Sstevel@tonic-gate ea_strdup(src->eo_item.ei_string); 12507c478bd9Sstevel@tonic-gate if (dst->eo_item.ei_string == NULL) { 12517c478bd9Sstevel@tonic-gate ea_free_object(dst, EUP_ALLOC); 12527c478bd9Sstevel@tonic-gate return (NULL); 12537c478bd9Sstevel@tonic-gate } 12547c478bd9Sstevel@tonic-gate } 12557c478bd9Sstevel@tonic-gate break; 12567c478bd9Sstevel@tonic-gate case EXT_RAW: 12577c478bd9Sstevel@tonic-gate if (src->eo_item.ei_raw != NULL) { 12587c478bd9Sstevel@tonic-gate dst->eo_item.ei_raw = 12597c478bd9Sstevel@tonic-gate ea_alloc(src->eo_item.ei_size); 12607c478bd9Sstevel@tonic-gate if (dst->eo_item.ei_raw == NULL) { 12617c478bd9Sstevel@tonic-gate ea_free_object(dst, EUP_ALLOC); 12627c478bd9Sstevel@tonic-gate return (NULL); 12637c478bd9Sstevel@tonic-gate } 12647c478bd9Sstevel@tonic-gate bcopy(src->eo_item.ei_raw, dst->eo_item.ei_raw, 12657c478bd9Sstevel@tonic-gate (size_t)src->eo_item.ei_size); 12667c478bd9Sstevel@tonic-gate } 12677c478bd9Sstevel@tonic-gate break; 12687c478bd9Sstevel@tonic-gate case EXT_EXACCT_OBJECT: 12697c478bd9Sstevel@tonic-gate if (src->eo_item.ei_object != NULL) { 12707c478bd9Sstevel@tonic-gate dst->eo_item.ei_object = 12717c478bd9Sstevel@tonic-gate ea_alloc(src->eo_item.ei_size); 12727c478bd9Sstevel@tonic-gate if (dst->eo_item.ei_object == NULL) { 12737c478bd9Sstevel@tonic-gate ea_free_object(dst, EUP_ALLOC); 12747c478bd9Sstevel@tonic-gate return (NULL); 12757c478bd9Sstevel@tonic-gate } 12767c478bd9Sstevel@tonic-gate bcopy(src->eo_item.ei_raw, dst->eo_item.ei_raw, 12777c478bd9Sstevel@tonic-gate (size_t)src->eo_item.ei_size); 12787c478bd9Sstevel@tonic-gate } 12797c478bd9Sstevel@tonic-gate break; 12807c478bd9Sstevel@tonic-gate default: 12817c478bd9Sstevel@tonic-gate /* Other item types require no special handling. */ 12827c478bd9Sstevel@tonic-gate break; 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate break; 12857c478bd9Sstevel@tonic-gate default: 12867c478bd9Sstevel@tonic-gate ea_free_object(dst, EUP_ALLOC); 12877c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_INVALID_OBJ); 12887c478bd9Sstevel@tonic-gate return (NULL); 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 12917c478bd9Sstevel@tonic-gate return (dst); 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* 12957c478bd9Sstevel@tonic-gate * Recursively copy a list of ea_object_t. All the elements in the eo_next 12967c478bd9Sstevel@tonic-gate * list will be copied, and any group objects will be recursively copied. 12977c478bd9Sstevel@tonic-gate */ 12987c478bd9Sstevel@tonic-gate ea_object_t * 12997c478bd9Sstevel@tonic-gate ea_copy_object_tree(const ea_object_t *src) 13007c478bd9Sstevel@tonic-gate { 13017c478bd9Sstevel@tonic-gate ea_object_t *ret_obj, *dst, *last; 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate for (ret_obj = last = NULL; src != NULL; 13047c478bd9Sstevel@tonic-gate last = dst, src = src->eo_next) { 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate /* Allocate a new object and copy to it. */ 13077c478bd9Sstevel@tonic-gate if ((dst = ea_copy_object(src)) == NULL) { 13087c478bd9Sstevel@tonic-gate ea_free_object(ret_obj, EUP_ALLOC); 13097c478bd9Sstevel@tonic-gate return (NULL); 13107c478bd9Sstevel@tonic-gate } 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate /* Groups need the object list copying. */ 13137c478bd9Sstevel@tonic-gate if (src->eo_type == EO_GROUP) { 13147c478bd9Sstevel@tonic-gate dst->eo_group.eg_objs = 13157c478bd9Sstevel@tonic-gate ea_copy_object_tree(src->eo_group.eg_objs); 13167c478bd9Sstevel@tonic-gate if (dst->eo_group.eg_objs == NULL) { 13177c478bd9Sstevel@tonic-gate ea_free_object(ret_obj, EUP_ALLOC); 13187c478bd9Sstevel@tonic-gate return (NULL); 13197c478bd9Sstevel@tonic-gate } 13207c478bd9Sstevel@tonic-gate dst->eo_group.eg_nobjs = src->eo_group.eg_nobjs; 13217c478bd9Sstevel@tonic-gate } 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate /* Remember the list head the first time round. */ 13247c478bd9Sstevel@tonic-gate if (ret_obj == NULL) { 13257c478bd9Sstevel@tonic-gate ret_obj = dst; 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate /* Link together if not at the list head. */ 13297c478bd9Sstevel@tonic-gate if (last != NULL) { 13307c478bd9Sstevel@tonic-gate last->eo_next = dst; 13317c478bd9Sstevel@tonic-gate } 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 13347c478bd9Sstevel@tonic-gate return (ret_obj); 13357c478bd9Sstevel@tonic-gate } 13367c478bd9Sstevel@tonic-gate 13377c478bd9Sstevel@tonic-gate /* 13387c478bd9Sstevel@tonic-gate * Read in the specified number of objects, returning the same data 13397c478bd9Sstevel@tonic-gate * structure that would have originally been passed to ea_write(). 13407c478bd9Sstevel@tonic-gate */ 13417c478bd9Sstevel@tonic-gate ea_object_t * 13427c478bd9Sstevel@tonic-gate ea_get_object_tree(ea_file_t *ef, uint32_t nobj) 13437c478bd9Sstevel@tonic-gate { 13447c478bd9Sstevel@tonic-gate ea_object_t *first_obj, *prev_obj, *obj; 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate first_obj = prev_obj = NULL; 13477c478bd9Sstevel@tonic-gate while (nobj--) { 13487c478bd9Sstevel@tonic-gate /* Allocate space for the new object. */ 13497c478bd9Sstevel@tonic-gate obj = ea_alloc(sizeof (ea_object_t)); 13507c478bd9Sstevel@tonic-gate bzero(obj, sizeof (*obj)); 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate /* Read it in. */ 13537c478bd9Sstevel@tonic-gate if (ea_get_object(ef, obj) == -1) { 13547c478bd9Sstevel@tonic-gate ea_free(obj, sizeof (ea_object_t)); 13557c478bd9Sstevel@tonic-gate if (first_obj != NULL) { 13567c478bd9Sstevel@tonic-gate ea_free_object(first_obj, EUP_ALLOC); 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate return (NULL); 13597c478bd9Sstevel@tonic-gate } 13607c478bd9Sstevel@tonic-gate 13617c478bd9Sstevel@tonic-gate /* Link it into the list. */ 13627c478bd9Sstevel@tonic-gate if (first_obj == NULL) { 13637c478bd9Sstevel@tonic-gate first_obj = obj; 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate if (prev_obj != NULL) { 13667c478bd9Sstevel@tonic-gate prev_obj->eo_next = obj; 13677c478bd9Sstevel@tonic-gate } 13687c478bd9Sstevel@tonic-gate prev_obj = obj; 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate /* Recurse if the object is a group with contents. */ 13717c478bd9Sstevel@tonic-gate if (obj->eo_type == EO_GROUP && obj->eo_group.eg_nobjs > 0) { 13727c478bd9Sstevel@tonic-gate if ((obj->eo_group.eg_objs = ea_get_object_tree(ef, 13737c478bd9Sstevel@tonic-gate obj->eo_group.eg_nobjs)) == NULL) { 13747c478bd9Sstevel@tonic-gate /* exacct_error set above. */ 13757c478bd9Sstevel@tonic-gate ea_free_object(first_obj, EUP_ALLOC); 13767c478bd9Sstevel@tonic-gate return (NULL); 13777c478bd9Sstevel@tonic-gate } 13787c478bd9Sstevel@tonic-gate } 13797c478bd9Sstevel@tonic-gate } 13807c478bd9Sstevel@tonic-gate EXACCT_SET_ERR(EXR_OK); 13817c478bd9Sstevel@tonic-gate return (first_obj); 13827c478bd9Sstevel@tonic-gate } 1383