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*42204Smarc * @(#)kern_acct.c 7.10 (Berkeley) 05/17/90 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" 2040803Smarc #include "ioctl.h" 2140803Smarc #include "termios.h" 2240803Smarc #include "tty.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 */ 4012788Ssam sysacct() 4112788Ssam { 4237728Smckusick register struct vnode *vp; 4312788Ssam register struct a { 4412788Ssam char *fname; 4512788Ssam } *uap = (struct a *)u.u_ap; 4616695Smckusick register struct nameidata *ndp = &u.u_nd; 4737728Smckusick extern int acctwatch(); 4837728Smckusick struct vnode *oacctp; 4912788Ssam 5037553Smckusick if (u.u_error = suser(u.u_cred, &u.u_acflag)) 5137553Smckusick return; 5237553Smckusick if (savacctp) { 5337553Smckusick acctp = savacctp; 5437553Smckusick savacctp = NULL; 5537553Smckusick } 5637553Smckusick if (uap->fname==NULL) { 5737728Smckusick if (vp = acctp) { 5837553Smckusick acctp = NULL; 5937728Smckusick vrele(vp); 6037728Smckusick untimeout(acctwatch, (caddr_t)&chk); 6112788Ssam } 6237553Smckusick return; 6312788Ssam } 6437553Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 6537553Smckusick ndp->ni_segflg = UIO_USERSPACE; 6637553Smckusick ndp->ni_dirp = uap->fname; 6737728Smckusick if (u.u_error = namei(ndp)) 6837553Smckusick return; 6937728Smckusick vp = ndp->ni_vp; 7037728Smckusick if (vp->v_type != VREG) { 7137553Smckusick u.u_error = EACCES; 7237728Smckusick vrele(vp); 7337553Smckusick return; 7437553Smckusick } 7541400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 7637553Smckusick u.u_error = EROFS; 7737728Smckusick vrele(vp); 7837553Smckusick return; 7937553Smckusick } 8037728Smckusick oacctp = acctp; 8137728Smckusick acctp = vp; 8237728Smckusick if (oacctp) 8337728Smckusick vrele(oacctp); 8437728Smckusick acctwatch(&chk); 8512788Ssam } 8612788Ssam 8712788Ssam /* 8837728Smckusick * Periodically check the file system to see if accounting 8937728Smckusick * should be turned on or off. 9012788Ssam */ 9137728Smckusick acctwatch(resettime) 9237728Smckusick struct timeval *resettime; 9312788Ssam { 9437728Smckusick struct statfs sb; 9512788Ssam 9612788Ssam if (savacctp) { 9737728Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb); 9837728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 9912788Ssam acctp = savacctp; 10012788Ssam savacctp = NULL; 10137728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 10237728Smckusick return; 10312788Ssam } 10412788Ssam } 10537728Smckusick if (acctp == NULL) 10612788Ssam return; 10737728Smckusick (void)VFS_STATFS(acctp->v_mount, &sb); 10837728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 10912788Ssam savacctp = acctp; 11012788Ssam acctp = NULL; 11137728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 11237728Smckusick } 11337728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 11437728Smckusick } 11537728Smckusick 11637728Smckusick /* 11737728Smckusick * On exit, write a record on the accounting file. 11837728Smckusick */ 11937728Smckusick acct() 12037728Smckusick { 12137728Smckusick register struct rusage *ru; 12237728Smckusick struct vnode *vp; 12340803Smarc struct timeval t, ut, st; 12440803Smarc int i, s; 12537728Smckusick struct acct acctbuf; 12637728Smckusick register struct acct *ap = &acctbuf; 12740803Smarc register struct proc *p = u.u_procp; 12837728Smckusick 12937728Smckusick if ((vp = acctp) == NULL) 13012788Ssam return; 13140803Smarc bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); 13216715Ssam ru = &u.u_ru; 13340803Smarc s = splclock(); 13440803Smarc ut = p->p_utime; 13540803Smarc st = p->p_stime; 13616715Ssam t = time; 13740803Smarc splx(s); 13840803Smarc ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); 13940803Smarc ap->ac_stime = compress(st.tv_sec, st.tv_usec); 14016715Ssam timevalsub(&t, &u.u_start); 14116715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 14216715Ssam ap->ac_btime = u.u_start.tv_sec; 14338931Skarels ap->ac_uid = u.u_procp->p_ruid; 14438931Skarels ap->ac_gid = u.u_procp->p_rgid; 14540803Smarc t = st; 14640803Smarc timevaladd(&t, &ut); 14716719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 14816715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 14916715Ssam else 15016715Ssam ap->ac_mem = 0; 15116715Ssam ap->ac_mem >>= CLSIZELOG2; 15226277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 153*42204Smarc if (p->p_flag&SCTTY && p->p_session->s_ttyp) 15440803Smarc ap->ac_tty = p->p_session->s_ttyp->t_dev; 15512788Ssam else 15612788Ssam ap->ac_tty = NODEV; 15712788Ssam ap->ac_flag = u.u_acflag; 15837728Smckusick u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 15937728Smckusick (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0); 16012788Ssam } 16112788Ssam 16212788Ssam /* 16312788Ssam * Produce a pseudo-floating point representation 16412788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 16512788Ssam */ 16616715Ssam compress(t, ut) 16712788Ssam register long t; 16816715Ssam long ut; 16912788Ssam { 17012788Ssam register exp = 0, round = 0; 17112788Ssam 17217501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 17316715Ssam if (ut) 17417501Skarels t += ut / (1000000 / AHZ); 17512788Ssam while (t >= 8192) { 17612788Ssam exp++; 17712788Ssam round = t&04; 17812788Ssam t >>= 3; 17912788Ssam } 18012788Ssam if (round) { 18112788Ssam t++; 18212788Ssam if (t >= 8192) { 18312788Ssam t >>= 3; 18412788Ssam exp++; 18512788Ssam } 18612788Ssam } 18712788Ssam return ((exp<<13) + t); 18812788Ssam } 189