123365Smckusick /* 2*37728Smckusick * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3*37728Smckusick * All rights reserved. 423365Smckusick * 5*37728Smckusick * Redistribution and use in source and binary forms are permitted 6*37728Smckusick * provided that the above copyright notice and this paragraph are 7*37728Smckusick * duplicated in all such forms and that any documentation, 8*37728Smckusick * advertising materials, and other materials related to such 9*37728Smckusick * distribution and use acknowledge that the software was developed 10*37728Smckusick * by the University of California, Berkeley. The name of the 11*37728Smckusick * University may not be used to endorse or promote products derived 12*37728Smckusick * from this software without specific prior written permission. 13*37728Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*37728Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*37728Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*37728Smckusick * 17*37728Smckusick * @(#)kern_acct.c 7.5 (Berkeley) 05/09/89 1823365Smckusick */ 1912788Ssam 2017088Sbloom #include "param.h" 2117088Sbloom #include "systm.h" 2217088Sbloom #include "user.h" 23*37728Smckusick #include "vnode.h" 24*37728Smckusick #include "mount.h" 2517088Sbloom #include "kernel.h" 2617088Sbloom #include "acct.h" 2717088Sbloom #include "uio.h" 28*37728Smckusick #include "syslog.h" 2912788Ssam 3012788Ssam /* 31*37728Smckusick * Values associated with enabling and disabling accounting 32*37728Smckusick */ 33*37728Smckusick int acctsuspend = 2; /* stop accounting when < 2% free space left */ 34*37728Smckusick int acctresume = 4; /* resume when free space risen to > 4% */ 35*37728Smckusick struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 36*37728Smckusick 37*37728Smckusick /* 3812788Ssam * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 3912788Ssam */ 40*37728Smckusick struct vnode *acctp; 41*37728Smckusick struct vnode *savacctp; 4212788Ssam 4312788Ssam /* 4412788Ssam * Perform process accounting functions. 4512788Ssam */ 4612788Ssam sysacct() 4712788Ssam { 48*37728Smckusick register struct vnode *vp; 4912788Ssam register struct a { 5012788Ssam char *fname; 5112788Ssam } *uap = (struct a *)u.u_ap; 5216695Smckusick register struct nameidata *ndp = &u.u_nd; 53*37728Smckusick extern int acctwatch(); 54*37728Smckusick struct vnode *oacctp; 5512788Ssam 5637553Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 5737553Smckusick return; 5837553Smckusick if (savacctp) { 5937553Smckusick acctp = savacctp; 6037553Smckusick savacctp = NULL; 6137553Smckusick } 6237553Smckusick if (uap->fname==NULL) { 63*37728Smckusick if (vp = acctp) { 6437553Smckusick acctp = NULL; 65*37728Smckusick vrele(vp); 66*37728Smckusick untimeout(acctwatch, (caddr_t)&chk); 6712788Ssam } 6837553Smckusick return; 6912788Ssam } 7037553Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 7137553Smckusick ndp->ni_segflg = UIO_USERSPACE; 7237553Smckusick ndp->ni_dirp = uap->fname; 73*37728Smckusick if (u.u_error = namei(ndp)) 7437553Smckusick return; 75*37728Smckusick vp = ndp->ni_vp; 76*37728Smckusick if (vp->v_type != VREG) { 7737553Smckusick u.u_error = EACCES; 78*37728Smckusick vrele(vp); 7937553Smckusick return; 8037553Smckusick } 81*37728Smckusick if (vp->v_mount->m_flag & M_RDONLY) { 8237553Smckusick u.u_error = EROFS; 83*37728Smckusick vrele(vp); 8437553Smckusick return; 8537553Smckusick } 86*37728Smckusick oacctp = acctp; 87*37728Smckusick acctp = vp; 88*37728Smckusick if (oacctp) 89*37728Smckusick vrele(oacctp); 90*37728Smckusick acctwatch(&chk); 9112788Ssam } 9212788Ssam 9312788Ssam /* 94*37728Smckusick * Periodically check the file system to see if accounting 95*37728Smckusick * should be turned on or off. 9612788Ssam */ 97*37728Smckusick acctwatch(resettime) 98*37728Smckusick struct timeval *resettime; 9912788Ssam { 100*37728Smckusick struct statfs sb; 10112788Ssam 10212788Ssam if (savacctp) { 103*37728Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb); 104*37728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 10512788Ssam acctp = savacctp; 10612788Ssam savacctp = NULL; 107*37728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 108*37728Smckusick return; 10912788Ssam } 11012788Ssam } 111*37728Smckusick if (acctp == NULL) 11212788Ssam return; 113*37728Smckusick (void)VFS_STATFS(acctp->v_mount, &sb); 114*37728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 11512788Ssam savacctp = acctp; 11612788Ssam acctp = NULL; 117*37728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 118*37728Smckusick } 119*37728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 120*37728Smckusick } 121*37728Smckusick 122*37728Smckusick /* 123*37728Smckusick * On exit, write a record on the accounting file. 124*37728Smckusick */ 125*37728Smckusick acct() 126*37728Smckusick { 127*37728Smckusick register struct rusage *ru; 128*37728Smckusick struct vnode *vp; 129*37728Smckusick struct timeval t; 130*37728Smckusick int i; 131*37728Smckusick struct acct acctbuf; 132*37728Smckusick register struct acct *ap = &acctbuf; 133*37728Smckusick 134*37728Smckusick if ((vp = acctp) == NULL) 13512788Ssam return; 13635809Smarc bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm)); 13716715Ssam ru = &u.u_ru; 13816715Ssam ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 13916715Ssam ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 14016715Ssam t = time; 14116715Ssam timevalsub(&t, &u.u_start); 14216715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 14316715Ssam ap->ac_btime = u.u_start.tv_sec; 14412788Ssam ap->ac_uid = u.u_ruid; 14512788Ssam ap->ac_gid = u.u_rgid; 14616715Ssam t = ru->ru_stime; 14716715Ssam timevaladd(&t, &ru->ru_utime); 14816719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 14916715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 15016715Ssam else 15116715Ssam ap->ac_mem = 0; 15216715Ssam ap->ac_mem >>= CLSIZELOG2; 15326277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 15412788Ssam if (u.u_ttyp) 15512788Ssam ap->ac_tty = u.u_ttyd; 15612788Ssam else 15712788Ssam ap->ac_tty = NODEV; 15812788Ssam ap->ac_flag = u.u_acflag; 159*37728Smckusick u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 160*37728Smckusick (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0); 16112788Ssam } 16212788Ssam 16312788Ssam /* 16412788Ssam * Produce a pseudo-floating point representation 16512788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 16612788Ssam */ 16716715Ssam compress(t, ut) 16812788Ssam register long t; 16916715Ssam long ut; 17012788Ssam { 17112788Ssam register exp = 0, round = 0; 17212788Ssam 17317501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 17416715Ssam if (ut) 17517501Skarels t += ut / (1000000 / AHZ); 17612788Ssam while (t >= 8192) { 17712788Ssam exp++; 17812788Ssam round = t&04; 17912788Ssam t >>= 3; 18012788Ssam } 18112788Ssam if (round) { 18212788Ssam t++; 18312788Ssam if (t >= 8192) { 18412788Ssam t >>= 3; 18512788Ssam exp++; 18612788Ssam } 18712788Ssam } 18812788Ssam return ((exp<<13) + t); 18912788Ssam } 190