123365Smckusick /* 237728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 337728Smckusick * All rights reserved. 423365Smckusick * 537728Smckusick * Redistribution and use in source and binary forms are permitted 637728Smckusick * provided that the above copyright notice and this paragraph are 737728Smckusick * duplicated in all such forms and that any documentation, 837728Smckusick * advertising materials, and other materials related to such 937728Smckusick * distribution and use acknowledge that the software was developed 1037728Smckusick * by the University of California, Berkeley. The name of the 1137728Smckusick * University may not be used to endorse or promote products derived 1237728Smckusick * from this software without specific prior written permission. 1337728Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437728Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537728Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637728Smckusick * 17*38931Skarels * @(#)kern_acct.c 7.6 (Berkeley) 09/03/89 1823365Smckusick */ 1912788Ssam 2017088Sbloom #include "param.h" 2117088Sbloom #include "systm.h" 22*38931Skarels #include "time.h" 23*38931Skarels #include "proc.h" 2417088Sbloom #include "user.h" 2537728Smckusick #include "vnode.h" 2637728Smckusick #include "mount.h" 2717088Sbloom #include "kernel.h" 2817088Sbloom #include "acct.h" 2917088Sbloom #include "uio.h" 3037728Smckusick #include "syslog.h" 3112788Ssam 3212788Ssam /* 3337728Smckusick * Values associated with enabling and disabling accounting 3437728Smckusick */ 3537728Smckusick int acctsuspend = 2; /* stop accounting when < 2% free space left */ 3637728Smckusick int acctresume = 4; /* resume when free space risen to > 4% */ 3737728Smckusick struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 3837728Smckusick 3937728Smckusick /* 4012788Ssam * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 4112788Ssam */ 4237728Smckusick struct vnode *acctp; 4337728Smckusick struct vnode *savacctp; 4412788Ssam 4512788Ssam /* 4612788Ssam * Perform process accounting functions. 4712788Ssam */ 4812788Ssam sysacct() 4912788Ssam { 5037728Smckusick register struct vnode *vp; 5112788Ssam register struct a { 5212788Ssam char *fname; 5312788Ssam } *uap = (struct a *)u.u_ap; 5416695Smckusick register struct nameidata *ndp = &u.u_nd; 5537728Smckusick extern int acctwatch(); 5637728Smckusick struct vnode *oacctp; 5712788Ssam 5837553Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 5937553Smckusick return; 6037553Smckusick if (savacctp) { 6137553Smckusick acctp = savacctp; 6237553Smckusick savacctp = NULL; 6337553Smckusick } 6437553Smckusick if (uap->fname==NULL) { 6537728Smckusick if (vp = acctp) { 6637553Smckusick acctp = NULL; 6737728Smckusick vrele(vp); 6837728Smckusick untimeout(acctwatch, (caddr_t)&chk); 6912788Ssam } 7037553Smckusick return; 7112788Ssam } 7237553Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 7337553Smckusick ndp->ni_segflg = UIO_USERSPACE; 7437553Smckusick ndp->ni_dirp = uap->fname; 7537728Smckusick if (u.u_error = namei(ndp)) 7637553Smckusick return; 7737728Smckusick vp = ndp->ni_vp; 7837728Smckusick if (vp->v_type != VREG) { 7937553Smckusick u.u_error = EACCES; 8037728Smckusick vrele(vp); 8137553Smckusick return; 8237553Smckusick } 8337728Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 8437553Smckusick u.u_error = EROFS; 8537728Smckusick vrele(vp); 8637553Smckusick return; 8737553Smckusick } 8837728Smckusick oacctp = acctp; 8937728Smckusick acctp = vp; 9037728Smckusick if (oacctp) 9137728Smckusick vrele(oacctp); 9237728Smckusick acctwatch(&chk); 9312788Ssam } 9412788Ssam 9512788Ssam /* 9637728Smckusick * Periodically check the file system to see if accounting 9737728Smckusick * should be turned on or off. 9812788Ssam */ 9937728Smckusick acctwatch(resettime) 10037728Smckusick struct timeval *resettime; 10112788Ssam { 10237728Smckusick struct statfs sb; 10312788Ssam 10412788Ssam if (savacctp) { 10537728Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb); 10637728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 10712788Ssam acctp = savacctp; 10812788Ssam savacctp = NULL; 10937728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 11037728Smckusick return; 11112788Ssam } 11212788Ssam } 11337728Smckusick if (acctp == NULL) 11412788Ssam return; 11537728Smckusick (void)VFS_STATFS(acctp->v_mount, &sb); 11637728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 11712788Ssam savacctp = acctp; 11812788Ssam acctp = NULL; 11937728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 12037728Smckusick } 12137728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 12237728Smckusick } 12337728Smckusick 12437728Smckusick /* 12537728Smckusick * On exit, write a record on the accounting file. 12637728Smckusick */ 12737728Smckusick acct() 12837728Smckusick { 12937728Smckusick register struct rusage *ru; 13037728Smckusick struct vnode *vp; 13137728Smckusick struct timeval t; 13237728Smckusick int i; 13337728Smckusick struct acct acctbuf; 13437728Smckusick register struct acct *ap = &acctbuf; 13537728Smckusick 13637728Smckusick if ((vp = acctp) == NULL) 13712788Ssam return; 13835809Smarc bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm)); 13916715Ssam ru = &u.u_ru; 14016715Ssam ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 14116715Ssam ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 14216715Ssam t = time; 14316715Ssam timevalsub(&t, &u.u_start); 14416715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 14516715Ssam ap->ac_btime = u.u_start.tv_sec; 146*38931Skarels ap->ac_uid = u.u_procp->p_ruid; 147*38931Skarels ap->ac_gid = u.u_procp->p_rgid; 14816715Ssam t = ru->ru_stime; 14916715Ssam timevaladd(&t, &ru->ru_utime); 15016719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 15116715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 15216715Ssam else 15316715Ssam ap->ac_mem = 0; 15416715Ssam ap->ac_mem >>= CLSIZELOG2; 15526277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 15612788Ssam if (u.u_ttyp) 15712788Ssam ap->ac_tty = u.u_ttyd; 15812788Ssam else 15912788Ssam ap->ac_tty = NODEV; 16012788Ssam ap->ac_flag = u.u_acflag; 16137728Smckusick u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 16237728Smckusick (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0); 16312788Ssam } 16412788Ssam 16512788Ssam /* 16612788Ssam * Produce a pseudo-floating point representation 16712788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 16812788Ssam */ 16916715Ssam compress(t, ut) 17012788Ssam register long t; 17116715Ssam long ut; 17212788Ssam { 17312788Ssam register exp = 0, round = 0; 17412788Ssam 17517501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 17616715Ssam if (ut) 17717501Skarels t += ut / (1000000 / AHZ); 17812788Ssam while (t >= 8192) { 17912788Ssam exp++; 18012788Ssam round = t&04; 18112788Ssam t >>= 3; 18212788Ssam } 18312788Ssam if (round) { 18412788Ssam t++; 18512788Ssam if (t >= 8192) { 18612788Ssam t >>= 3; 18712788Ssam exp++; 18812788Ssam } 18912788Ssam } 19012788Ssam return ((exp<<13) + t); 19112788Ssam } 192