Esempio n. 1
0
/*
 * 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);
}
Esempio n. 2
0
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));
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
/*
 * 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);
}
Esempio n. 5
0
/*
 * 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);
}