123365Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 339481Smckusick * All rights reserved. The Berkeley software License Agreement 439481Smckusick * specifies the terms and conditions for redistribution. 523365Smckusick * 6*48021Smckusick * @(#)kern_acct.c 7.16 (Berkeley) 04/15/91 723365Smckusick */ 812788Ssam 917088Sbloom #include "param.h" 1017088Sbloom #include "systm.h" 1147545Skarels #include "namei.h" 1247545Skarels #include "resourcevar.h" 1338931Skarels #include "proc.h" 1443379Smckusick #include "ioctl.h" 1543379Smckusick #include "termios.h" 1643379Smckusick #include "tty.h" 1737728Smckusick #include "vnode.h" 1837728Smckusick #include "mount.h" 1917088Sbloom #include "kernel.h" 2045055Smckusick #include "file.h" 2117088Sbloom #include "acct.h" 2237728Smckusick #include "syslog.h" 2312788Ssam 2412788Ssam /* 2537728Smckusick * Values associated with enabling and disabling accounting 2637728Smckusick */ 2737728Smckusick int acctsuspend = 2; /* stop accounting when < 2% free space left */ 2837728Smckusick int acctresume = 4; /* resume when free space risen to > 4% */ 2937728Smckusick struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 3037728Smckusick 3137728Smckusick /* 3212788Ssam * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 3312788Ssam */ 3437728Smckusick struct vnode *acctp; 3537728Smckusick struct vnode *savacctp; 3612788Ssam 3712788Ssam /* 3812788Ssam * Perform process accounting functions. 3912788Ssam */ 4043379Smckusick /* ARGSUSED */ 4143379Smckusick sysacct(p, uap, retval) 4243379Smckusick struct proc *p; 4343379Smckusick struct args { 4443379Smckusick char *fname; 4543379Smckusick } *uap; 4643379Smckusick int *retval; 4712788Ssam { 4837728Smckusick register struct vnode *vp; 4937728Smckusick extern int acctwatch(); 5037728Smckusick struct vnode *oacctp; 5143379Smckusick int error; 5247545Skarels struct nameidata nd; 5312788Ssam 5447545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 5544404Skarels return (error); 5637553Smckusick if (savacctp) { 5737553Smckusick acctp = savacctp; 5837553Smckusick savacctp = NULL; 5937553Smckusick } 6045055Smckusick if (uap->fname == NULL) { 6137728Smckusick if (vp = acctp) { 6237553Smckusick acctp = NULL; 6337728Smckusick vrele(vp); 6437728Smckusick untimeout(acctwatch, (caddr_t)&chk); 6512788Ssam } 6644404Skarels return (0); 6712788Ssam } 6847545Skarels nd.ni_segflg = UIO_USERSPACE; 6947545Skarels nd.ni_dirp = uap->fname; 7047545Skarels if (error = vn_open(&nd, p, FWRITE, 0644)) 7144404Skarels return (error); 7247545Skarels vp = nd.ni_vp; 7337728Smckusick if (vp->v_type != VREG) { 7437728Smckusick vrele(vp); 7544404Skarels return (EACCES); 7637553Smckusick } 7737728Smckusick oacctp = acctp; 7837728Smckusick acctp = vp; 7937728Smckusick if (oacctp) 8037728Smckusick vrele(oacctp); 8137728Smckusick acctwatch(&chk); 8244404Skarels return (0); 8312788Ssam } 8412788Ssam 8512788Ssam /* 8637728Smckusick * Periodically check the file system to see if accounting 8737728Smckusick * should be turned on or off. 8812788Ssam */ 8937728Smckusick acctwatch(resettime) 9037728Smckusick struct timeval *resettime; 9112788Ssam { 9237728Smckusick struct statfs sb; 9312788Ssam 9412788Ssam if (savacctp) { 95*48021Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); 9637728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 9712788Ssam acctp = savacctp; 9812788Ssam savacctp = NULL; 9937728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 10037728Smckusick return; 10112788Ssam } 10212788Ssam } 10337728Smckusick if (acctp == NULL) 10412788Ssam return; 105*48021Smckusick (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); 10637728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 10712788Ssam savacctp = acctp; 10812788Ssam acctp = NULL; 10937728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 11037728Smckusick } 11137728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 11237728Smckusick } 11337728Smckusick 11437728Smckusick /* 11537728Smckusick * On exit, write a record on the accounting file. 11637728Smckusick */ 11743379Smckusick acct(p) 11843379Smckusick register struct proc *p; 11937728Smckusick { 12037728Smckusick register struct rusage *ru; 12137728Smckusick struct vnode *vp; 12240803Smarc struct timeval t, ut, st; 12340803Smarc int i, s; 12437728Smckusick struct acct acctbuf; 12537728Smckusick register struct acct *ap = &acctbuf; 12637728Smckusick 12737728Smckusick if ((vp = acctp) == NULL) 12843379Smckusick return (0); 12940803Smarc bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); 13047545Skarels ru = &p->p_stats->p_ru; 13140803Smarc s = splclock(); 13240803Smarc ut = p->p_utime; 13340803Smarc st = p->p_stime; 13416715Ssam t = time; 13540803Smarc splx(s); 13640803Smarc ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); 13740803Smarc ap->ac_stime = compress(st.tv_sec, st.tv_usec); 13847545Skarels timevalsub(&t, &p->p_stats->p_start); 13916715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 14047545Skarels ap->ac_btime = p->p_stats->p_start.tv_sec; 14147545Skarels ap->ac_uid = p->p_cred->p_ruid; 14247545Skarels ap->ac_gid = p->p_cred->p_rgid; 14340803Smarc t = st; 14440803Smarc timevaladd(&t, &ut); 14516719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 14647545Skarels ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; 14716715Ssam else 14816715Ssam ap->ac_mem = 0; 14926277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 15042204Smarc if (p->p_flag&SCTTY && p->p_session->s_ttyp) 15140803Smarc ap->ac_tty = p->p_session->s_ttyp->t_dev; 15212788Ssam else 15312788Ssam ap->ac_tty = NODEV; 15447545Skarels ap->ac_flag = p->p_acflag; 155*48021Smckusick return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, 156*48021Smckusick UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, 157*48021Smckusick (struct proc *)0)); 15812788Ssam } 15912788Ssam 16012788Ssam /* 16112788Ssam * Produce a pseudo-floating point representation 16212788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 16312788Ssam */ 16416715Ssam compress(t, ut) 16512788Ssam register long t; 16616715Ssam long ut; 16712788Ssam { 16812788Ssam register exp = 0, round = 0; 16912788Ssam 17017501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 17116715Ssam if (ut) 17217501Skarels t += ut / (1000000 / AHZ); 17312788Ssam while (t >= 8192) { 17412788Ssam exp++; 17512788Ssam round = t&04; 17612788Ssam t >>= 3; 17712788Ssam } 17812788Ssam if (round) { 17912788Ssam t++; 18012788Ssam if (t >= 8192) { 18112788Ssam t >>= 3; 18212788Ssam exp++; 18312788Ssam } 18412788Ssam } 18512788Ssam return ((exp<<13) + t); 18612788Ssam } 187