123365Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3*39481Smckusick * All rights reserved. The Berkeley software License Agreement 4*39481Smckusick * specifies the terms and conditions for redistribution. 523365Smckusick * 6*39481Smckusick * @(#)kern_acct.c 7.7 (Berkeley) 11/02/89 723365Smckusick */ 812788Ssam 917088Sbloom #include "param.h" 1017088Sbloom #include "systm.h" 1138931Skarels #include "time.h" 1238931Skarels #include "proc.h" 1317088Sbloom #include "user.h" 1437728Smckusick #include "vnode.h" 1537728Smckusick #include "mount.h" 1617088Sbloom #include "kernel.h" 1717088Sbloom #include "acct.h" 1817088Sbloom #include "uio.h" 1937728Smckusick #include "syslog.h" 2012788Ssam 2112788Ssam /* 2237728Smckusick * Values associated with enabling and disabling accounting 2337728Smckusick */ 2437728Smckusick int acctsuspend = 2; /* stop accounting when < 2% free space left */ 2537728Smckusick int acctresume = 4; /* resume when free space risen to > 4% */ 2637728Smckusick struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 2737728Smckusick 2837728Smckusick /* 2912788Ssam * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 3012788Ssam */ 3137728Smckusick struct vnode *acctp; 3237728Smckusick struct vnode *savacctp; 3312788Ssam 3412788Ssam /* 3512788Ssam * Perform process accounting functions. 3612788Ssam */ 3712788Ssam sysacct() 3812788Ssam { 3937728Smckusick register struct vnode *vp; 4012788Ssam register struct a { 4112788Ssam char *fname; 4212788Ssam } *uap = (struct a *)u.u_ap; 4316695Smckusick register struct nameidata *ndp = &u.u_nd; 4437728Smckusick extern int acctwatch(); 4537728Smckusick struct vnode *oacctp; 4612788Ssam 4737553Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 4837553Smckusick return; 4937553Smckusick if (savacctp) { 5037553Smckusick acctp = savacctp; 5137553Smckusick savacctp = NULL; 5237553Smckusick } 5337553Smckusick if (uap->fname==NULL) { 5437728Smckusick if (vp = acctp) { 5537553Smckusick acctp = NULL; 5637728Smckusick vrele(vp); 5737728Smckusick untimeout(acctwatch, (caddr_t)&chk); 5812788Ssam } 5937553Smckusick return; 6012788Ssam } 6137553Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 6237553Smckusick ndp->ni_segflg = UIO_USERSPACE; 6337553Smckusick ndp->ni_dirp = uap->fname; 6437728Smckusick if (u.u_error = namei(ndp)) 6537553Smckusick return; 6637728Smckusick vp = ndp->ni_vp; 6737728Smckusick if (vp->v_type != VREG) { 6837553Smckusick u.u_error = EACCES; 6937728Smckusick vrele(vp); 7037553Smckusick return; 7137553Smckusick } 7237728Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 7337553Smckusick u.u_error = EROFS; 7437728Smckusick vrele(vp); 7537553Smckusick return; 7637553Smckusick } 7737728Smckusick oacctp = acctp; 7837728Smckusick acctp = vp; 7937728Smckusick if (oacctp) 8037728Smckusick vrele(oacctp); 8137728Smckusick acctwatch(&chk); 8212788Ssam } 8312788Ssam 8412788Ssam /* 8537728Smckusick * Periodically check the file system to see if accounting 8637728Smckusick * should be turned on or off. 8712788Ssam */ 8837728Smckusick acctwatch(resettime) 8937728Smckusick struct timeval *resettime; 9012788Ssam { 9137728Smckusick struct statfs sb; 9212788Ssam 9312788Ssam if (savacctp) { 9437728Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb); 9537728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 9612788Ssam acctp = savacctp; 9712788Ssam savacctp = NULL; 9837728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 9937728Smckusick return; 10012788Ssam } 10112788Ssam } 10237728Smckusick if (acctp == NULL) 10312788Ssam return; 10437728Smckusick (void)VFS_STATFS(acctp->v_mount, &sb); 10537728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 10612788Ssam savacctp = acctp; 10712788Ssam acctp = NULL; 10837728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 10937728Smckusick } 11037728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 11137728Smckusick } 11237728Smckusick 11337728Smckusick /* 11437728Smckusick * On exit, write a record on the accounting file. 11537728Smckusick */ 11637728Smckusick acct() 11737728Smckusick { 11837728Smckusick register struct rusage *ru; 11937728Smckusick struct vnode *vp; 12037728Smckusick struct timeval t; 12137728Smckusick int i; 12237728Smckusick struct acct acctbuf; 12337728Smckusick register struct acct *ap = &acctbuf; 12437728Smckusick 12537728Smckusick if ((vp = acctp) == NULL) 12612788Ssam return; 12735809Smarc bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm)); 12816715Ssam ru = &u.u_ru; 12916715Ssam ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 13016715Ssam ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 13116715Ssam t = time; 13216715Ssam timevalsub(&t, &u.u_start); 13316715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 13416715Ssam ap->ac_btime = u.u_start.tv_sec; 13538931Skarels ap->ac_uid = u.u_procp->p_ruid; 13638931Skarels ap->ac_gid = u.u_procp->p_rgid; 13716715Ssam t = ru->ru_stime; 13816715Ssam timevaladd(&t, &ru->ru_utime); 13916719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 14016715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 14116715Ssam else 14216715Ssam ap->ac_mem = 0; 14316715Ssam ap->ac_mem >>= CLSIZELOG2; 14426277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 14512788Ssam if (u.u_ttyp) 14612788Ssam ap->ac_tty = u.u_ttyd; 14712788Ssam else 14812788Ssam ap->ac_tty = NODEV; 14912788Ssam ap->ac_flag = u.u_acflag; 15037728Smckusick u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 15137728Smckusick (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0); 15212788Ssam } 15312788Ssam 15412788Ssam /* 15512788Ssam * Produce a pseudo-floating point representation 15612788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 15712788Ssam */ 15816715Ssam compress(t, ut) 15912788Ssam register long t; 16016715Ssam long ut; 16112788Ssam { 16212788Ssam register exp = 0, round = 0; 16312788Ssam 16417501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 16516715Ssam if (ut) 16617501Skarels t += ut / (1000000 / AHZ); 16712788Ssam while (t >= 8192) { 16812788Ssam exp++; 16912788Ssam round = t&04; 17012788Ssam t >>= 3; 17112788Ssam } 17212788Ssam if (round) { 17312788Ssam t++; 17412788Ssam if (t >= 8192) { 17512788Ssam t >>= 3; 17612788Ssam exp++; 17712788Ssam } 17812788Ssam } 17912788Ssam return ((exp<<13) + t); 18012788Ssam } 181