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