X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/715baff10ca319398d8285a0ac7c56219dc65fff..6b8f7051f2b8ef9bd16f7fb52d3226972bd3aa4f:/usr/src/sys/kern/kern_acct.c diff --git a/usr/src/sys/kern/kern_acct.c b/usr/src/sys/kern/kern_acct.c index 26b70bde96..235c2e0b54 100644 --- a/usr/src/sys/kern/kern_acct.c +++ b/usr/src/sys/kern/kern_acct.c @@ -1,133 +1,213 @@ -/* kern_acct.c 6.2 84/07/08 */ +/*- + * Copyright (c) 1982, 1986, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * (c) UNIX System Laboratories, Inc. + * All or some portions of this file are derived from material licensed + * to the University of California by American Telephone and Telegraph + * Co. or Unix System Laboratories, Inc. and are reproduced herein with + * the permission of UNIX System Laboratories, Inc. + * + * %sccs.include.proprietary.c% + * + * @(#)kern_acct.c 8.6 (Berkeley) %G% + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/inode.h" -#include "../h/fs.h" -#include "../h/kernel.h" -#include "../h/acct.h" -#include "../h/uio.h" +/* + * Values associated with enabling and disabling accounting + */ +int acctsuspend = 2; /* stop accounting when < 2% free space left */ +int acctresume = 4; /* resume when free space risen to > 4% */ +int acctchkfreq = 15; /* frequency (in seconds) to check space */ /* * SHOULD REPLACE THIS WITH A DRIVER THAT CAN BE READ TO SIMPLIFY. */ -struct inode *acctp; -struct inode *savacctp; +struct vnode *acctp; +struct vnode *savacctp; /* - * Perform process accounting functions. + * Enable or disable process accounting. + * + * If a non-null filename is given, that file is used to store accounting + * records on process exit. If a null filename is given process accounting + * is suspended. If accounting is enabled, the system checks the amount + * of freespace on the filesystem at timeval intervals. If the amount of + * freespace is below acctsuspend percent, accounting is suspended. If + * accounting has been suspended, and freespace rises above acctresume, + * accounting is resumed. */ -sysacct() +struct acct_args { + char *fname; +}; +acct(p, uap, retval) + struct proc *p; + struct acct_args *uap; + int *retval; { - register struct inode *ip; - register struct a { - char *fname; - } *uap = (struct a *)u.u_ap; - register struct nameidata *ndp = &u.u_nd; + register struct vnode *vp; + extern void acctwatch __P((void *)); + struct vnode *oacctp; + int error; + struct nameidata nd; - if (suser()) { - if (savacctp) { - acctp = savacctp; - savacctp = NULL; + if (error = suser(p->p_ucred, &p->p_acflag)) + return (error); + if (savacctp) { + acctp = savacctp; + savacctp = NULL; + } + if (uap->fname == NULL) { + if (vp = acctp) { + acctp = NULL; + error = vn_close(vp, FWRITE, p->p_ucred, p); + untimeout(acctwatch, NULL); } - if (uap->fname==NULL) { - if (ip = acctp) { - irele(ip); - acctp = NULL; - } + return (error); + } + NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->fname, p); + if (error = vn_open(&nd, FWRITE, 0644)) + return (error); + vp = nd.ni_vp; + VOP_UNLOCK(vp); + if (vp->v_type != VREG) { + (void) vn_close(vp, FWRITE, p->p_ucred, p); + return (EACCES); + } + oacctp = acctp; + acctp = vp; + if (oacctp) + error = vn_close(oacctp, FWRITE, p->p_ucred, p); + acctwatch(NULL); + return (error); +} + +/* + * Periodically check the file system to see if accounting + * should be turned on or off. Beware the case where the vnode + * has been vgone()'d out from underneath us, e.g. when the file + * system containing the accounting file has been forcibly unmounted. + */ +/* ARGSUSED */ +void +acctwatch(a) + void *a; +{ + struct statfs sb; + + if (savacctp) { + if (savacctp->v_type == VBAD) { + (void) vn_close(savacctp, FWRITE, NOCRED, NULL); + savacctp = NULL; return; } - ndp->ni_nameiop = LOOKUP | FOLLOW; - ndp->ni_segflg = UIO_USERSPACE; - ndp->ni_dirp = uap->fname; - ip = namei(ndp); - if(ip == NULL) + (void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0); + if (sb.f_bavail > acctresume * sb.f_blocks / 100) { + acctp = savacctp; + savacctp = NULL; + log(LOG_NOTICE, "Accounting resumed\n"); + } + } else { + if (acctp == NULL) return; - if((ip->i_mode & IFMT) != IFREG) { - u.u_error = EACCES; - iput(ip); + if (acctp->v_type == VBAD) { + (void) vn_close(acctp, FWRITE, NOCRED, NULL); + acctp = NULL; return; } - if (acctp && (acctp->i_number != ip->i_number || - acctp->i_dev != ip->i_dev)) - irele(acctp); - acctp = ip; - iunlock(ip); + (void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0); + if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) { + savacctp = acctp; + acctp = NULL; + log(LOG_NOTICE, "Accounting suspended\n"); + } } + timeout(acctwatch, NULL, acctchkfreq * hz); } -int acctsuspend = 2; /* stop accounting when < 2% free space left */ -int acctresume = 4; /* resume when free space risen to > 4% */ - -struct acct acctbuf; /* - * On exit, write a record on the accounting file. + * This routine calculates an accounting record for a process and, + * if accounting is enabled, writes it to the accounting file. */ -acct() +acct_process(p) + register struct proc *p; { - register int i; - register struct inode *ip; - register struct fs *fs; - off_t siz; + register struct rusage *ru; + struct vnode *vp; + struct timeval t, ut, st; + int error, i, s; + struct acct acctbuf; register struct acct *ap = &acctbuf; - if (savacctp) { - fs = savacctp->i_fs; - if (freespace(fs, fs->fs_minfree + acctresume) > 0) { - acctp = savacctp; - savacctp = NULL; - printf("Accounting resumed\n"); - } + s = splclock(); + if ((vp = acctp) == NULL) { + splx(s); + return (0); } - if ((ip = acctp) == NULL) - return; - fs = acctp->i_fs; - if (freespace(fs, fs->fs_minfree + acctsuspend) <= 0) { - savacctp = acctp; + if (vp->v_type == VBAD) { + (void) vn_close(vp, FWRITE, NOCRED, NULL); acctp = NULL; - printf("Accounting suspended\n"); - return; + splx(s); + return (0); } - ilock(ip); - for (i = 0; i < sizeof (ap->ac_comm); i++) - ap->ac_comm[i] = u.u_comm[i]; - ap->ac_utime = compress((long)u.u_ru.ru_utime.tv_sec); - ap->ac_stime = compress((long)u.u_ru.ru_stime.tv_sec); - ap->ac_etime = compress((long)time.tv_sec - u.u_start); - ap->ac_btime = u.u_start; - ap->ac_uid = u.u_ruid; - ap->ac_gid = u.u_rgid; - ap->ac_mem = 0; - if (i = u.u_ru.ru_utime.tv_sec + u.u_ru.ru_stime.tv_sec) - ap->ac_mem = - (u.u_ru.ru_ixrss + u.u_ru.ru_idrss + u.u_ru.ru_isrss) / i; - ap->ac_io = compress((long)(u.u_ru.ru_inblock + u.u_ru.ru_oublock)); - if (u.u_ttyp) - ap->ac_tty = u.u_ttyd; + bcopy(p->p_comm, ap->ac_comm, sizeof(ap->ac_comm)); + ru = &p->p_stats->p_ru; + calcru(p, &ut, &st, NULL); + t = time; + ap->ac_utime = compress(ut.tv_sec, ut.tv_usec); + ap->ac_stime = compress(st.tv_sec, st.tv_usec); + timevalsub(&t, &p->p_stats->p_start); + ap->ac_etime = compress(t.tv_sec, t.tv_usec); + ap->ac_btime = p->p_stats->p_start.tv_sec; + ap->ac_uid = p->p_cred->p_ruid; + ap->ac_gid = p->p_cred->p_rgid; + t = st; + timevaladd(&t, &ut); + if (i = t.tv_sec * hz + t.tv_usec / tick) + ap->ac_mem = (ru->ru_ixrss + ru->ru_idrss + ru->ru_isrss) / i; + else + ap->ac_mem = 0; + ap->ac_io = compress(ru->ru_inblock + ru->ru_oublock, (long)0); + if (p->p_flag & P_CONTROLT && p->p_session->s_ttyp) + ap->ac_tty = p->p_session->s_ttyp->t_dev; else ap->ac_tty = NODEV; - ap->ac_flag = u.u_acflag; - siz = ip->i_size; - u.u_error = 0; /* XXX */ - u.u_error = - rdwri(UIO_WRITE, ip, (caddr_t)ap, sizeof (acctbuf), siz, - 1, (int *)0); - if (u.u_error) - itrunc(ip, (u_long)siz); - iunlock(ip); + ap->ac_flag = p->p_acflag; + VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE); + error = vn_rdwr(UIO_WRITE, vp, (caddr_t)ap, sizeof (acctbuf), (off_t)0, + UIO_SYSSPACE, IO_UNIT|IO_APPEND, p->p_ucred, (int *)0, + (struct proc *)0); + splx(s); + return (error); } /* * Produce a pseudo-floating point representation * with 3 bits base-8 exponent, 13 bits fraction. */ -compress(t) +compress(t, ut) register long t; + long ut; { register exp = 0, round = 0; + t = t * AHZ; /* compiler will convert only this format to a shift */ + if (ut) + t += ut / (1000000 / AHZ); while (t >= 8192) { exp++; round = t&04;