-/* kern_acct.c 6.2 84/07/08 */
+/*-
+ * Copyright (c) 1982, 1986, 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * %sccs.include.proprietary.c%
+ *
+ * @(#)kern_acct.c 8.6 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/resourcevar.h>
+#include <sys/proc.h>
+#include <sys/ioctl.h>
+#include <sys/termios.h>
+#include <sys/tty.h>
+#include <sys/vnode.h>
+#include <sys/mount.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/acct.h>
+#include <sys/syslog.h>
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/inode.h"
-#include "../h/fs.h"
-#include "../h/kernel.h"
-#include "../h/acct.h"
-#include "../h/uio.h"
+/*
+ * Values associated with enabling and disabling accounting
+ */
+int acctsuspend = 2; /* stop accounting when < 2% free space left */
+int acctresume = 4; /* resume when free space risen to > 4% */
+int acctchkfreq = 15; /* frequency (in seconds) to check space */
/*
* SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY.
*/
-struct inode *acctp;
-struct inode *savacctp;
+struct vnode *acctp;
+struct vnode *savacctp;
/*
- * Perform process accounting functions.
+ * Enable or disable process accounting.
+ *
+ * If a non-null filename is given, that file is used to store accounting
+ * records on process exit. If a null filename is given process accounting
+ * is suspended. If accounting is enabled, the system checks the amount
+ * of freespace on the filesystem at timeval intervals. If the amount of
+ * freespace is below acctsuspend percent, accounting is suspended. If
+ * accounting has been suspended, and freespace rises above acctresume,
+ * accounting is resumed.
*/
-sysacct()
+struct acct_args {
+ char *fname;
+};
+acct(p, uap, retval)
+ struct proc *p;
+ struct acct_args *uap;
+ int *retval;
{
- register struct inode *ip;
- register struct a {
- char *fname;
- } *uap = (struct a *)u.u_ap;
- register struct nameidata *ndp = &u.u_nd;
+ register struct vnode *vp;
+ extern void acctwatch __P((void *));
+ struct vnode *oacctp;
+ int error;
+ struct nameidata nd;
- if (suser()) {
- if (savacctp) {
- acctp = savacctp;
- savacctp = NULL;
+ if (error = suser(p->p_ucred, &p->p_acflag))
+ return (error);
+ if (savacctp) {
+ acctp = savacctp;
+ savacctp = NULL;
+ }
+ if (uap->fname == NULL) {
+ if (vp = acctp) {
+ acctp = NULL;
+ error = vn_close(vp, FWRITE, p->p_ucred, p);
+ untimeout(acctwatch, NULL);
}
- if (uap->fname==NULL) {
- if (ip = acctp) {
- irele(ip);
- acctp = NULL;
- }
+ return (error);
+ }
+ NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p);
+ if (error = vn_open(&nd, FWRITE, 0644))
+ return (error);
+ vp = nd.ni_vp;
+ VOP_UNLOCK(vp);
+ if (vp->v_type != VREG) {
+ (void) vn_close(vp, FWRITE, p->p_ucred, p);
+ return (EACCES);
+ }
+ oacctp = acctp;
+ acctp = vp;
+ if (oacctp)
+ error = vn_close(oacctp, FWRITE, p->p_ucred, p);
+ acctwatch(NULL);
+ return (error);
+}
+
+/*
+ * Periodically check the file system to see if accounting
+ * should be turned on or off. Beware the case where the vnode
+ * has been vgone()'d out from underneath us, e.g. when the file
+ * system containing the accounting file has been forcibly unmounted.
+ */
+/* ARGSUSED */
+void
+acctwatch(a)
+ void *a;
+{
+ struct statfs sb;
+
+ if (savacctp) {
+ if (savacctp->v_type == VBAD) {
+ (void) vn_close(savacctp, FWRITE, NOCRED, NULL);
+ savacctp = NULL;
return;
}
- ndp->ni_nameiop = LOOKUP | FOLLOW;
- ndp->ni_segflg = UIO_USERSPACE;
- ndp->ni_dirp = uap->fname;
- ip = namei(ndp);
- if(ip == NULL)
+ (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
+ if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
+ acctp = savacctp;
+ savacctp = NULL;
+ log(LOG_NOTICE, "Accounting resumed\n");
+ }
+ } else {
+ if (acctp == NULL)
return;
- if((ip->i_mode & IFMT) != IFREG) {
- u.u_error = EACCES;
- iput(ip);
+ if (acctp->v_type == VBAD) {
+ (void) vn_close(acctp, FWRITE, NOCRED, NULL);
+ acctp = NULL;
return;
}
- if (acctp && (acctp->i_number != ip->i_number ||
- acctp->i_dev != ip->i_dev))
- irele(acctp);
- acctp = ip;
- iunlock(ip);
+ (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
+ if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
+ savacctp = acctp;
+ acctp = NULL;
+ log(LOG_NOTICE, "Accounting suspended\n");
+ }
}
+ timeout(acctwatch, NULL, acctchkfreq * hz);
}
-int acctsuspend = 2; /* stop accounting when < 2% free space left */
-int acctresume = 4; /* resume when free space risen to > 4% */
-
-struct acct acctbuf;
/*
- * On exit, write a record on the accounting file.
+ * This routine calculates an accounting record for a process and,
+ * if accounting is enabled, writes it to the accounting file.
*/
-acct()
+acct_process(p)
+ register struct proc *p;
{
- register int i;
- register struct inode *ip;
- register struct fs *fs;
- off_t siz;
+ register struct rusage *ru;
+ struct vnode *vp;
+ struct timeval t, ut, st;
+ int error, i, s;
+ struct acct acctbuf;
register struct acct *ap = &acctbuf;
- if (savacctp) {
- fs = savacctp->i_fs;
- if (freespace(fs, fs->fs_minfree + acctresume) > 0) {
- acctp = savacctp;
- savacctp = NULL;
- printf("Accounting resumed\n");
- }
+ s = splclock();
+ if ((vp = acctp) == NULL) {
+ splx(s);
+ return (0);
}
- if ((ip = acctp) == NULL)
- return;
- fs = acctp->i_fs;
- if (freespace(fs, fs->fs_minfree + acctsuspend) <= 0) {
- savacctp = acctp;
+ if (vp->v_type == VBAD) {
+ (void) vn_close(vp, FWRITE, NOCRED, NULL);
acctp = NULL;
- printf("Accounting suspended\n");
- return;
+ splx(s);
+ return (0);
}
- ilock(ip);
- for (i = 0; i < sizeof (ap->ac_comm); i++)
- ap->ac_comm[i] = u.u_comm[i];
- ap->ac_utime = compress((long)u.u_ru.ru_utime.tv_sec);
- ap->ac_stime = compress((long)u.u_ru.ru_stime.tv_sec);
- ap->ac_etime = compress((long)time.tv_sec - u.u_start);
- ap->ac_btime = u.u_start;
- ap->ac_uid = u.u_ruid;
- ap->ac_gid = u.u_rgid;
- ap->ac_mem = 0;
- if (i = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec)
- ap->ac_mem =
- (u.u_ru.ru_ixrss + u.u_ru.ru_idrss + u.u_ru.ru_isrss) / i;
- ap->ac_io = compress((long)(u.u_ru.ru_inblock + u.u_ru.ru_oublock));
- if (u.u_ttyp)
- ap->ac_tty = u.u_ttyd;
+ bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm));
+ ru = &p->p_stats->p_ru;
+ calcru(p, &ut, &st, NULL);
+ t = time;
+ ap->ac_utime = compress(ut.tv_sec, ut.tv_usec);
+ ap->ac_stime = compress(st.tv_sec, st.tv_usec);
+ timevalsub(&t, &p->p_stats->p_start);
+ ap->ac_etime = compress(t.tv_sec, t.tv_usec);
+ ap->ac_btime = p->p_stats->p_start.tv_sec;
+ ap->ac_uid = p->p_cred->p_ruid;
+ ap->ac_gid = p->p_cred->p_rgid;
+ t = st;
+ timevaladd(&t, &ut);
+ if (i = t.tv_sec * hz + t.tv_usec / tick)
+ ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i;
+ else
+ ap->ac_mem = 0;
+ ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0);
+ if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp)
+ ap->ac_tty = p->p_session->s_ttyp->t_dev;
else
ap->ac_tty = NODEV;
- ap->ac_flag = u.u_acflag;
- siz = ip->i_size;
- u.u_error = 0; /* XXX */
- u.u_error =
- rdwri(UIO_WRITE, ip, (caddr_t)ap, sizeof (acctbuf), siz,
- 1, (int *)0);
- if (u.u_error)
- itrunc(ip, (u_long)siz);
- iunlock(ip);
+ ap->ac_flag = p->p_acflag;
+ VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
+ error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0,
+ UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0,
+ (struct proc *)0);
+ splx(s);
+ return (error);
}
/*
* Produce a pseudo-floating point representation
* with 3 bits base-8 exponent, 13 bits fraction.
*/
-compress(t)
+compress(t, ut)
register long t;
+ long ut;
{
register exp = 0, round = 0;
+ t = t * AHZ; /* compiler will convert only this format to a shift */
+ if (ut)
+ t += ut / (1000000 / AHZ);
while (t >= 8192) {
exp++;
round = t&04;