149587Sbostic /*- 249587Sbostic * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. 349587Sbostic * All rights reserved. 423365Smckusick * 549587Sbostic * %sccs.include.proprietary.c% 649587Sbostic * 7*49671Smckusick * @(#)kern_acct.c 7.18 (Berkeley) 05/11/91 823365Smckusick */ 912788Ssam 1017088Sbloom #include "param.h" 1117088Sbloom #include "systm.h" 1247545Skarels #include "namei.h" 1347545Skarels #include "resourcevar.h" 1438931Skarels #include "proc.h" 1543379Smckusick #include "ioctl.h" 1643379Smckusick #include "termios.h" 1743379Smckusick #include "tty.h" 1837728Smckusick #include "vnode.h" 1937728Smckusick #include "mount.h" 2017088Sbloom #include "kernel.h" 2145055Smckusick #include "file.h" 2217088Sbloom #include "acct.h" 2337728Smckusick #include "syslog.h" 2412788Ssam 2512788Ssam /* 2637728Smckusick * Values associated with enabling and disabling accounting 2737728Smckusick */ 2837728Smckusick int acctsuspend = 2; /* stop accounting when < 2% free space left */ 2937728Smckusick int acctresume = 4; /* resume when free space risen to > 4% */ 3037728Smckusick struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 3137728Smckusick 3237728Smckusick /* 3312788Ssam * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 3412788Ssam */ 3537728Smckusick struct vnode *acctp; 3637728Smckusick struct vnode *savacctp; 3712788Ssam 3812788Ssam /* 39*49671Smckusick * Enable or disable process accounting. 40*49671Smckusick * 41*49671Smckusick * If a non-null filename is given, that file is used to store accounting 42*49671Smckusick * records on process exit. If a null filename is given process accounting 43*49671Smckusick * is suspended. If accounting is enabled, the system checks the amount 44*49671Smckusick * of freespace on the filesystem at timeval intervals. If the amount of 45*49671Smckusick * freespace is below acctsuspend percent, accounting is suspended. If 46*49671Smckusick * accounting has been suspended, and freespace rises above acctresume, 47*49671Smckusick * accounting is resumed. 4812788Ssam */ 4943379Smckusick /* ARGSUSED */ 5043379Smckusick sysacct(p, uap, retval) 5143379Smckusick struct proc *p; 5243379Smckusick struct args { 5343379Smckusick char *fname; 5443379Smckusick } *uap; 5543379Smckusick int *retval; 5612788Ssam { 5737728Smckusick register struct vnode *vp; 5837728Smckusick extern int acctwatch(); 5937728Smckusick struct vnode *oacctp; 6043379Smckusick int error; 6147545Skarels struct nameidata nd; 6212788Ssam 6347545Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 6444404Skarels return (error); 6537553Smckusick if (savacctp) { 6637553Smckusick acctp = savacctp; 6737553Smckusick savacctp = NULL; 6837553Smckusick } 6945055Smckusick if (uap->fname == NULL) { 7037728Smckusick if (vp = acctp) { 7137553Smckusick acctp = NULL; 7237728Smckusick vrele(vp); 7337728Smckusick untimeout(acctwatch, (caddr_t)&chk); 7412788Ssam } 7544404Skarels return (0); 7612788Ssam } 7747545Skarels nd.ni_segflg = UIO_USERSPACE; 7847545Skarels nd.ni_dirp = uap->fname; 7947545Skarels if (error = vn_open(&nd, p, FWRITE, 0644)) 8044404Skarels return (error); 8147545Skarels vp = nd.ni_vp; 8237728Smckusick if (vp->v_type != VREG) { 8337728Smckusick vrele(vp); 8444404Skarels return (EACCES); 8537553Smckusick } 8637728Smckusick oacctp = acctp; 8737728Smckusick acctp = vp; 8837728Smckusick if (oacctp) 8937728Smckusick vrele(oacctp); 9037728Smckusick acctwatch(&chk); 9144404Skarels return (0); 9212788Ssam } 9312788Ssam 9412788Ssam /* 9537728Smckusick * Periodically check the file system to see if accounting 9637728Smckusick * should be turned on or off. 9712788Ssam */ 9837728Smckusick acctwatch(resettime) 9937728Smckusick struct timeval *resettime; 10012788Ssam { 10137728Smckusick struct statfs sb; 10212788Ssam 10312788Ssam if (savacctp) { 10448021Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); 10537728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 10612788Ssam acctp = savacctp; 10712788Ssam savacctp = NULL; 10837728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 10937728Smckusick return; 11012788Ssam } 11112788Ssam } 11237728Smckusick if (acctp == NULL) 11312788Ssam return; 11448021Smckusick (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); 11537728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 11612788Ssam savacctp = acctp; 11712788Ssam acctp = NULL; 11837728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 11937728Smckusick } 12037728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 12137728Smckusick } 12237728Smckusick 12337728Smckusick /* 124*49671Smckusick * This routine calculates an accounting record for a process and, 125*49671Smckusick * if accounting is enabled, writes it to the accounting file. 12637728Smckusick */ 12743379Smckusick acct(p) 12843379Smckusick register struct proc *p; 12937728Smckusick { 13037728Smckusick register struct rusage *ru; 13137728Smckusick struct vnode *vp; 13240803Smarc struct timeval t, ut, st; 13340803Smarc int i, s; 13437728Smckusick struct acct acctbuf; 13537728Smckusick register struct acct *ap = &acctbuf; 13637728Smckusick 13737728Smckusick if ((vp = acctp) == NULL) 13843379Smckusick return (0); 13940803Smarc bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); 14047545Skarels ru = &p->p_stats->p_ru; 14140803Smarc s = splclock(); 14240803Smarc ut = p->p_utime; 14340803Smarc st = p->p_stime; 14416715Ssam t = time; 14540803Smarc splx(s); 14640803Smarc ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); 14740803Smarc ap->ac_stime = compress(st.tv_sec, st.tv_usec); 14847545Skarels timevalsub(&t, &p->p_stats->p_start); 14916715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 15047545Skarels ap->ac_btime = p->p_stats->p_start.tv_sec; 15147545Skarels ap->ac_uid = p->p_cred->p_ruid; 15247545Skarels ap->ac_gid = p->p_cred->p_rgid; 15340803Smarc t = st; 15440803Smarc timevaladd(&t, &ut); 15516719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 15647545Skarels ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; 15716715Ssam else 15816715Ssam ap->ac_mem = 0; 15926277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 16042204Smarc if (p->p_flag&SCTTY && p->p_session->s_ttyp) 16140803Smarc ap->ac_tty = p->p_session->s_ttyp->t_dev; 16212788Ssam else 16312788Ssam ap->ac_tty = NODEV; 16447545Skarels ap->ac_flag = p->p_acflag; 16548021Smckusick return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, 16648021Smckusick UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, 16748021Smckusick (struct proc *)0)); 16812788Ssam } 16912788Ssam 17012788Ssam /* 17112788Ssam * Produce a pseudo-floating point representation 17212788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 17312788Ssam */ 17416715Ssam compress(t, ut) 17512788Ssam register long t; 17616715Ssam long ut; 17712788Ssam { 17812788Ssam register exp = 0, round = 0; 17912788Ssam 18017501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 18116715Ssam if (ut) 18217501Skarels t += ut / (1000000 / AHZ); 18312788Ssam while (t >= 8192) { 18412788Ssam exp++; 18512788Ssam round = t&04; 18612788Ssam t >>= 3; 18712788Ssam } 18812788Ssam if (round) { 18912788Ssam t++; 19012788Ssam if (t >= 8192) { 19112788Ssam t >>= 3; 19212788Ssam exp++; 19312788Ssam } 19412788Ssam } 19512788Ssam return ((exp<<13) + t); 19612788Ssam } 197