/* * void *exacct_create_header(size_t *) * * Overview * exacct_create_header() constructs an exacct file header identifying the * accounting file as the output of the kernel. exacct_create_header() and * the static write_header() and verify_header() routines in libexacct must * remain synchronized. * * Return values * A pointer to a packed exacct buffer containing the appropriate header is * returned; the size of the buffer is placed in the location indicated by * sizep. * * Caller's context * Suitable for KM_SLEEP allocations. */ void * exacct_create_header(size_t *sizep) { ea_object_t *hdr_grp; uint32_t bskip; void *buf; size_t bufsize; hdr_grp = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); (void) ea_attach_item(hdr_grp, (void *)&exacct_version, 0, EXT_UINT32 | EXC_DEFAULT | EXD_VERSION); (void) ea_attach_item(hdr_grp, (void *)exacct_header, 0, EXT_STRING | EXC_DEFAULT | EXD_FILETYPE); (void) ea_attach_item(hdr_grp, (void *)exacct_creator, 0, EXT_STRING | EXC_DEFAULT | EXD_CREATOR); (void) ea_attach_item(hdr_grp, uts_nodename(), 0, EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME); bufsize = ea_pack_object(hdr_grp, NULL, 0); buf = kmem_alloc(bufsize, KM_SLEEP); (void) ea_pack_object(hdr_grp, buf, bufsize); ea_free_object(hdr_grp, EUP_ALLOC); /* * To prevent reading the header when reading the file backwards, * set the large backskip of the header group to 0 (last 4 bytes). */ bskip = 0; exacct_order32(&bskip); bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), sizeof (bskip)); *sizep = bufsize; return (buf); }
ea_object_type_t ea_previous_object(ea_file_t *ef, ea_object_t *obj) { ea_file_impl_t *f = (ea_file_impl_t *)ef; uint32_t bkskip; int r; if (fseeko(f->ef_fp, -((off_t)sizeof (uint32_t)), SEEK_CUR) == -1) { if (errno == EINVAL) { EXACCT_SET_ERR(EXR_EOF); } else { EXACCT_SET_ERR(EXR_SYSCALL_FAIL); } return (EO_ERROR); } if ((r = fread(&bkskip, 1, sizeof (uint32_t), f->ef_fp)) != sizeof (uint32_t)) { if (r == 0) { EXACCT_SET_ERR(EXR_EOF); } else { EXACCT_SET_ERR(EXR_SYSCALL_FAIL); } return (EO_ERROR); } exacct_order32(&bkskip); /* * A backskip of 0 means that the current record can't be skipped over. * This will be true for the header record, and for records longer than * 2^32. */ if (bkskip == 0) { EXACCT_SET_ERR(EXR_EOF); return (EO_ERROR); } (void) stack_previous_object(f); if (fseeko(f->ef_fp, -((off_t)bkskip), SEEK_CUR) == -1) { if (errno == EINVAL) { /* * If we attempted to seek past BOF, then the file was * corrupt, as we can only trust the backskip we read. */ EXACCT_SET_ERR(EXR_CORRUPT_FILE); } else { EXACCT_SET_ERR(EXR_SYSCALL_FAIL); } return (EO_ERROR); } f->ef_advance = 0; return (ea_next_object(ef, obj)); }
static int write_header(ea_file_t *ef) { ea_object_t hdr_grp; ea_object_t vers_obj; ea_object_t creator_obj; ea_object_t filetype_obj; ea_object_t hostname_obj; uint32_t bskip; const uint32_t version = EXACCT_VERSION; ea_file_impl_t *f = (ea_file_impl_t *)ef; void *buf; size_t bufsize; char hostbuf[SYSINFO_BUFSIZE]; int error = EXR_OK; bzero(&hdr_grp, sizeof (ea_object_t)); bzero(&vers_obj, sizeof (ea_object_t)); bzero(&creator_obj, sizeof (ea_object_t)); bzero(&filetype_obj, sizeof (ea_object_t)); bzero(&hostname_obj, sizeof (ea_object_t)); bzero(hostbuf, SYSINFO_BUFSIZE); (void) sysinfo(SI_HOSTNAME, hostbuf, SYSINFO_BUFSIZE); if (ea_set_item(&vers_obj, EXT_UINT32 | EXC_DEFAULT | EXD_VERSION, (void *)&version, 0) == -1 || ea_set_item(&creator_obj, EXT_STRING | EXC_DEFAULT | EXD_CREATOR, f->ef_creator, strlen(f->ef_creator)) == -1 || ea_set_item(&filetype_obj, EXT_STRING | EXC_DEFAULT | EXD_FILETYPE, EXACCT_HDR_STR, strlen(EXACCT_HDR_STR)) == -1 || ea_set_item(&hostname_obj, EXT_STRING | EXC_DEFAULT | EXD_HOSTNAME, hostbuf, strlen(hostbuf)) == -1) { error = ea_error(); goto cleanup1; } (void) ea_set_group(&hdr_grp, EXT_GROUP | EXC_DEFAULT | EXD_GROUP_HEADER); (void) ea_attach_to_group(&hdr_grp, &vers_obj); (void) ea_attach_to_group(&hdr_grp, &creator_obj); (void) ea_attach_to_group(&hdr_grp, &filetype_obj); (void) ea_attach_to_group(&hdr_grp, &hostname_obj); /* Get the required size by passing a null buffer. */ bufsize = ea_pack_object(&hdr_grp, NULL, 0); if ((buf = ea_alloc(bufsize)) == NULL) { error = ea_error(); goto cleanup1; } if (ea_pack_object(&hdr_grp, buf, bufsize) == (size_t)-1) { error = ea_error(); goto cleanup2; } /* * To prevent reading the header when reading the file backwards, * set the large backskip of the header group to 0 (last 4 bytes). */ bskip = 0; exacct_order32(&bskip); bcopy(&bskip, (char *)buf + bufsize - sizeof (bskip), sizeof (bskip)); if (fwrite(buf, sizeof (char), bufsize, f->ef_fp) != bufsize || fflush(f->ef_fp) == EOF) { error = EXR_SYSCALL_FAIL; goto cleanup2; } cleanup2: ea_free(buf, bufsize); cleanup1: (void) ea_free_item(&vers_obj, EUP_ALLOC); (void) ea_free_item(&creator_obj, EUP_ALLOC); (void) ea_free_item(&filetype_obj, EUP_ALLOC); (void) ea_free_item(&hostname_obj, EUP_ALLOC); EXACCT_SET_ERR(error); return (error == EXR_OK ? 0 : -1); }
/* * xget_object() contains the logic for extracting an individual object from a * packed buffer, which it consumes using xread() and xseek() operations * provided by the caller. flags may be set to either EUP_ALLOC, in which case * new memory is allocated for the variable length items unpacked, or * EUP_NOALLOC, in which case item data pointer indicate locations within the * buffer, using the provided xpos() function. EUP_NOALLOC is generally not * useful for callers representing interaction with actual file streams, and * should not be specified thereby. */ static ea_object_type_t xget_object( ea_file_impl_t *f, ea_object_t *obj, size_t (*xread)(ea_file_impl_t *, void *, size_t), off_t (*xseek)(ea_file_impl_t *, off_t), void *(*xpos)(ea_file_impl_t *), int flags) { ea_size_t sz; uint32_t gp_backskip, scratch32; void *buf; size_t r; /* Read the catalog tag. */ if ((r = xread(f, &obj->eo_catalog, sizeof (ea_catalog_t))) == 0) { EXACCT_SET_ERR(EXR_EOF); return (EO_ERROR); } else if (r != sizeof (ea_catalog_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order32(&obj->eo_catalog); /* * If this is a record group, we treat it separately: only record * groups cause us to allocate new depth frames. */ if ((obj->eo_catalog & EXT_TYPE_MASK) == EXT_GROUP) { obj->eo_type = EO_GROUP; /* Read size field, and number of objects. */ if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order64(&sz); if (xread(f, &obj->eo_group.eg_nobjs, sizeof (uint32_t)) != sizeof (uint32_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order32(&obj->eo_group.eg_nobjs); /* Now read the group's small backskip. */ if (xread(f, &gp_backskip, sizeof (uint32_t)) != sizeof (uint32_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } /* Push a new depth stack frame. */ if (stack_new_group(f, obj->eo_group.eg_nobjs) != 0) { /* exacct_error set above */ return (EO_ERROR); } /* * If the group has no items, we now need to position to the * end of the group, because there will be no subsequent calls * to process the group, it being empty. */ if (obj->eo_group.eg_nobjs == 0) { if (stack_next_object(f, xread) == -1) { /* exacct_error set above. */ return (EO_ERROR); } } f->ef_advance = 0; EXACCT_SET_ERR(EXR_OK); return (obj->eo_type); } /* * Otherwise we are reading an item. */ obj->eo_type = EO_ITEM; switch (obj->eo_catalog & EXT_TYPE_MASK) { case EXT_STRING: case EXT_EXACCT_OBJECT: case EXT_RAW: if (xread(f, &sz, sizeof (ea_size_t)) != sizeof (ea_size_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order64(&sz); /* * Subtract backskip value from size. */ sz -= sizeof (uint32_t); if ((flags & EUP_ALLOC_MASK) == EUP_NOALLOC) { buf = xpos(f); if (xseek(f, sz) == -1) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } } else { if ((buf = ea_alloc(sz)) == NULL) /* exacct_error set above. */ return (EO_ERROR); if (xread(f, buf, sz) != sz) { ea_free(buf, sz); EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } } obj->eo_item.ei_string = buf; /* * Maintain our consistent convention that string lengths * include the terminating NULL character. */ obj->eo_item.ei_size = sz; break; case EXT_UINT8: if (xread(f, &obj->eo_item.ei_uint8, sizeof (uint8_t)) != sizeof (uint8_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } obj->eo_item.ei_size = sizeof (uint8_t); break; case EXT_UINT16: if (xread(f, &obj->eo_item.ei_uint16, sizeof (uint16_t)) != sizeof (uint16_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order16(&obj->eo_item.ei_uint16); obj->eo_item.ei_size = sizeof (uint16_t); break; case EXT_UINT32: if (xread(f, &obj->eo_item.ei_uint32, sizeof (uint32_t)) != sizeof (uint32_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order32(&obj->eo_item.ei_uint32); obj->eo_item.ei_size = sizeof (uint32_t); break; case EXT_UINT64: if (xread(f, &obj->eo_item.ei_uint64, sizeof (uint64_t)) != sizeof (uint64_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order64(&obj->eo_item.ei_uint64); obj->eo_item.ei_size = sizeof (uint64_t); break; case EXT_DOUBLE: if (xread(f, &obj->eo_item.ei_double, sizeof (double)) != sizeof (double)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order64((uint64_t *)&obj->eo_item.ei_double); obj->eo_item.ei_size = sizeof (double); break; default: /* * We've encountered an unknown type value. Flag the error and * exit. */ EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } /* * Advance over current large backskip value, * and position at the start of the next object. */ if (xread(f, &scratch32, sizeof (scratch32)) != sizeof (scratch32)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } if (stack_next_object(f, xread) == -1) { /* exacct_error set above. */ return (EO_ERROR); } f->ef_advance = 0; EXACCT_SET_ERR(EXR_OK); return (obj->eo_type); }
/* * ea_next_object(), ea_previous_object(), and ea_get_object() are written such * that the file cursor is always located on an object boundary. */ ea_object_type_t ea_next_object(ea_file_t *ef, ea_object_t *obj) { ea_file_impl_t *f = (ea_file_impl_t *)ef; ea_size_t len; off_t backup; size_t ret; /* * If ef_advance is zero, then we are executing after a get or previous * operation and do not move to the next or previous object. Otherwise, * advance to the next available item. Note that ef_advance does NOT * include the large backskip at the end of a object, this being dealt * with by the depth stack handling in stack_next_object. */ if (f->ef_advance != 0) { if (fseeko(f->ef_fp, (off_t)f->ef_advance, SEEK_CUR) == -1) { EXACCT_SET_ERR(EXR_SYSCALL_FAIL); return (EO_ERROR); } if (stack_next_object(f, fread_wrapper) == -1) { /* exacct_error set above. */ return (EO_ERROR); } } f->ef_advance = 0; /* Read the catalog tag */ ret = fread(&obj->eo_catalog, 1, sizeof (ea_catalog_t), f->ef_fp); if (ret == 0) { EXACCT_SET_ERR(EXR_EOF); return (EO_ERROR); } else if (ret < sizeof (ea_catalog_t)) { EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order32(&obj->eo_catalog); backup = sizeof (ea_catalog_t); obj->eo_type = EO_ITEM; /* Figure out the offset to just before the large backskip. */ switch (obj->eo_catalog & EXT_TYPE_MASK) { case EXT_GROUP: obj->eo_type = EO_GROUP; f->ef_advance = sizeof (uint32_t); /* FALLTHROUGH */ case EXT_STRING: case EXT_EXACCT_OBJECT: case EXT_RAW: if (fread(&len, 1, sizeof (ea_size_t), f->ef_fp) < sizeof (ea_size_t)) { obj->eo_type = EO_NONE; EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } exacct_order64(&len); /* Note: len already includes the size of the backskip. */ f->ef_advance += sizeof (ea_catalog_t) + sizeof (ea_size_t) + len; backup += sizeof (ea_size_t); break; case EXT_UINT8: f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint8_t) + sizeof (uint32_t); break; case EXT_UINT16: f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint16_t) + sizeof (uint32_t); break; case EXT_UINT32: f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint32_t) + sizeof (uint32_t); break; case EXT_UINT64: f->ef_advance = sizeof (ea_catalog_t) + sizeof (uint64_t) + sizeof (uint32_t); break; case EXT_DOUBLE: f->ef_advance = sizeof (ea_catalog_t) + sizeof (double) + sizeof (uint32_t); break; default: obj->eo_type = EO_NONE; EXACCT_SET_ERR(EXR_CORRUPT_FILE); return (EO_ERROR); } /* Reposition to the start of this object. */ if (fseeko(f->ef_fp, -backup, SEEK_CUR) == -1) { obj->eo_type = EO_NONE; f->ef_advance = 0; EXACCT_SET_ERR(EXR_SYSCALL_FAIL); return (EO_ERROR); } EXACCT_SET_ERR(EXR_OK); return (obj->eo_type); }