1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 * 6 * @(#)kern_acct.c 7.11 (Berkeley) 06/21/90 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "time.h" 12 #include "proc.h" 13 #include "ioctl.h" 14 #include "termios.h" 15 #include "tty.h" 16 #undef RETURN 17 #include "syscontext.h" 18 #include "vnode.h" 19 #include "mount.h" 20 #include "kernel.h" 21 #include "acct.h" 22 #include "uio.h" 23 #include "syslog.h" 24 25 /* 26 * Values associated with enabling and disabling accounting 27 */ 28 int acctsuspend = 2; /* stop accounting when < 2% free space left */ 29 int acctresume = 4; /* resume when free space risen to > 4% */ 30 struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 31 32 /* 33 * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 34 */ 35 struct vnode *acctp; 36 struct vnode *savacctp; 37 38 /* 39 * Perform process accounting functions. 40 */ 41 /* ARGSUSED */ 42 sysacct(p, uap, retval) 43 struct proc *p; 44 struct args { 45 char *fname; 46 } *uap; 47 int *retval; 48 { 49 register struct vnode *vp; 50 register struct nameidata *ndp = &u.u_nd; 51 extern int acctwatch(); 52 struct vnode *oacctp; 53 int error; 54 55 if (error = suser(u.u_cred, &u.u_acflag)) 56 RETURN (error); 57 if (savacctp) { 58 acctp = savacctp; 59 savacctp = NULL; 60 } 61 if (uap->fname==NULL) { 62 if (vp = acctp) { 63 acctp = NULL; 64 vrele(vp); 65 untimeout(acctwatch, (caddr_t)&chk); 66 } 67 RETURN (0); 68 } 69 ndp->ni_nameiop = LOOKUP | FOLLOW; 70 ndp->ni_segflg = UIO_USERSPACE; 71 ndp->ni_dirp = uap->fname; 72 if (error = namei(ndp)) 73 RETURN (error); 74 vp = ndp->ni_vp; 75 if (vp->v_type != VREG) { 76 vrele(vp); 77 RETURN (EACCES); 78 } 79 if (vp->v_mount->mnt_flag & MNT_RDONLY) { 80 vrele(vp); 81 RETURN (EROFS); 82 } 83 oacctp = acctp; 84 acctp = vp; 85 if (oacctp) 86 vrele(oacctp); 87 acctwatch(&chk); 88 RETURN (0); 89 } 90 91 /* 92 * Periodically check the file system to see if accounting 93 * should be turned on or off. 94 */ 95 acctwatch(resettime) 96 struct timeval *resettime; 97 { 98 struct statfs sb; 99 100 if (savacctp) { 101 (void)VFS_STATFS(savacctp->v_mount, &sb); 102 if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 103 acctp = savacctp; 104 savacctp = NULL; 105 log(LOG_NOTICE, "Accounting resumed\n"); 106 return; 107 } 108 } 109 if (acctp == NULL) 110 return; 111 (void)VFS_STATFS(acctp->v_mount, &sb); 112 if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 113 savacctp = acctp; 114 acctp = NULL; 115 log(LOG_NOTICE, "Accounting suspended\n"); 116 } 117 timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 118 } 119 120 /* 121 * On exit, write a record on the accounting file. 122 */ 123 acct(p) 124 register struct proc *p; 125 { 126 register struct rusage *ru; 127 struct vnode *vp; 128 struct timeval t, ut, st; 129 int i, s; 130 struct acct acctbuf; 131 register struct acct *ap = &acctbuf; 132 133 if ((vp = acctp) == NULL) 134 return (0); 135 bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); 136 ru = &u.u_ru; 137 s = splclock(); 138 ut = p->p_utime; 139 st = p->p_stime; 140 t = time; 141 splx(s); 142 ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); 143 ap->ac_stime = compress(st.tv_sec, st.tv_usec); 144 timevalsub(&t, &u.u_start); 145 ap->ac_etime = compress(t.tv_sec, t.tv_usec); 146 ap->ac_btime = u.u_start.tv_sec; 147 ap->ac_uid = p->p_ruid; 148 ap->ac_gid = p->p_rgid; 149 t = st; 150 timevaladd(&t, &ut); 151 if (i = t.tv_sec * hz + t.tv_usec / tick) 152 ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 153 else 154 ap->ac_mem = 0; 155 ap->ac_mem >>= CLSIZELOG2; 156 ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 157 if (p->p_flag&SCTTY && p->p_session->s_ttyp) 158 ap->ac_tty = p->p_session->s_ttyp->t_dev; 159 else 160 ap->ac_tty = NODEV; 161 ap->ac_flag = u.u_acflag; 162 return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 163 (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0)); 164 } 165 166 /* 167 * Produce a pseudo-floating point representation 168 * with 3 bits base-8 exponent, 13 bits fraction. 169 */ 170 compress(t, ut) 171 register long t; 172 long ut; 173 { 174 register exp = 0, round = 0; 175 176 t = t * AHZ; /* compiler will convert only this format to a shift */ 177 if (ut) 178 t += ut / (1000000 / AHZ); 179 while (t >= 8192) { 180 exp++; 181 round = t&04; 182 t >>= 3; 183 } 184 if (round) { 185 t++; 186 if (t >= 8192) { 187 t >>= 3; 188 exp++; 189 } 190 } 191 return ((exp<<13) + t); 192 } 193