1 /*- 2 * Copyright (c) 1982, 1986, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 * 7 * @(#)kern_acct.c 7.22 (Berkeley) 05/14/92 8 */ 9 10 #include "param.h" 11 #include "systm.h" 12 #include "namei.h" 13 #include "resourcevar.h" 14 #include "proc.h" 15 #include "ioctl.h" 16 #include "termios.h" 17 #include "tty.h" 18 #include "vnode.h" 19 #include "mount.h" 20 #include "kernel.h" 21 #include "file.h" 22 #include "acct.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 * Enable or disable process accounting. 40 * 41 * If a non-null filename is given, that file is used to store accounting 42 * records on process exit. If a null filename is given process accounting 43 * is suspended. If accounting is enabled, the system checks the amount 44 * of freespace on the filesystem at timeval intervals. If the amount of 45 * freespace is below acctsuspend percent, accounting is suspended. If 46 * accounting has been suspended, and freespace rises above acctresume, 47 * accounting is resumed. 48 */ 49 /* ARGSUSED */ 50 sysacct(p, uap, retval) 51 struct proc *p; 52 struct args { 53 char *fname; 54 } *uap; 55 int *retval; 56 { 57 USES_VOP_UNLOCK; 58 register struct vnode *vp; 59 extern int acctwatch(); 60 struct vnode *oacctp; 61 int error; 62 struct nameidata nd; 63 64 if (error = suser(p->p_ucred, &p->p_acflag)) 65 return (error); 66 if (savacctp) { 67 acctp = savacctp; 68 savacctp = NULL; 69 } 70 if (uap->fname == NULL) { 71 if (vp = acctp) { 72 acctp = NULL; 73 error = vn_close(vp, FWRITE, p->p_ucred, p); 74 untimeout(acctwatch, (caddr_t)&chk); 75 } 76 return (error); 77 } 78 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); 79 if (error = vn_open(&nd, FWRITE, 0644)) 80 return (error); 81 vp = nd.ni_vp; 82 VOP_UNLOCK(vp); 83 if (vp->v_type != VREG) { 84 (void) vn_close(vp, FWRITE, p->p_ucred, p); 85 return (EACCES); 86 } 87 oacctp = acctp; 88 acctp = vp; 89 if (oacctp) 90 error = vn_close(oacctp, FWRITE, p->p_ucred, p); 91 acctwatch(&chk); 92 return (error); 93 } 94 95 /* 96 * Periodically check the file system to see if accounting 97 * should be turned on or off. 98 */ 99 acctwatch(resettime) 100 struct timeval *resettime; 101 { 102 struct statfs sb; 103 104 if (savacctp) { 105 (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); 106 if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 107 acctp = savacctp; 108 savacctp = NULL; 109 log(LOG_NOTICE, "Accounting resumed\n"); 110 return; 111 } 112 } 113 if (acctp == NULL) 114 return; 115 (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); 116 if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 117 savacctp = acctp; 118 acctp = NULL; 119 log(LOG_NOTICE, "Accounting suspended\n"); 120 } 121 timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 122 } 123 124 /* 125 * This routine calculates an accounting record for a process and, 126 * if accounting is enabled, writes it to the accounting file. 127 */ 128 acct(p) 129 register struct proc *p; 130 { 131 register struct rusage *ru; 132 struct vnode *vp; 133 struct timeval t, ut, st; 134 int i, s; 135 struct acct acctbuf; 136 register struct acct *ap = &acctbuf; 137 138 if ((vp = acctp) == NULL) 139 return (0); 140 bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); 141 ru = &p->p_stats->p_ru; 142 s = splclock(); 143 ut = p->p_utime; 144 st = p->p_stime; 145 t = time; 146 splx(s); 147 ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); 148 ap->ac_stime = compress(st.tv_sec, st.tv_usec); 149 timevalsub(&t, &p->p_stats->p_start); 150 ap->ac_etime = compress(t.tv_sec, t.tv_usec); 151 ap->ac_btime = p->p_stats->p_start.tv_sec; 152 ap->ac_uid = p->p_cred->p_ruid; 153 ap->ac_gid = p->p_cred->p_rgid; 154 t = st; 155 timevaladd(&t, &ut); 156 if (i = t.tv_sec * hz + t.tv_usec / tick) 157 ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; 158 else 159 ap->ac_mem = 0; 160 ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 161 if (p->p_flag&SCTTY && p->p_session->s_ttyp) 162 ap->ac_tty = p->p_session->s_ttyp->t_dev; 163 else 164 ap->ac_tty = NODEV; 165 ap->ac_flag = p->p_acflag; 166 return (vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, 167 UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, 168 (struct proc *)0)); 169 } 170 171 /* 172 * Produce a pseudo-floating point representation 173 * with 3 bits base-8 exponent, 13 bits fraction. 174 */ 175 compress(t, ut) 176 register long t; 177 long ut; 178 { 179 register exp = 0, round = 0; 180 181 t = t * AHZ; /* compiler will convert only this format to a shift */ 182 if (ut) 183 t += ut / (1000000 / AHZ); 184 while (t >= 8192) { 185 exp++; 186 round = t&04; 187 t >>= 3; 188 } 189 if (round) { 190 t++; 191 if (t >= 8192) { 192 t >>= 3; 193 exp++; 194 } 195 } 196 return ((exp<<13) + t); 197 } 198