Exemple #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);
}
Exemple #2
0
/*
 * int exacct_assemble_proc_usage(proc_usage_t *, int (*)(void *, size_t, void
 *	*, size_t, size_t *), void *, size_t, size_t *)
 *
 * Overview
 *   Assemble record with miscellaneous accounting information about the process
 *   and execute the callback on it. It is the callback's job to set "actual" to
 *   the size of record.
 *
 * Return values
 *   The result of the callback function, unless the extended process accounting
 *   feature is not active, in which case ENOTACTIVE is returned.
 *
 * Caller's context
 *   Suitable for KM_SLEEP allocations.
 */
int
exacct_assemble_proc_usage(ac_info_t *ac_proc, proc_usage_t *pu,
    int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
    void *ubuf, size_t ubufsize, size_t *actual, int flag)
{
	ulong_t mask[AC_MASK_SZ];
	ea_object_t *proc_record;
	ea_catalog_t record_type;
	void *buf;
	size_t bufsize;
	int ret;

	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL);

	mutex_enter(&ac_proc->ac_lock);
	if (ac_proc->ac_state == AC_OFF) {
		mutex_exit(&ac_proc->ac_lock);
		return (ENOTACTIVE);
	}
	bt_copy(&ac_proc->ac_mask[0], mask, AC_MASK_SZ);
	mutex_exit(&ac_proc->ac_lock);

	switch (flag) {
	case EW_FINAL:
		record_type = EXD_GROUP_PROC;
		break;
	case EW_PARTIAL:
		record_type = EXD_GROUP_PROC_PARTIAL;
		break;
	}

	proc_record = exacct_assemble_proc_record(pu, mask, record_type);
	if (proc_record == NULL)
		return (0);

	/*
	 * Pack object into buffer and pass to callback.
	 */
	bufsize = ea_pack_object(proc_record, NULL, 0);
	buf = kmem_alloc(bufsize, KM_SLEEP);
	(void) ea_pack_object(proc_record, buf, bufsize);

	ret = callback(ac_proc, ubuf, ubufsize, buf, bufsize, actual);

	/*
	 * Free all previously allocations.
	 */
	kmem_free(buf, bufsize);
	ea_free_object(proc_record, EUP_ALLOC);
	return (ret);
}
Exemple #3
0
int
exacct_assemble_flow_usage(ac_info_t *ac_flow, flow_usage_t *fu,
    int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
    void *ubuf, size_t ubufsize, size_t *actual)
{
	ulong_t mask[AC_MASK_SZ];
	ea_object_t *flow_usage;
	ea_catalog_t record_type;
	void *buf;
	size_t bufsize;
	int ret;

	mutex_enter(&ac_flow->ac_lock);
	if (ac_flow->ac_state == AC_OFF) {
		mutex_exit(&ac_flow->ac_lock);
		return (ENOTACTIVE);
	}
	bt_copy(&ac_flow->ac_mask[0], mask, AC_MASK_SZ);
	mutex_exit(&ac_flow->ac_lock);

	record_type = EXD_GROUP_FLOW;

	flow_usage = exacct_assemble_flow_record(fu, mask, record_type);
	if (flow_usage == NULL) {
		return (0);
	}

	/*
	 * Pack object into buffer and pass to callback.
	 */
	bufsize = ea_pack_object(flow_usage, NULL, 0);
	buf = kmem_alloc(bufsize, KM_NOSLEEP);
	if (buf == NULL) {
		return (ENOMEM);
	}

	(void) ea_pack_object(flow_usage, buf, bufsize);

	ret = callback(ac_flow, ubuf, ubufsize, buf, bufsize, actual);

	/*
	 * Free all previously allocations.
	 */
	kmem_free(buf, bufsize);
	ea_free_object(flow_usage, EUP_ALLOC);
	return (ret);
}
Exemple #4
0
/*
 * exacct_tag_proc(pid_t, taskid_t, void *, size_t, int, char *)
 *
 * Overview
 *   exacct_tag_proc() provides the exacct record construction and writing
 *   support required by putacct(2) for processes.
 *
 * Return values
 *   The result of the write operation is returned, unless the extended
 *   accounting facility is not active, in which case ENOTACTIVE is returned.
 *
 * Caller's context
 *   Suitable for KM_SLEEP allocations.
 */
int
exacct_tag_proc(ac_info_t *ac_proc, pid_t pid, taskid_t tkid, void *ubuf,
    size_t ubufsz, int flags, const char *hostname)
{
	int error = 0;
	void *buf;
	size_t bufsize;
	ea_catalog_t cat;
	ea_object_t *tag;

	mutex_enter(&ac_proc->ac_lock);
	if (ac_proc->ac_state == AC_OFF || ac_proc->ac_vnode == NULL) {
		mutex_exit(&ac_proc->ac_lock);
		return (ENOTACTIVE);
	}
	mutex_exit(&ac_proc->ac_lock);

	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_PROC_TAG);
	(void) ea_attach_item(tag, &pid, sizeof (uint32_t),
	    EXT_UINT32 | EXC_DEFAULT | EXD_PROC_PID);
	(void) ea_attach_item(tag, &tkid, 0,
	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
	(void) ea_attach_item(tag, (void *)hostname, 0,
	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
	if (flags == EP_RAW)
		cat = EXT_RAW | EXC_DEFAULT | EXD_PROC_TAG;
	else
		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_PROC_TAG;
	(void) ea_attach_item(tag, ubuf, ubufsz, cat);

	bufsize = ea_pack_object(tag, NULL, 0);
	buf = kmem_alloc(bufsize, KM_SLEEP);
	(void) ea_pack_object(tag, buf, bufsize);
	error = exacct_vn_write(ac_proc, buf, bufsize);
	kmem_free(buf, bufsize);
	ea_free_object(tag, EUP_ALLOC);
	return (error);
}
Exemple #5
0
int
ea_write_object(ea_file_t *ef, ea_object_t *obj)
{
	ea_size_t sz;
	void *buf;
	ea_file_impl_t *f = (ea_file_impl_t *)ef;

	/*
	 * If we weren't opened for writing, this call fails.
	 */
	if ((f->ef_oflags & O_RDWR) == 0 &&
	    (f->ef_oflags & O_WRONLY) == 0) {
		EXACCT_SET_ERR(EXR_NOTSUPP);
		return (-1);
	}

	/* Pack with a null buffer to get the size. */
	sz = ea_pack_object(obj, NULL, 0);
	if (sz == -1 || (buf = ea_alloc(sz)) == NULL) {
		/* exacct_error set above. */
		return (-1);
	}
	if (ea_pack_object(obj, buf, sz) == (size_t)-1) {
		ea_free(buf, sz);
		/* exacct_error set above. */
		return (-1);
	}
	if (fwrite(buf, sizeof (char), sz, f->ef_fp) != sz) {
		ea_free(buf, sz);
		EXACCT_SET_ERR(EXR_SYSCALL_FAIL);
		return (-1);
	}
	ea_free(buf, sz);
	EXACCT_SET_ERR(EXR_OK);
	return (0);
}
Exemple #6
0
/*
 * int exacct_tag_task(task_t *, void *, size_t, int)
 *
 * Overview
 *   exacct_tag_task() provides the exacct record construction and writing
 *   support required by putacct(2) for task entities.
 *
 * Return values
 *   The result of the write operation is returned, unless the extended
 *   accounting facility is not active, in which case ENOTACTIVE is returned.
 *
 * Caller's context
 *   Suitable for KM_SLEEP allocations.
 */
int
exacct_tag_task(ac_info_t *ac_task, task_t *tk, void *ubuf, size_t ubufsz,
    int flags)
{
	int error = 0;
	void *buf;
	size_t bufsize;
	ea_catalog_t cat;
	ea_object_t *tag;

	mutex_enter(&ac_task->ac_lock);
	if (ac_task->ac_state == AC_OFF || ac_task->ac_vnode == NULL) {
		mutex_exit(&ac_task->ac_lock);
		return (ENOTACTIVE);
	}
	mutex_exit(&ac_task->ac_lock);

	tag = ea_alloc_group(EXT_GROUP | EXC_DEFAULT | EXD_GROUP_TASK_TAG);
	(void) ea_attach_item(tag, &tk->tk_tkid, 0,
	    EXT_UINT32 | EXC_DEFAULT | EXD_TASK_TASKID);
	(void) ea_attach_item(tag, tk->tk_zone->zone_nodename, 0,
	    EXT_STRING | EXC_DEFAULT | EXD_TASK_HOSTNAME);
	if (flags == EP_RAW)
		cat = EXT_RAW | EXC_DEFAULT | EXD_TASK_TAG;
	else
		cat = EXT_EXACCT_OBJECT | EXC_DEFAULT | EXD_TASK_TAG;
	(void) ea_attach_item(tag, ubuf, ubufsz, cat);

	bufsize = ea_pack_object(tag, NULL, 0);
	buf = kmem_alloc(bufsize, KM_SLEEP);
	(void) ea_pack_object(tag, buf, bufsize);
	error = exacct_vn_write(ac_task, buf, bufsize);
	kmem_free(buf, bufsize);
	ea_free_object(tag, EUP_ALLOC);
	return (error);
}
Exemple #7
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);
}
/*
 * Convert the perl form of an ::Object into the corresponding exacct form.
 * This is used prior to writing an ::Object to a file, or passing it to
 * putacct.  This is only required for embedded items and groups - for normal
 * items it is a no-op.
 */
ea_object_t *
deflate_xs_ea_object(SV *sv)
{
	xs_ea_object_t	*xs_obj;
	ea_object_t	*ea_obj;

	/* Get the source xs_ea_object_t. */
	PERL_ASSERT(sv != NULL);
	sv = SvRV(sv);
	PERL_ASSERT(sv != NULL);
	xs_obj = INT2PTR(xs_ea_object_t *, SvIV(sv));
	PERL_ASSERT(xs_obj != NULL);
	ea_obj = xs_obj->ea_obj;
	PERL_ASSERT(ea_obj != NULL);

	/* Break any list this object is a part of. */
	ea_obj->eo_next = NULL;

	/* Deal with Items containing embedded Objects. */
	if (IS_EMBED_ITEM(xs_obj)) {
		xs_ea_object_t	*child_xs_obj;
		SV		*perl_obj;
		size_t		bufsz;

		/* Get the underlying perl object an deflate that in turn. */
		perl_obj = xs_obj->perl_obj;
		PERL_ASSERT(perl_obj != NULL);
		deflate_xs_ea_object(perl_obj);
		perl_obj = SvRV(perl_obj);
		PERL_ASSERT(perl_obj != NULL);
		child_xs_obj = INT2PTR(xs_ea_object_t *, SvIV(perl_obj));
		PERL_ASSERT(child_xs_obj->ea_obj != NULL);

		/* Free any existing object contents. */
		if (ea_obj->eo_item.ei_object != NULL) {
			ea_free(ea_obj->eo_item.ei_object,
			    ea_obj->eo_item.ei_size);
			ea_obj->eo_item.ei_object = NULL;
			ea_obj->eo_item.ei_size = 0;
		}

		/*  Pack the object. */
		while (1) {
			/* Use the last buffer size as a best guess. */
			if (last_bufsz != 0) {
				ea_obj->eo_item.ei_object =
				    ea_alloc(last_bufsz);
				PERL_ASSERT(ea_obj->eo_item.ei_object != NULL);
			} else {
				ea_obj->eo_item.ei_object = NULL;
			}

			/*
			 * Pack the object.  If the buffer is too small,
			 * we will go around again with the correct size.
			 * If unsucessful, we will bail.
			 */
			if ((bufsz = ea_pack_object(child_xs_obj->ea_obj,
			    ea_obj->eo_item.ei_object, last_bufsz)) == -1) {
				ea_free(ea_obj->eo_item.ei_object, last_bufsz);
				ea_obj->eo_item.ei_object = NULL;
				return (NULL);
			} else if (bufsz > last_bufsz) {
				ea_free(ea_obj->eo_item.ei_object, last_bufsz);
				last_bufsz = bufsz;
				continue;
			} else {
				ea_obj->eo_item.ei_size = bufsz;
				break;
			}
		}

	/* Deal with Groups. */
	} else if (IS_GROUP(xs_obj)) {
Exemple #9
0
/*
 * int exacct_assemble_task_usage(task_t *, int (*)(void *, size_t, void *,
 *	size_t, size_t *), void *, size_t, size_t *, int)
 *
 * Overview
 *   exacct_assemble_task_usage() builds the packed exacct buffer for the
 *   indicated task, executes the given callback function, and free the packed
 *   buffer.
 *
 * Return values
 *   Returns 0 on success; otherwise the appropriate error code is returned.
 *
 * Caller's context
 *   Suitable for KM_SLEEP allocations.
 */
int
exacct_assemble_task_usage(ac_info_t *ac_task, task_t *tk,
    int (*callback)(ac_info_t *, void *, size_t, void *, size_t, size_t *),
    void *ubuf, size_t ubufsize, size_t *actual, int flag)
{
	ulong_t mask[AC_MASK_SZ];
	ea_object_t *task_record;
	ea_catalog_t record_type;
	task_usage_t *tu;
	void *buf;
	size_t bufsize;
	int ret;

	ASSERT(flag == EW_FINAL || flag == EW_PARTIAL || flag == EW_INTERVAL);

	mutex_enter(&ac_task->ac_lock);
	if (ac_task->ac_state == AC_OFF) {
		mutex_exit(&ac_task->ac_lock);
		return (ENOTACTIVE);
	}
	bt_copy(ac_task->ac_mask, mask, AC_MASK_SZ);
	mutex_exit(&ac_task->ac_lock);

	switch (flag) {
	case EW_FINAL:
		record_type = EXD_GROUP_TASK;
		break;
	case EW_PARTIAL:
		record_type = EXD_GROUP_TASK_PARTIAL;
		break;
	case EW_INTERVAL:
		record_type = EXD_GROUP_TASK_INTERVAL;
		break;
	}

	/*
	 * Calculate task usage and assemble it into the task record.
	 */
	tu = kmem_zalloc(sizeof (task_usage_t), KM_SLEEP);
	exacct_calculate_task_usage(tk, tu, flag);
	task_record = exacct_assemble_task_record(tk, tu, mask, record_type);
	if (task_record == NULL) {
		/*
		 * The current configuration of the accounting system has
		 * resulted in records with no data; accordingly, we don't write
		 * these, but we return success.
		 */
		kmem_free(tu, sizeof (task_usage_t));
		return (0);
	}

	/*
	 * Pack object into buffer and run callback on it.
	 */
	bufsize = ea_pack_object(task_record, NULL, 0);
	buf = kmem_alloc(bufsize, KM_SLEEP);
	(void) ea_pack_object(task_record, buf, bufsize);
	ret = callback(ac_task, ubuf, ubufsize, buf, bufsize, actual);

	/*
	 * Free all previously allocated structures.
	 */
	kmem_free(buf, bufsize);
	ea_free_object(task_record, EUP_ALLOC);
	kmem_free(tu, sizeof (task_usage_t));
	return (ret);
}