|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /*- ! 24: * Copyright (c) 1982, 1986, 1989, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * (c) UNIX System Laboratories, Inc. ! 27: * All or some portions of this file are derived from material licensed ! 28: * to the University of California by American Telephone and Telegraph ! 29: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 30: * the permission of UNIX System Laboratories, Inc. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 ! 61: */ ! 62: /* HISTORY ! 63: * 08-May-95 Mac Gillon (mgillon) at NeXT ! 64: * Purged old history ! 65: * New version based on 4.4 ! 66: */ ! 67: ! 68: ! 69: #include <sys/param.h> ! 70: #include <sys/proc.h> ! 71: #include <sys/mount.h> ! 72: #include <sys/vnode.h> ! 73: #include <sys/file.h> ! 74: #include <sys/syslog.h> ! 75: #include <sys/kernel.h> ! 76: #include <sys/namei.h> ! 77: #include <sys/errno.h> ! 78: #include <sys/acct.h> ! 79: #include <sys/resourcevar.h> ! 80: #include <sys/ioctl.h> ! 81: #include <sys/tty.h> ! 82: ! 83: /* ! 84: * The routines implemented in this file are described in: ! 85: * Leffler, et al.: The Design and Implementation of the 4.3BSD ! 86: * UNIX Operating System (Addison Welley, 1989) ! 87: * on pages 62-63. ! 88: * ! 89: * Arguably, to simplify accounting operations, this mechanism should ! 90: * be replaced by one in which an accounting log file (similar to /dev/klog) ! 91: * is read by a user process, etc. However, that has its own problems. ! 92: */ ! 93: ! 94: /* ! 95: * Internal accounting functions. ! 96: * The former's operation is described in Leffler, et al., and the latter ! 97: * was provided by UCB with the 4.4BSD-Lite release ! 98: */ ! 99: comp_t encode_comp_t __P((u_long, u_long)); ! 100: void acctwatch __P((void *)); ! 101: ! 102: /* ! 103: * Accounting vnode pointer, and saved vnode pointer. ! 104: */ ! 105: struct vnode *acctp; ! 106: struct vnode *savacctp; ! 107: ! 108: /* ! 109: * Values associated with enabling and disabling accounting ! 110: */ ! 111: int acctsuspend = 2; /* stop accounting when < 2% free space left */ ! 112: int acctresume = 4; /* resume when free space risen to > 4% */ ! 113: int acctchkfreq = 15; /* frequency (in seconds) to check space */ ! 114: ! 115: /* ! 116: * Accounting system call. Written based on the specification and ! 117: * previous implementation done by Mark Tinguely. ! 118: */ ! 119: struct acct_args { ! 120: char *path; ! 121: }; ! 122: acct(p, uap, retval) ! 123: struct proc *p; ! 124: struct acct_args *uap; ! 125: int *retval; ! 126: { ! 127: struct nameidata nd; ! 128: int error; ! 129: ! 130: /* Make sure that the caller is root. */ ! 131: if (error = suser(p->p_ucred, &p->p_acflag)) ! 132: return (error); ! 133: ! 134: /* ! 135: * If accounting is to be started to a file, open that file for ! 136: * writing and make sure it's a 'normal'. ! 137: */ ! 138: if (uap->path != NULL) { ! 139: NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, p); ! 140: if (error = vn_open(&nd, FWRITE, 0)) ! 141: return (error); ! 142: VOP_UNLOCK(nd.ni_vp, 0, p); ! 143: if (nd.ni_vp->v_type != VREG) { ! 144: vn_close(nd.ni_vp, FWRITE, p->p_ucred, p); ! 145: return (EACCES); ! 146: } ! 147: } ! 148: ! 149: /* ! 150: * If accounting was previously enabled, kill the old space-watcher, ! 151: * close the file, and (if no new file was specified, leave). ! 152: */ ! 153: if (acctp != NULLVP || savacctp != NULLVP) { ! 154: untimeout(acctwatch, NULL); ! 155: error = vn_close((acctp != NULLVP ? acctp : savacctp), FWRITE, ! 156: p->p_ucred, p); ! 157: acctp = savacctp = NULLVP; ! 158: } ! 159: if (uap->path == NULL) ! 160: return (error); ! 161: ! 162: /* ! 163: * Save the new accounting file vnode, and schedule the new ! 164: * free space watcher. ! 165: */ ! 166: acctp = nd.ni_vp; ! 167: acctwatch(NULL); ! 168: return (error); ! 169: } ! 170: ! 171: /* ! 172: * Write out process accounting information, on process exit. ! 173: * Data to be written out is specified in Leffler, et al. ! 174: * and are enumerated below. (They're also noted in the system ! 175: * "acct.h" header file.) ! 176: */ ! 177: acct_process(p) ! 178: struct proc *p; ! 179: { ! 180: struct acct acct; ! 181: struct rusage *r; ! 182: struct timeval ut, st, tmp; ! 183: int s, t; ! 184: struct vnode *vp; ! 185: ! 186: /* If accounting isn't enabled, don't bother */ ! 187: vp = acctp; ! 188: if (vp == NULLVP) ! 189: return (0); ! 190: ! 191: /* ! 192: * Get process accounting information. ! 193: */ ! 194: ! 195: /* (1) The name of the command that ran */ ! 196: bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); ! 197: ! 198: /* (2) The amount of user and system time that was used */ ! 199: calcru(p, &ut, &st, NULL); ! 200: acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); ! 201: acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); ! 202: ! 203: /* (3) The elapsed time the commmand ran (and its starting time) */ ! 204: acct.ac_btime = p->p_stats->p_start.tv_sec; ! 205: s = splclock(); ! 206: tmp = time; ! 207: splx(s); ! 208: timevalsub(&tmp, &p->p_stats->p_start); ! 209: acct.ac_etime = encode_comp_t(tmp.tv_sec, tmp.tv_usec); ! 210: ! 211: /* (4) The average amount of memory used */ ! 212: r = &p->p_stats->p_ru; ! 213: tmp = ut; ! 214: timevaladd(&tmp, &st); ! 215: t = tmp.tv_sec * hz + tmp.tv_usec / tick; ! 216: if (t) ! 217: acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / t; ! 218: else ! 219: acct.ac_mem = 0; ! 220: ! 221: /* (5) The number of disk I/O operations done */ ! 222: acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0); ! 223: ! 224: /* (6) The UID and GID of the process */ ! 225: acct.ac_uid = p->p_cred->p_ruid; ! 226: acct.ac_gid = p->p_cred->p_rgid; ! 227: ! 228: /* (7) The terminal from which the process was started */ ! 229: if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp) ! 230: acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev; ! 231: else ! 232: acct.ac_tty = NODEV; ! 233: ! 234: /* (8) The boolean flags that tell how the process terminated, etc. */ ! 235: acct.ac_flag = p->p_acflag; ! 236: ! 237: /* ! 238: * Now, just write the accounting information to the file. ! 239: */ ! 240: VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); ! 241: return (vn_rdwr(UIO_WRITE, vp, (caddr_t)&acct, sizeof (acct), ! 242: (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred, ! 243: (int *)0, p)); ! 244: } ! 245: ! 246: /* ! 247: * Encode_comp_t converts from ticks in seconds and microseconds ! 248: * to ticks in 1/AHZ seconds. The encoding is described in ! 249: * Leffler, et al., on page 63. ! 250: */ ! 251: ! 252: #define MANTSIZE 13 /* 13 bit mantissa. */ ! 253: #define EXPSIZE 3 /* Base 8 (3 bit) exponent. */ ! 254: #define MAXFRACT ((1 << MANTSIZE) - 1) /* Maximum fractional value. */ ! 255: ! 256: comp_t ! 257: encode_comp_t(s, us) ! 258: u_long s, us; ! 259: { ! 260: int exp, rnd; ! 261: ! 262: exp = 0; ! 263: rnd = 0; ! 264: s *= AHZ; ! 265: s += us / (1000000 / AHZ); /* Maximize precision. */ ! 266: ! 267: while (s > MAXFRACT) { ! 268: rnd = s & (1 << (EXPSIZE - 1)); /* Round up? */ ! 269: s >>= EXPSIZE; /* Base 8 exponent == 3 bit shift. */ ! 270: exp++; ! 271: } ! 272: ! 273: /* If we need to round up, do it (and handle overflow correctly). */ ! 274: if (rnd && (++s > MAXFRACT)) { ! 275: s >>= EXPSIZE; ! 276: exp++; ! 277: } ! 278: ! 279: /* Clean it up and polish it off. */ ! 280: exp <<= MANTSIZE; /* Shift the exponent into place */ ! 281: exp += s; /* and add on the mantissa. */ ! 282: return (exp); ! 283: } ! 284: ! 285: /* ! 286: * Periodically check the file system to see if accounting ! 287: * should be turned on or off. Beware the case where the vnode ! 288: * has been vgone()'d out from underneath us, e.g. when the file ! 289: * system containing the accounting file has been forcibly unmounted. ! 290: */ ! 291: /* ARGSUSED */ ! 292: void ! 293: acctwatch(a) ! 294: void *a; ! 295: { ! 296: struct statfs sb; ! 297: ! 298: if (savacctp != NULLVP) { ! 299: if (savacctp->v_type == VBAD) { ! 300: (void) vn_close(savacctp, FWRITE, NOCRED, NULL); ! 301: savacctp = NULLVP; ! 302: return; ! 303: } ! 304: (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); ! 305: if (sb.f_bavail > acctresume * sb.f_blocks / 100) { ! 306: acctp = savacctp; ! 307: savacctp = NULLVP; ! 308: log(LOG_NOTICE, "Accounting resumed\n"); ! 309: } ! 310: } else if (acctp != NULLVP) { ! 311: if (acctp->v_type == VBAD) { ! 312: (void) vn_close(acctp, FWRITE, NOCRED, NULL); ! 313: acctp = NULLVP; ! 314: return; ! 315: } ! 316: (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); ! 317: if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { ! 318: savacctp = acctp; ! 319: acctp = NULLVP; ! 320: log(LOG_NOTICE, "Accounting suspended\n"); ! 321: } ! 322: } else ! 323: return; ! 324: timeout(acctwatch, NULL, acctchkfreq * hz); ! 325: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.