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*43379Smckusick * @(#)kern_acct.c 7.11 (Berkeley) 06/21/90 723365Smckusick */ 812788Ssam 917088Sbloom #include "param.h" 1017088Sbloom #include "systm.h" 1138931Skarels #include "time.h" 1238931Skarels #include "proc.h" 13*43379Smckusick #include "ioctl.h" 14*43379Smckusick #include "termios.h" 15*43379Smckusick #include "tty.h" 16*43379Smckusick #undef RETURN 17*43379Smckusick #include "syscontext.h" 1837728Smckusick #include "vnode.h" 1937728Smckusick #include "mount.h" 2017088Sbloom #include "kernel.h" 2117088Sbloom #include "acct.h" 2217088Sbloom #include "uio.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 /* 3912788Ssam * Perform process accounting functions. 4012788Ssam */ 41*43379Smckusick /* ARGSUSED */ 42*43379Smckusick sysacct(p, uap, retval) 43*43379Smckusick struct proc *p; 44*43379Smckusick struct args { 45*43379Smckusick char *fname; 46*43379Smckusick } *uap; 47*43379Smckusick int *retval; 4812788Ssam { 4937728Smckusick register struct vnode *vp; 5016695Smckusick register struct nameidata *ndp = &u.u_nd; 5137728Smckusick extern int acctwatch(); 5237728Smckusick struct vnode *oacctp; 53*43379Smckusick int error; 5412788Ssam 55*43379Smckusick if (error = suser(u.u_cred, &u.u_acflag)) 56*43379Smckusick RETURN (error); 5737553Smckusick if (savacctp) { 5837553Smckusick acctp = savacctp; 5937553Smckusick savacctp = NULL; 6037553Smckusick } 6137553Smckusick if (uap->fname==NULL) { 6237728Smckusick if (vp = acctp) { 6337553Smckusick acctp = NULL; 6437728Smckusick vrele(vp); 6537728Smckusick untimeout(acctwatch, (caddr_t)&chk); 6612788Ssam } 67*43379Smckusick RETURN (0); 6812788Ssam } 6937553Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 7037553Smckusick ndp->ni_segflg = UIO_USERSPACE; 7137553Smckusick ndp->ni_dirp = uap->fname; 72*43379Smckusick if (error = namei(ndp)) 73*43379Smckusick RETURN (error); 7437728Smckusick vp = ndp->ni_vp; 7537728Smckusick if (vp->v_type != VREG) { 7637728Smckusick vrele(vp); 77*43379Smckusick RETURN (EACCES); 7837553Smckusick } 7941400Smckusick if (vp->v_mount->mnt_flag & MNT_RDONLY) { 8037728Smckusick vrele(vp); 81*43379Smckusick RETURN (EROFS); 8237553Smckusick } 8337728Smckusick oacctp = acctp; 8437728Smckusick acctp = vp; 8537728Smckusick if (oacctp) 8637728Smckusick vrele(oacctp); 8737728Smckusick acctwatch(&chk); 88*43379Smckusick RETURN (0); 8912788Ssam } 9012788Ssam 9112788Ssam /* 9237728Smckusick * Periodically check the file system to see if accounting 9337728Smckusick * should be turned on or off. 9412788Ssam */ 9537728Smckusick acctwatch(resettime) 9637728Smckusick struct timeval *resettime; 9712788Ssam { 9837728Smckusick struct statfs sb; 9912788Ssam 10012788Ssam if (savacctp) { 10137728Smckusick (void)VFS_STATFS(savacctp->v_mount, &sb); 10237728Smckusick if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 10312788Ssam acctp = savacctp; 10412788Ssam savacctp = NULL; 10537728Smckusick log(LOG_NOTICE, "Accounting resumed\n"); 10637728Smckusick return; 10712788Ssam } 10812788Ssam } 10937728Smckusick if (acctp == NULL) 11012788Ssam return; 11137728Smckusick (void)VFS_STATFS(acctp->v_mount, &sb); 11237728Smckusick if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 11312788Ssam savacctp = acctp; 11412788Ssam acctp = NULL; 11537728Smckusick log(LOG_NOTICE, "Accounting suspended\n"); 11637728Smckusick } 11737728Smckusick timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 11837728Smckusick } 11937728Smckusick 12037728Smckusick /* 12137728Smckusick * On exit, write a record on the accounting file. 12237728Smckusick */ 123*43379Smckusick acct(p) 124*43379Smckusick register struct proc *p; 12537728Smckusick { 12637728Smckusick register struct rusage *ru; 12737728Smckusick struct vnode *vp; 12840803Smarc struct timeval t, ut, st; 12940803Smarc int i, s; 13037728Smckusick struct acct acctbuf; 13137728Smckusick register struct acct *ap = &acctbuf; 13237728Smckusick 13337728Smckusick if ((vp = acctp) == NULL) 134*43379Smckusick return (0); 13540803Smarc bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); 13616715Ssam ru = &u.u_ru; 13740803Smarc s = splclock(); 13840803Smarc ut = p->p_utime; 13940803Smarc st = p->p_stime; 14016715Ssam t = time; 14140803Smarc splx(s); 14240803Smarc ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); 14340803Smarc ap->ac_stime = compress(st.tv_sec, st.tv_usec); 14416715Ssam timevalsub(&t, &u.u_start); 14516715Ssam ap->ac_etime = compress(t.tv_sec, t.tv_usec); 14616715Ssam ap->ac_btime = u.u_start.tv_sec; 147*43379Smckusick ap->ac_uid = p->p_ruid; 148*43379Smckusick ap->ac_gid = p->p_rgid; 14940803Smarc t = st; 15040803Smarc timevaladd(&t, &ut); 15116719Skarels if (i = t.tv_sec * hz + t.tv_usec / tick) 15216715Ssam ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 15316715Ssam else 15416715Ssam ap->ac_mem = 0; 15516715Ssam ap->ac_mem >>= CLSIZELOG2; 15626277Skarels ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 15742204Smarc if (p->p_flag&SCTTY && p->p_session->s_ttyp) 15840803Smarc ap->ac_tty = p->p_session->s_ttyp->t_dev; 15912788Ssam else 16012788Ssam ap->ac_tty = NODEV; 16112788Ssam ap->ac_flag = u.u_acflag; 162*43379Smckusick return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 163*43379Smckusick (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0)); 16412788Ssam } 16512788Ssam 16612788Ssam /* 16712788Ssam * Produce a pseudo-floating point representation 16812788Ssam * with 3 bits base-8 exponent, 13 bits fraction. 16912788Ssam */ 17016715Ssam compress(t, ut) 17112788Ssam register long t; 17216715Ssam long ut; 17312788Ssam { 17412788Ssam register exp = 0, round = 0; 17512788Ssam 17617501Skarels t = t * AHZ; /* compiler will convert only this format to a shift */ 17716715Ssam if (ut) 17817501Skarels t += ut / (1000000 / AHZ); 17912788Ssam while (t >= 8192) { 18012788Ssam exp++; 18112788Ssam round = t&04; 18212788Ssam t >>= 3; 18312788Ssam } 18412788Ssam if (round) { 18512788Ssam t++; 18612788Ssam if (t >= 8192) { 18712788Ssam t >>= 3; 18812788Ssam exp++; 18912788Ssam } 19012788Ssam } 19112788Ssam return ((exp<<13) + t); 19212788Ssam } 193