summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/brand/lx/os/lx_acct.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/uts/common/brand/lx/os/lx_acct.c')
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_acct.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/usr/src/uts/common/brand/lx/os/lx_acct.c b/usr/src/uts/common/brand/lx/os/lx_acct.c
new file mode 100644
index 0000000000..7f38a240ab
--- /dev/null
+++ b/usr/src/uts/common/brand/lx/os/lx_acct.c
@@ -0,0 +1,198 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2017 Joyent, Inc.
+ */
+
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <sys/systm.h>
+#include <sys/acct.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+#include <sys/cred.h>
+#include <sys/file.h>
+#include <sys/vnode.h>
+#include <sys/session.h>
+#include <sys/wait.h>
+#include <sys/ddi.h>
+#include <sys/zone.h>
+#include <sys/lx_types.h>
+
+/*
+ * Based on the Linux acct(5) man page, their comp_t definition is the same
+ * as ours. lxac_etime is encoded as a float for v3 accounting records.
+ */
+
+#define LX_ACCT_VERSION 3
+
+/*
+ * Bit flags in lxac_flag. The Linux AFORK and ASU match native. The rest of
+ * the flags diverge.
+ */
+#define LX_AFORK 0x01 /* executed fork, but no exec */
+#define LX_ASU 0x02 /* used superuser privileges */
+#define LX_ACORE 0x08 /* dumped core */
+#define LX_AXSIG 0x10 /* killed by a signal */
+
+typedef struct lx_acct {
+ char lxac_flag;
+ char lxac_version;
+ uint16_t lxac_tty;
+ uint32_t lxac_exitcode;
+ uint32_t lxac_uid;
+ uint32_t lxac_gid;
+ uint32_t lxac_pid;
+ uint32_t lxac_ppid;
+ uint32_t lxac_btime; /* seconds since the epoch */
+ uint32_t lxac_etime; /* float representation of ticks */
+ comp_t lxac_utime;
+ comp_t lxac_stime;
+ comp_t lxac_mem; /* kb */
+ comp_t lxac_io; /* unused */
+ comp_t lxac_rw; /* unused */
+ comp_t lxac_minflt;
+ comp_t lxac_majflt;
+ comp_t lxac_swaps; /* unused */
+ char lxac_comm[16];
+} lx_acct_t;
+
+/*
+ * Same functionality as acct_compress(). Produce a pseudo-floating point
+ * representation with 3 bits base-8 exponent, 13 bits fraction.
+ */
+static comp_t
+lx_acct_compt(ulong_t t)
+{
+ int exp = 0, round = 0;
+
+ while (t >= 8192) {
+ exp++;
+ round = t & 04;
+ t >>= 3;
+ }
+ if (round) {
+ t++;
+ if (t >= 8192) {
+ t >>= 3;
+ exp++;
+ }
+ }
+#ifdef _LP64
+ if (exp > 7) {
+ /* prevent wraparound */
+ t = 8191;
+ exp = 7;
+ }
+#endif
+ return ((exp << 13) + t);
+}
+
+/*
+ * 32-bit IEEE float encoding as-per Linux.
+ */
+static uint32_t
+lx_acct_float(int64_t t)
+{
+ uint32_t val, exp = 190;
+
+ if (t == 0)
+ return (0);
+
+ while (t > 0) {
+ t <<= 1;
+ exp--;
+ }
+ val = (uint32_t)(t >> 40) & 0x7fffffu;
+
+ return (val | (exp << 23));
+}
+
+/*
+ * Write a Linux-formatted record to the accounting file.
+ */
+void
+lx_acct_out(vnode_t *vp, int exit_status)
+{
+ struct proc *p;
+ user_t *ua;
+ struct cred *cr;
+ dev_t d;
+ pid_t pid, ppid;
+ struct vattr va;
+ ssize_t resid = 0;
+ int err;
+ lx_acct_t a;
+
+ p = curproc;
+ ua = PTOU(p);
+ cr = CRED();
+
+ bzero(&a, sizeof (a));
+
+ a.lxac_flag = ua->u_acflag & (LX_AFORK | LX_ASU);
+ a.lxac_version = LX_ACCT_VERSION;
+ d = cttydev(p);
+ a.lxac_tty = LX_MAKEDEVICE(getmajor(d), getminor(d));
+ if (WIFEXITED(exit_status)) {
+ a.lxac_exitcode = WEXITSTATUS(exit_status);
+ } else if (WIFSIGNALED(exit_status)) {
+ a.lxac_flag |= LX_AXSIG;
+ if (WCOREDUMP(exit_status)) {
+ a.lxac_flag |= LX_ACORE;
+ }
+ }
+ a.lxac_uid = crgetruid(cr);
+ a.lxac_gid = crgetrgid(cr);
+ pid = p->p_pid;
+ ppid = p->p_ppid;
+ /* Perform pid translation ala lxpr_fixpid(). */
+ if (pid == curzone->zone_proc_initpid) {
+ pid = 1;
+ ppid = 0;
+ } else {
+ if (ppid == curzone->zone_proc_initpid) {
+ ppid = 1;
+ } else if (ppid == curzone->zone_zsched->p_pid ||
+ (p->p_flag & SZONETOP) != 0) {
+ ppid = 1;
+ }
+ }
+ a.lxac_pid = pid;
+ a.lxac_ppid = ppid;
+ a.lxac_btime = ua->u_start.tv_sec;
+ /* For Linux v3 accounting record, this is an encoded float. */
+ a.lxac_etime = lx_acct_float(ddi_get_lbolt() - ua->u_ticks);
+ a.lxac_utime = lx_acct_compt(NSEC_TO_TICK(p->p_acct[LMS_USER]));
+ a.lxac_stime = lx_acct_compt(
+ NSEC_TO_TICK(p->p_acct[LMS_SYSTEM] + p->p_acct[LMS_TRAP]));
+ a.lxac_mem = lx_acct_compt((ulong_t)(ptob(ua->u_mem) / 1024));
+ /* a.lxac_io unused */
+ /* a.lxac_rw unused */
+ a.lxac_minflt = lx_acct_compt((ulong_t)p->p_ru.minflt);
+ a.lxac_majflt = lx_acct_compt((ulong_t)p->p_ru.majflt);
+ /* a.lxac_swaps unused */
+ bcopy(ua->u_comm, a.lxac_comm, sizeof (a.lxac_comm));
+
+ /*
+ * As with the native acct() handling, we save the size so that if the
+ * write fails, we can reset the size to avoid corrupting the accounting
+ * file.
+ */
+ va.va_mask = AT_SIZE;
+ if (VOP_GETATTR(vp, &va, 0, kcred, NULL) == 0) {
+ err = vn_rdwr(UIO_WRITE, vp, (caddr_t)&a, sizeof (a), 0LL,
+ UIO_SYSSPACE, FAPPEND, (rlim64_t)MAXOFF_T, kcred, &resid);
+ if (err != 0 || resid != 0)
+ (void) VOP_SETATTR(vp, &va, 0, kcred, NULL);
+ }
+}