1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)kern_acct.c 7.5 (Berkeley) 05/09/89 18 */ 19 20 #include "param.h" 21 #include "systm.h" 22 #include "user.h" 23 #include "vnode.h" 24 #include "mount.h" 25 #include "kernel.h" 26 #include "acct.h" 27 #include "uio.h" 28 #include "syslog.h" 29 30 /* 31 * Values associated with enabling and disabling accounting 32 */ 33 int acctsuspend = 2; /* stop accounting when < 2% free space left */ 34 int acctresume = 4; /* resume when free space risen to > 4% */ 35 struct timeval chk = { 15, 0 };/* frequency to check space for accounting */ 36 37 /* 38 * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 39 */ 40 struct vnode *acctp; 41 struct vnode *savacctp; 42 43 /* 44 * Perform process accounting functions. 45 */ 46 sysacct() 47 { 48 register struct vnode *vp; 49 register struct a { 50 char *fname; 51 } *uap = (struct a *)u.u_ap; 52 register struct nameidata *ndp = &u.u_nd; 53 extern int acctwatch(); 54 struct vnode *oacctp; 55 56 if (u.u_error = suser(u.u_cred, &u.u_acflag)) 57 return; 58 if (savacctp) { 59 acctp = savacctp; 60 savacctp = NULL; 61 } 62 if (uap->fname==NULL) { 63 if (vp = acctp) { 64 acctp = NULL; 65 vrele(vp); 66 untimeout(acctwatch, (caddr_t)&chk); 67 } 68 return; 69 } 70 ndp->ni_nameiop = LOOKUP | FOLLOW; 71 ndp->ni_segflg = UIO_USERSPACE; 72 ndp->ni_dirp = uap->fname; 73 if (u.u_error = namei(ndp)) 74 return; 75 vp = ndp->ni_vp; 76 if (vp->v_type != VREG) { 77 u.u_error = EACCES; 78 vrele(vp); 79 return; 80 } 81 if (vp->v_mount->m_flag & M_RDONLY) { 82 u.u_error = EROFS; 83 vrele(vp); 84 return; 85 } 86 oacctp = acctp; 87 acctp = vp; 88 if (oacctp) 89 vrele(oacctp); 90 acctwatch(&chk); 91 } 92 93 /* 94 * Periodically check the file system to see if accounting 95 * should be turned on or off. 96 */ 97 acctwatch(resettime) 98 struct timeval *resettime; 99 { 100 struct statfs sb; 101 102 if (savacctp) { 103 (void)VFS_STATFS(savacctp->v_mount, &sb); 104 if (sb.f_bavail > acctresume * sb.f_blocks / 100) { 105 acctp = savacctp; 106 savacctp = NULL; 107 log(LOG_NOTICE, "Accounting resumed\n"); 108 return; 109 } 110 } 111 if (acctp == NULL) 112 return; 113 (void)VFS_STATFS(acctp->v_mount, &sb); 114 if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { 115 savacctp = acctp; 116 acctp = NULL; 117 log(LOG_NOTICE, "Accounting suspended\n"); 118 } 119 timeout(acctwatch, (caddr_t)resettime, hzto(resettime)); 120 } 121 122 /* 123 * On exit, write a record on the accounting file. 124 */ 125 acct() 126 { 127 register struct rusage *ru; 128 struct vnode *vp; 129 struct timeval t; 130 int i; 131 struct acct acctbuf; 132 register struct acct *ap = &acctbuf; 133 134 if ((vp = acctp) == NULL) 135 return; 136 bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm)); 137 ru = &u.u_ru; 138 ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 139 ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 140 t = time; 141 timevalsub(&t, &u.u_start); 142 ap->ac_etime = compress(t.tv_sec, t.tv_usec); 143 ap->ac_btime = u.u_start.tv_sec; 144 ap->ac_uid = u.u_ruid; 145 ap->ac_gid = u.u_rgid; 146 t = ru->ru_stime; 147 timevaladd(&t, &ru->ru_utime); 148 if (i = t.tv_sec * hz + t.tv_usec / tick) 149 ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 150 else 151 ap->ac_mem = 0; 152 ap->ac_mem >>= CLSIZELOG2; 153 ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 154 if (u.u_ttyp) 155 ap->ac_tty = u.u_ttyd; 156 else 157 ap->ac_tty = NODEV; 158 ap->ac_flag = u.u_acflag; 159 u.u_error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), 160 (off_t)0, UIO_SYSSPACE, IO_UNIT|IO_APPEND, u.u_cred, (int *)0); 161 } 162 163 /* 164 * Produce a pseudo-floating point representation 165 * with 3 bits base-8 exponent, 13 bits fraction. 166 */ 167 compress(t, ut) 168 register long t; 169 long ut; 170 { 171 register exp = 0, round = 0; 172 173 t = t * AHZ; /* compiler will convert only this format to a shift */ 174 if (ut) 175 t += ut / (1000000 / AHZ); 176 while (t >= 8192) { 177 exp++; 178 round = t&04; 179 t >>= 3; 180 } 181 if (round) { 182 t++; 183 if (t >= 8192) { 184 t >>= 3; 185 exp++; 186 } 187 } 188 return ((exp<<13) + t); 189 } 190