/* * 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); }
/* * 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); }
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); }
/* * 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); }
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); }
/* * 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); }
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)) {
/* * 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); }