]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_acct.c
   2  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   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. 
  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 
  20  * @APPLE_LICENSE_HEADER_END@ 
  22 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ 
  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. 
  32  * Redistribution and use in source and binary forms, with or without 
  33  * modification, are permitted provided that the following conditions 
  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. 
  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 
  60  *      @(#)kern_acct.c 8.1 (Berkeley) 6/14/93 
  63  * 08-May-95  Mac Gillon (mgillon) at NeXT 
  65  *      New version based on 4.4 
  69 #include <sys/param.h> 
  70 #include <sys/proc_internal.h> 
  71 #include <sys/kauth.h> 
  72 #include <sys/mount_internal.h> 
  73 #include <sys/vnode_internal.h> 
  74 #include <sys/file_internal.h> 
  75 #include <sys/syslog.h> 
  76 #include <sys/kernel.h> 
  77 #include <sys/namei.h> 
  78 #include <sys/errno.h> 
  80 #include <sys/resourcevar.h> 
  81 #include <sys/ioctl.h> 
  83 #include <sys/sysproto.h> 
  84 #include <machine/spl.h> 
  87  * The routines implemented in this file are described in: 
  88  *      Leffler, et al.: The Design and Implementation of the 4.3BSD 
  89  *          UNIX Operating System (Addison Welley, 1989) 
  92  * Arguably, to simplify accounting operations, this mechanism should 
  93  * be replaced by one in which an accounting log file (similar to /dev/klog) 
  94  * is read by a user process, etc.  However, that has its own problems. 
  98  * Internal accounting functions. 
  99  * The former's operation is described in Leffler, et al., and the latter 
 100  * was provided by UCB with the 4.4BSD-Lite release 
 102 comp_t  
encode_comp_t(u_long
, u_long
); 
 103 void    acctwatch(void *); 
 104 void    acctwatch_funnel(void *); 
 107  * Accounting vnode pointer, and suspended accounting vnode pointer.  States 
 110  *      acctp           suspend_acctp   state 
 111  *      -------------   ------------    ------------------------------ 
 112  *      NULL            NULL            Accounting disabled 
 113  *      !NULL           NULL            Accounting enabled 
 114  *      NULL            !NULL           Accounting enabled, but suspended 
 115  *      !NULL           !NULL           <not allowed> 
 118 struct  vnode 
*suspend_acctp
; 
 121  * Values associated with enabling and disabling accounting 
 123 int     acctsuspend 
= 2;        /* stop accounting when < 2% free space left */ 
 124 int     acctresume 
= 4;         /* resume when free space risen to > 4% */ 
 125 int     acctchkfreq 
= 15;       /* frequency (in seconds) to check space */ 
 128  * Accounting system call.  Written based on the specification and 
 129  * previous implementation done by Mark Tinguely. 
 132 acct(struct proc 
*p
, struct acct_args 
*uap
, __unused 
int *retval
) 
 136         struct vfs_context context
; 
 139         context
.vc_ucred 
= kauth_cred_get(); 
 141         /* Make sure that the caller is root. */ 
 142         if ((error 
= suser(kauth_cred_get(), &p
->p_acflag
))) 
 146          * If accounting is to be started to a file, open that file for 
 147          * writing and make sure it's a 'normal'. 
 149         if (uap
->path 
!= USER_ADDR_NULL
) { 
 150                 NDINIT(&nd
, LOOKUP
, NOFOLLOW
, UIO_USERSPACE
, uap
->path
, &context
); 
 151                 if ((error 
= vn_open(&nd
, FWRITE
, 0))) 
 155                 if (nd
.ni_vp
->v_type 
!= VREG
) { 
 156                         vn_close(nd
.ni_vp
, FWRITE
, kauth_cred_get(), p
); 
 162          * If accounting was previously enabled, kill the old space-watcher, 
 163          * close the file, and (if no new file was specified, leave). 
 165         if (acctp 
!= NULLVP 
|| suspend_acctp 
!= NULLVP
) { 
 166                 untimeout(acctwatch_funnel
, NULL
); 
 167                 error 
= vn_close((acctp 
!= NULLVP 
? acctp 
: suspend_acctp
), FWRITE
, 
 168                     kauth_cred_get(), p
); 
 170                 acctp 
= suspend_acctp 
= NULLVP
; 
 172         if (uap
->path 
== USER_ADDR_NULL
) 
 176          * Save the new accounting file vnode, and schedule the new 
 177          * free space watcher. 
 185  * Write out process accounting information, on process exit. 
 186  * Data to be written out is specified in Leffler, et al. 
 187  * and are enumerated below.  (They're also noted in the system 
 188  * "acct.h" header file.) 
 196         struct timeval ut
, st
, tmp
; 
 201         /* If accounting isn't enabled, don't bother */ 
 207          * Get process accounting information. 
 210         /* (1) The name of the command that ran */ 
 211         bcopy(p
->p_comm
, an_acct
.ac_comm
, sizeof an_acct
.ac_comm
); 
 213         /* (2) The amount of user and system time that was used */ 
 214         calcru(p
, &ut
, &st
, NULL
); 
 215         an_acct
.ac_utime 
= encode_comp_t(ut
.tv_sec
, ut
.tv_usec
); 
 216         an_acct
.ac_stime 
= encode_comp_t(st
.tv_sec
, st
.tv_usec
); 
 218         /* (3) The elapsed time the commmand ran (and its starting time) */ 
 219         an_acct
.ac_btime 
= p
->p_stats
->p_start
.tv_sec
; 
 221         timevalsub(&tmp
, &p
->p_stats
->p_start
); 
 222         an_acct
.ac_etime 
= encode_comp_t(tmp
.tv_sec
, tmp
.tv_usec
); 
 224         /* (4) The average amount of memory used */ 
 225         r 
= &p
->p_stats
->p_ru
; 
 227         timevaladd(&tmp
, &st
); 
 228         t 
= tmp
.tv_sec 
* hz 
+ tmp
.tv_usec 
/ tick
; 
 230                 an_acct
.ac_mem 
= (r
->ru_ixrss 
+ r
->ru_idrss 
+ r
->ru_isrss
) / t
; 
 234         /* (5) The number of disk I/O operations done */ 
 235         an_acct
.ac_io 
= encode_comp_t(r
->ru_inblock 
+ r
->ru_oublock
, 0); 
 237         /* (6) The UID and GID of the process */ 
 238         an_acct
.ac_uid 
= p
->p_ucred
->cr_ruid
; 
 239         an_acct
.ac_gid 
= p
->p_ucred
->cr_rgid
; 
 241         /* (7) The terminal from which the process was started */ 
 242         if ((p
->p_flag 
& P_CONTROLT
) && p
->p_pgrp
->pg_session
->s_ttyp
) 
 243                 an_acct
.ac_tty 
= p
->p_pgrp
->pg_session
->s_ttyp
->t_dev
; 
 245                 an_acct
.ac_tty 
= NODEV
; 
 247         /* (8) The boolean flags that tell how the process terminated, etc. */ 
 248         an_acct
.ac_flag 
= p
->p_acflag
; 
 251          * Now, just write the accounting information to the file. 
 253         if ((error 
= vnode_getwithref(vp
)) == 0) { 
 254                 error 
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
)&an_acct
, sizeof (an_acct
), 
 255                                 (off_t
)0, UIO_SYSSPACE32
, IO_APPEND
|IO_UNIT
, p
->p_ucred
, 
 263  * Encode_comp_t converts from ticks in seconds and microseconds 
 264  * to ticks in 1/AHZ seconds.  The encoding is described in 
 265  * Leffler, et al., on page 63. 
 268 #define MANTSIZE        13                      /* 13 bit mantissa. */ 
 269 #define EXPSIZE         3                       /* Base 8 (3 bit) exponent. */ 
 270 #define MAXFRACT        ((1 << MANTSIZE) - 1)   /* Maximum fractional value. */ 
 281         s 
+= us 
/ (1000000 / AHZ
);      /* Maximize precision. */ 
 283         while (s 
> MAXFRACT
) { 
 284         rnd 
= s 
& (1 << (EXPSIZE 
- 1)); /* Round up? */ 
 285                 s 
>>= EXPSIZE
;          /* Base 8 exponent == 3 bit shift. */ 
 289         /* If we need to round up, do it (and handle overflow correctly). */ 
 290         if (rnd 
&& (++s 
> MAXFRACT
)) { 
 295         /* Clean it up and polish it off. */ 
 296         exp 
<<= MANTSIZE
;               /* Shift the exponent into place */ 
 297         exp 
+= s
;                       /* and add on the mantissa. */ 
 305         thread_funnel_set(kernel_flock
, TRUE
); 
 307         thread_funnel_set(kernel_flock
, FALSE
); 
 312  * Periodically check the file system to see if accounting 
 313  * should be turned on or off.  Beware the case where the vnode 
 314  * has been vgone()'d out from underneath us, e.g. when the file 
 315  * system containing the accounting file has been forcibly unmounted. 
 319 acctwatch(__unused 
void *a
) 
 321         struct vfs_context context
; 
 325         VFSATTR_WANTED(&va
, f_blocks
); 
 326         VFSATTR_WANTED(&va
, f_bavail
); 
 327         context
.vc_proc 
= current_proc(); 
 328         context
.vc_ucred 
= kauth_cred_get(); 
 330         if (suspend_acctp 
!= NULLVP
) { 
 332                  * Resuming accounting when accounting is suspended, and the 
 333                  * filesystem containing the suspended accounting file goes 
 334                  * below a low watermark 
 336                 if (suspend_acctp
->v_type 
== VBAD
) { 
 337                         (void) vn_close(suspend_acctp
, FWRITE
, NOCRED
, NULL
); 
 338                         suspend_acctp 
= NULLVP
; 
 341                 (void)vfs_getattr(suspend_acctp
->v_mount
, &va
, &context
); 
 342                 if (va
.f_bavail 
> acctresume 
* va
.f_blocks 
/ 100) { 
 343                         acctp 
= suspend_acctp
; 
 344                         suspend_acctp 
= NULLVP
; 
 345                         log(LOG_NOTICE
, "Accounting resumed\n"); 
 347         } else if (acctp 
!= NULLVP
) { 
 349                  * Suspending accounting when accounting is currently active, 
 350                  * and the filesystem containing the active accounting file 
 351                  * goes over a high watermark 
 353                 if (acctp
->v_type 
== VBAD
) { 
 354                         (void) vn_close(acctp
, FWRITE
, NOCRED
, NULL
); 
 358                 (void)vfs_getattr(acctp
->v_mount
, &va
, &context
); 
 359                 if (va
.f_bavail 
<= acctsuspend 
* va
.f_blocks 
/ 100) { 
 360                         suspend_acctp 
= acctp
; 
 362                         log(LOG_NOTICE
, "Accounting suspended\n"); 
 368         timeout(acctwatch_funnel
, NULL
, acctchkfreq 
* hz
);