[BACK]Return to kern_acct.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_acct.c, Revision 1.1

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

CVSweb