Home | History | Annotate | Line # | Download | only in kern
kern_acct.c revision 1.22
      1 /*
      2  * Copyright (c) 1994 Christopher G. Demetriou
      3  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
      4  * All rights reserved.
      5  * (c) UNIX System Laboratories, Inc.
      6  * All or some portions of this file are derived from material licensed
      7  * to the University of California by American Telephone and Telegraph
      8  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
      9  * the permission of UNIX System Laboratories, Inc.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the University of
     22  *	California, Berkeley and its contributors.
     23  * 4. Neither the name of the University nor the names of its contributors
     24  *    may be used to endorse or promote products derived from this software
     25  *    without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     37  * SUCH DAMAGE.
     38  *
     39  *	from: @(#)kern_acct.c	7.18 (Berkeley) 5/11/91
     40  *	$Id: kern_acct.c,v 1.22 1994/05/17 04:21:49 cgd Exp $
     41  */
     42 
     43 #include <sys/param.h>
     44 #include <sys/systm.h>
     45 #include <sys/namei.h>
     46 #include <sys/resourcevar.h>
     47 #include <sys/proc.h>
     48 #include <sys/ioctl.h>
     49 #include <sys/termios.h>
     50 #include <sys/tty.h>
     51 #include <sys/vnode.h>
     52 #include <sys/mount.h>
     53 #include <sys/kernel.h>
     54 #include <sys/file.h>
     55 #include <sys/acct.h>
     56 #include <sys/syslog.h>
     57 
     58 #include <vm/vm.h>
     59 #include <vm/vm_param.h>
     60 
     61 /*
     62  * Values associated with enabling and disabling accounting
     63  */
     64 int	acctsuspend = 2;	/* stop accounting when < 2% free space left */
     65 int	acctresume = 4;		/* resume when free space risen to > 4% */
     66 struct	timeval chk = { 15, 0 };/* frequency to check space for accounting */
     67 struct	timeval nextchk;	/* the next time space is checked */
     68 struct  vnode *acctp = NULL;	/* file to which to do accounting */
     69 struct  vnode *savacctp = NULL;	/* file to which to do accounting when space */
     70 
     71 static comp_t encode_comp_t __P((u_long, u_long));
     72 
     73 /*
     74  * Enable or disable process accounting.
     75  *
     76  * If a non-null filename is given, that file is used to store accounting
     77  * records on process exit. If a null filename is given process accounting
     78  * is suspended. If accounting is enabled, the system checks the amount
     79  * of freespace on the filesystem at timeval intervals. If the amount of
     80  * freespace is below acctsuspend percent, accounting is suspended. If
     81  * accounting has been suspended, and freespace rises above acctresume,
     82  * accounting is resumed.
     83  *
     84  * author: Mark Tinguely (tinguely (at) plains.NoDak.edu) 8/10/93
     85  */
     86 
     87 struct acct_args {
     88 	char *fname;
     89 };
     90 /* ARGSUSED */
     91 acct(p, uap, retval)
     92 	struct proc *p;
     93 	struct acct_args *uap;
     94 	int *retval;
     95 {
     96 	register struct nameidata *ndp;
     97 	struct nameidata nd;
     98 	struct vattr attr;
     99 	int rv;
    100 	void acctwatch();
    101 
    102         if (rv = suser(p->p_ucred, &p->p_acflag))	/* must be root */
    103                 return(rv);
    104 
    105 	/*
    106 	 * Step 1. turn off accounting (if on). exit if fname is nil
    107 	 */
    108 	rv = 0;				/* just in case nothing is open */
    109 	if (acctp != NULL) {
    110 		rv = vn_close(acctp, FWRITE, p->p_ucred, p);
    111 		/* turn off disk check */
    112 		untimeout(acctwatch, &nextchk);
    113 		acctp = NULL;
    114 	}
    115 	else if (savacctp != NULL ) {
    116 		rv = vn_close(savacctp, FWRITE, p->p_ucred, p);
    117 		/* turn off disk check */
    118 		untimeout(acctwatch, &nextchk);
    119 		savacctp = NULL;
    120 	}
    121 	if (uap->fname == NULL)		/* accounting stopping complete */
    122 		return(rv);
    123 
    124 	/*
    125 	 * Step 2. open accounting filename for writing.
    126 	 */
    127 	nd.ni_segflg = UIO_USERSPACE;
    128 	nd.ni_dirp = uap->fname;
    129 
    130 	/* is it there? */
    131 	if (rv = vn_open(&nd, p, FWRITE, 0))
    132 		return (rv);
    133 
    134 	/* Step 2. Check the attributes on accounting file */
    135 	rv = VOP_GETATTR(nd.ni_vp, &attr, p->p_ucred, p);
    136 	if (rv)
    137 		goto acct_fail;
    138 
    139 	/*
    140 	 * is filesystem writable, do I have permission to write and is
    141 	 * a regular file?
    142 	 */
    143         if (nd.ni_vp->v_mount->mnt_flag & MNT_RDONLY) {
    144 		rv = EROFS;	/* to be consistant with man page */
    145 		goto acct_fail;
    146 	}
    147 	if ((VOP_ACCESS(nd.ni_vp, VWRITE, p->p_ucred, p)) ||
    148 	    (attr.va_type != VREG)) {
    149 		rv = EACCES;	/* permission denied error */
    150 		goto acct_fail;
    151 	}
    152 
    153 	/* Step 3. Save the accounting file vnode, schedule freespace watch. */
    154 	acctp  = nd.ni_vp;
    155 	savacctp = NULL;
    156 	VOP_UNLOCK(acctp);
    157 	acctwatch(&nextchk);	/* look for full system */
    158 	return(0);		/* end successfully */
    159 
    160 acct_fail:
    161 	vn_close(nd.ni_vp, FWRITE, p->p_ucred, p);
    162 	return(rv);
    163 }
    164 
    165 /*
    166  * Periodically check the file system to see if accounting
    167  * should be turned on or off.
    168  */
    169 void
    170 acctwatch(resettime)
    171 	struct timeval *resettime;
    172 {
    173 	struct statfs sb;
    174 	int s;
    175 
    176 	if (savacctp) {	/* accounting suspended */
    177 		(void)VFS_STATFS(savacctp->v_mount, &sb, (struct proc *)0);
    178 		if (sb.f_bavail > acctresume * sb.f_blocks / 100) {
    179 			acctp = savacctp;
    180 			savacctp = NULL;
    181 			log(LOG_NOTICE, "Accounting resumed\n");
    182 		}
    183 	} else if (acctp) { /* accounting going on */
    184 		(void)VFS_STATFS(acctp->v_mount, &sb, (struct proc *)0);
    185 		if (sb.f_bavail <= acctsuspend * sb.f_blocks / 100) {
    186 			savacctp = acctp;
    187 			acctp = NULL;
    188 			log(LOG_NOTICE, "Accounting suspended\n");
    189 		}
    190 	} else /* accounting yanked out from under us */
    191 		return;
    192 
    193 	s = splhigh(); *resettime = time; splx(s);
    194 	timevaladd(resettime, &chk);
    195 	timeout(acctwatch, resettime, hzto(resettime));
    196 }
    197 
    198 /*
    199  * This routine calculates an accounting record for a process and,
    200  * if accounting is enabled, writes it to the accounting file.
    201  *
    202  * author: Mark Tinguely (tinguely (at) plains.NoDak.edu) 8/10/93
    203  */
    204 
    205 acct_process(p)
    206 	register struct proc *p;
    207 {
    208 	struct acct acct;
    209 	struct rusage *r;
    210 	struct timeval tmptv, ut, st;
    211 	int rv;
    212 	long i;
    213 	u_int cnt;
    214 	char *c;
    215 
    216 	if (acctp == NULL)	/* accounting not turned on */
    217 		return;
    218 
    219 	/*
    220 	 * get process accounting information
    221 	 */
    222 	bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm);
    223 	calcru(p, &ut, &st, NULL);
    224 	acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec);
    225 	acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec);
    226 	acct.ac_btime = p->p_stats->p_start.tv_sec;
    227 	tmptv = time;
    228 	timevalsub(&tmptv, &p->p_stats->p_start);
    229 	acct.ac_etime = encode_comp_t(tmptv.tv_sec, tmptv.tv_usec);
    230 	acct.ac_uid = p->p_cred->p_ruid;
    231 	acct.ac_gid = p->p_cred->p_rgid;
    232 
    233 	r = &p->p_stats->p_ru;
    234 	tmptv = ut;
    235 	timevaladd(&tmptv, &st);
    236 	i = (tmptv.tv_sec * hz) + (tmptv.tv_usec / tick);
    237 	if (i)
    238 		acct.ac_mem = (r->ru_ixrss + r->ru_idrss + r->ru_isrss) / i;
    239 	else
    240 		acct.ac_mem = 0;
    241 	acct.ac_io = encode_comp_t(r->ru_inblock + r->ru_oublock, 0);
    242 
    243 	if ((p->p_flag & P_CONTROLT) && p->p_pgrp->pg_session->s_ttyp)
    244 		acct.ac_tty = p->p_pgrp->pg_session->s_ttyp->t_dev;
    245 	else
    246 		acct.ac_tty = NODEV;
    247 	acct.ac_flag = p->p_acflag;
    248 
    249 	/*
    250 	 * wirte accounting record to the file
    251 	 */
    252 	rv = vn_rdwr(UIO_WRITE, acctp, (caddr_t) &acct, sizeof (acct),
    253 	    (off_t)0, UIO_SYSSPACE, IO_APPEND|IO_UNIT, p->p_ucred,
    254 	    (int *) NULL, p);
    255 }
    256 
    257 /*
    258  * encode_comp_t converts from ticks in seconds and microseconds to ticks
    259  * in 1/AHZ seconds
    260  *
    261  * comp_t is a psuedo-floating point number with 13 bits of
    262  * mantissa and 3 bits of base 8 exponent and has resolution
    263  * of 1/AHZ seconds.
    264  */
    265 
    266 #define MANT		13			/* 13-bit mantissa */
    267 #define EXP		3			/* base 8 exponent */
    268 #define MAXFRACT	((1 << MANT) - 1)	/* max fract value */
    269 
    270 static comp_t
    271 encode_comp_t(s, us)
    272 	u_long s, us;
    273 {
    274 	int exp, rnd;
    275 
    276 	exp = 0;
    277 	rnd = 0;
    278 	s *= AHZ;
    279 	s += us / (1000000 / AHZ);		/* maximize precision */
    280 
    281 	while (s > MAXFRACT) {
    282 		rnd = s & (1 << (EXP-1));	/* round up? */
    283 		s >>= EXP;			/* base 8 exponent */
    284 		exp++;
    285 	}
    286 
    287 	/* if we need to round up, do it (and handle overflow correctly) */
    288 	if (rnd && (++s > MAXFRACT)) {
    289 		s >>= EXP;
    290 		exp++;
    291 	}
    292 
    293 	exp <<= MANT;			/* move the exponent */
    294 	exp += s;			/* add on the mantissa */
    295 	return (exp);
    296 }
    297