1 /* 2 * Copyright (c) 1982, 1986 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.3 (Berkeley) 10/18/88 7 */ 8 9 #include "param.h" 10 #include "systm.h" 11 #include "dir.h" 12 #include "user.h" 13 #include "inode.h" 14 #include "fs.h" 15 #include "kernel.h" 16 #include "acct.h" 17 #include "uio.h" 18 19 /* 20 * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. 21 */ 22 struct inode *acctp; 23 struct inode *savacctp; 24 25 /* 26 * Perform process accounting functions. 27 */ 28 sysacct() 29 { 30 register struct inode *ip; 31 register struct a { 32 char *fname; 33 } *uap = (struct a *)u.u_ap; 34 register struct nameidata *ndp = &u.u_nd; 35 36 if (suser()) { 37 if (savacctp) { 38 acctp = savacctp; 39 savacctp = NULL; 40 } 41 if (uap->fname==NULL) { 42 if (ip = acctp) { 43 acctp = NULL; 44 irele(ip); 45 } 46 return; 47 } 48 ndp->ni_nameiop = LOOKUP | FOLLOW; 49 ndp->ni_segflg = UIO_USERSPACE; 50 ndp->ni_dirp = uap->fname; 51 ip = namei(ndp); 52 if (ip == NULL) 53 return; 54 if ((ip->i_mode&IFMT) != IFREG) { 55 u.u_error = EACCES; 56 iput(ip); 57 return; 58 } 59 if (ip->i_fs->fs_ronly) { 60 u.u_error = EROFS; 61 iput(ip); 62 return; 63 } 64 if (acctp && (acctp->i_number != ip->i_number || 65 acctp->i_dev != ip->i_dev)) 66 irele(acctp); 67 acctp = ip; 68 iunlock(ip); 69 } 70 } 71 72 int acctsuspend = 2; /* stop accounting when < 2% free space left */ 73 int acctresume = 4; /* resume when free space risen to > 4% */ 74 75 struct acct acctbuf; 76 /* 77 * On exit, write a record on the accounting file. 78 */ 79 acct() 80 { 81 register int i; 82 register struct inode *ip; 83 register struct fs *fs; 84 register struct rusage *ru; 85 off_t siz; 86 struct timeval t; 87 register struct acct *ap = &acctbuf; 88 89 if (savacctp) { 90 fs = savacctp->i_fs; 91 if (freespace(fs, fs->fs_minfree + acctresume) > 0) { 92 acctp = savacctp; 93 savacctp = NULL; 94 printf("Accounting resumed\n"); 95 } 96 } 97 if ((ip = acctp) == NULL) 98 return; 99 fs = acctp->i_fs; 100 if (freespace(fs, fs->fs_minfree + acctsuspend) <= 0) { 101 savacctp = acctp; 102 acctp = NULL; 103 printf("Accounting suspended\n"); 104 return; 105 } 106 ilock(ip); 107 bcopy(u.u_comm, ap->ac_comm, sizeof(ap->ac_comm)); 108 ru = &u.u_ru; 109 ap->ac_utime = compress(ru->ru_utime.tv_sec, ru->ru_utime.tv_usec); 110 ap->ac_stime = compress(ru->ru_stime.tv_sec, ru->ru_stime.tv_usec); 111 t = time; 112 timevalsub(&t, &u.u_start); 113 ap->ac_etime = compress(t.tv_sec, t.tv_usec); 114 ap->ac_btime = u.u_start.tv_sec; 115 ap->ac_uid = u.u_ruid; 116 ap->ac_gid = u.u_rgid; 117 t = ru->ru_stime; 118 timevaladd(&t, &ru->ru_utime); 119 if (i = t.tv_sec * hz + t.tv_usec / tick) 120 ap->ac_mem = (ru->ru_ixrss+ru->ru_idrss+ru->ru_isrss) / i; 121 else 122 ap->ac_mem = 0; 123 ap->ac_mem >>= CLSIZELOG2; 124 ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); 125 if (u.u_ttyp) 126 ap->ac_tty = u.u_ttyd; 127 else 128 ap->ac_tty = NODEV; 129 ap->ac_flag = u.u_acflag; 130 siz = ip->i_size; 131 u.u_error = 0; /* XXX */ 132 u.u_error = 133 rdwri(UIO_WRITE, ip, (caddr_t)ap, sizeof (acctbuf), siz, 134 1, (int *)0); 135 if (u.u_error) 136 itrunc(ip, (u_long)siz); 137 iunlock(ip); 138 } 139 140 /* 141 * Produce a pseudo-floating point representation 142 * with 3 bits base-8 exponent, 13 bits fraction. 143 */ 144 compress(t, ut) 145 register long t; 146 long ut; 147 { 148 register exp = 0, round = 0; 149 150 t = t * AHZ; /* compiler will convert only this format to a shift */ 151 if (ut) 152 t += ut / (1000000 / AHZ); 153 while (t >= 8192) { 154 exp++; 155 round = t&04; 156 t >>= 3; 157 } 158 if (round) { 159 t++; 160 if (t >= 8192) { 161 t >>= 3; 162 exp++; 163 } 164 } 165 return ((exp<<13) + t); 166 } 167