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