10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*3446Smrj * Common Development and Distribution License (the "License"). 6*3446Smrj * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*3446Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 230Sstevel@tonic-gate * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 270Sstevel@tonic-gate /* All Rights Reserved */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate 300Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 310Sstevel@tonic-gate 320Sstevel@tonic-gate #include <sys/types.h> 330Sstevel@tonic-gate #include <sys/sysmacros.h> 340Sstevel@tonic-gate #include <sys/param.h> 350Sstevel@tonic-gate #include <sys/systm.h> 360Sstevel@tonic-gate #include <sys/acct.h> 370Sstevel@tonic-gate #include <sys/cred.h> 380Sstevel@tonic-gate #include <sys/user.h> 390Sstevel@tonic-gate #include <sys/errno.h> 400Sstevel@tonic-gate #include <sys/file.h> 410Sstevel@tonic-gate #include <sys/vnode.h> 420Sstevel@tonic-gate #include <sys/debug.h> 430Sstevel@tonic-gate #include <sys/proc.h> 440Sstevel@tonic-gate #include <sys/resource.h> 450Sstevel@tonic-gate #include <sys/session.h> 460Sstevel@tonic-gate #include <sys/modctl.h> 470Sstevel@tonic-gate #include <sys/syscall.h> 480Sstevel@tonic-gate #include <sys/policy.h> 490Sstevel@tonic-gate #include <sys/list.h> 500Sstevel@tonic-gate #include <sys/time.h> 510Sstevel@tonic-gate #include <sys/msacct.h> 520Sstevel@tonic-gate #include <sys/zone.h> 530Sstevel@tonic-gate 540Sstevel@tonic-gate /* 550Sstevel@tonic-gate * Each zone has its own accounting settings (on or off) and associated 560Sstevel@tonic-gate * file. The global zone is not special in this aspect; it will only 570Sstevel@tonic-gate * generate records for processes that ran in the global zone. We could 580Sstevel@tonic-gate * allow the global zone to record all activity on the system, but there 590Sstevel@tonic-gate * would be no way of knowing the zone in which the processes executed. 600Sstevel@tonic-gate * sysacct() is thus virtualized to only act on the caller's zone. 610Sstevel@tonic-gate */ 620Sstevel@tonic-gate struct acct_globals { 630Sstevel@tonic-gate struct acct acctbuf; 640Sstevel@tonic-gate kmutex_t aclock; 650Sstevel@tonic-gate struct vnode *acctvp; 660Sstevel@tonic-gate list_node_t aclink; 670Sstevel@tonic-gate }; 680Sstevel@tonic-gate 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * We need a list of all accounting settings for all zones, so we can 710Sstevel@tonic-gate * accurately determine if a file is in use for accounting (possibly by 720Sstevel@tonic-gate * another zone). 730Sstevel@tonic-gate */ 740Sstevel@tonic-gate static zone_key_t acct_zone_key; 750Sstevel@tonic-gate static list_t acct_list; 760Sstevel@tonic-gate kmutex_t acct_list_lock; 770Sstevel@tonic-gate 780Sstevel@tonic-gate static struct sysent acctsysent = { 790Sstevel@tonic-gate 1, 800Sstevel@tonic-gate SE_NOUNLOAD | SE_ARGC | SE_32RVAL1, 810Sstevel@tonic-gate sysacct 820Sstevel@tonic-gate }; 830Sstevel@tonic-gate 840Sstevel@tonic-gate static struct modlsys modlsys = { 850Sstevel@tonic-gate &mod_syscallops, "acct(2) syscall", &acctsysent 860Sstevel@tonic-gate }; 870Sstevel@tonic-gate 880Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 890Sstevel@tonic-gate static struct modlsys modlsys32 = { 900Sstevel@tonic-gate &mod_syscallops32, "32-bit acct(2) syscall", &acctsysent 910Sstevel@tonic-gate }; 920Sstevel@tonic-gate #endif 930Sstevel@tonic-gate 940Sstevel@tonic-gate static struct modlinkage modlinkage = { 950Sstevel@tonic-gate MODREV_1, 960Sstevel@tonic-gate &modlsys, 970Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 980Sstevel@tonic-gate &modlsys32, 990Sstevel@tonic-gate #endif 1000Sstevel@tonic-gate NULL 1010Sstevel@tonic-gate }; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /*ARGSUSED*/ 1040Sstevel@tonic-gate static void * 1050Sstevel@tonic-gate acct_init(zoneid_t zoneid) 1060Sstevel@tonic-gate { 1070Sstevel@tonic-gate struct acct_globals *ag; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate ag = kmem_alloc(sizeof (*ag), KM_SLEEP); 1100Sstevel@tonic-gate bzero(&ag->acctbuf, sizeof (ag->acctbuf)); 1110Sstevel@tonic-gate mutex_init(&ag->aclock, NULL, MUTEX_DEFAULT, NULL); 1120Sstevel@tonic-gate ag->acctvp = NULL; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate mutex_enter(&acct_list_lock); 1150Sstevel@tonic-gate list_insert_tail(&acct_list, ag); 1160Sstevel@tonic-gate mutex_exit(&acct_list_lock); 1170Sstevel@tonic-gate return (ag); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* ARGSUSED */ 1210Sstevel@tonic-gate static void 1220Sstevel@tonic-gate acct_shutdown(zoneid_t zoneid, void *arg) 1230Sstevel@tonic-gate { 1240Sstevel@tonic-gate struct acct_globals *ag = arg; 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate mutex_enter(&ag->aclock); 1270Sstevel@tonic-gate if (ag->acctvp) { 1280Sstevel@tonic-gate /* 1290Sstevel@tonic-gate * This needs to be done as a shutdown callback, otherwise this 1300Sstevel@tonic-gate * held vnode may cause filesystems to be busy, and the zone 1310Sstevel@tonic-gate * shutdown operation to fail. 1320Sstevel@tonic-gate */ 1330Sstevel@tonic-gate (void) VOP_CLOSE(ag->acctvp, FWRITE, 1, (offset_t)0, kcred); 1340Sstevel@tonic-gate VN_RELE(ag->acctvp); 1350Sstevel@tonic-gate } 1360Sstevel@tonic-gate ag->acctvp = NULL; 1370Sstevel@tonic-gate mutex_exit(&ag->aclock); 1380Sstevel@tonic-gate } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate /*ARGSUSED*/ 1410Sstevel@tonic-gate static void 1420Sstevel@tonic-gate acct_fini(zoneid_t zoneid, void *arg) 1430Sstevel@tonic-gate { 1440Sstevel@tonic-gate struct acct_globals *ag = arg; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate mutex_enter(&acct_list_lock); 1470Sstevel@tonic-gate list_remove(&acct_list, ag); 1480Sstevel@tonic-gate mutex_exit(&acct_list_lock); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate mutex_destroy(&ag->aclock); 1510Sstevel@tonic-gate kmem_free(ag, sizeof (*ag)); 1520Sstevel@tonic-gate } 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate int 1550Sstevel@tonic-gate _init(void) 1560Sstevel@tonic-gate { 1570Sstevel@tonic-gate int error; 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate mutex_init(&acct_list_lock, NULL, MUTEX_DEFAULT, NULL); 1600Sstevel@tonic-gate list_create(&acct_list, sizeof (struct acct_globals), 1610Sstevel@tonic-gate offsetof(struct acct_globals, aclink)); 1620Sstevel@tonic-gate /* 1630Sstevel@tonic-gate * Using an initializer here wastes a bit of memory for zones that 1640Sstevel@tonic-gate * don't use accounting, but vastly simplifies the locking. 1650Sstevel@tonic-gate */ 1660Sstevel@tonic-gate zone_key_create(&acct_zone_key, acct_init, acct_shutdown, acct_fini); 1670Sstevel@tonic-gate if ((error = mod_install(&modlinkage)) != 0) { 1680Sstevel@tonic-gate (void) zone_key_delete(acct_zone_key); 1690Sstevel@tonic-gate list_destroy(&acct_list); 1700Sstevel@tonic-gate mutex_destroy(&acct_list_lock); 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate return (error); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate int 1760Sstevel@tonic-gate _info(struct modinfo *modinfop) 1770Sstevel@tonic-gate { 1780Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* 1820Sstevel@tonic-gate * acct() is a "weak stub" routine called from exit(). 1830Sstevel@tonic-gate * Once this module has been loaded, we refuse to allow 1840Sstevel@tonic-gate * it to unload - otherwise accounting would quietly 1850Sstevel@tonic-gate * cease. See 1211661. It's possible to make this module 1860Sstevel@tonic-gate * unloadable but it's substantially safer not to bother. 1870Sstevel@tonic-gate */ 1880Sstevel@tonic-gate int 1890Sstevel@tonic-gate _fini(void) 1900Sstevel@tonic-gate { 1910Sstevel@tonic-gate return (EBUSY); 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate /* 1950Sstevel@tonic-gate * See if vp is in use by the accounting system on any zone. This does a deep 1960Sstevel@tonic-gate * comparison of vnodes such that a file and a lofs "shadow" node of it will 1970Sstevel@tonic-gate * appear to be the same. 1980Sstevel@tonic-gate * 1990Sstevel@tonic-gate * If 'compare_vfs' is true, the function will do a comparison of vfs_t's 2000Sstevel@tonic-gate * instead (ie, is the vfs_t on which the vnode resides in use by the 2010Sstevel@tonic-gate * accounting system in any zone). 2020Sstevel@tonic-gate * 2030Sstevel@tonic-gate * Returns 1 if found (in use), 0 otherwise. 2040Sstevel@tonic-gate */ 2050Sstevel@tonic-gate static int 2060Sstevel@tonic-gate acct_find(vnode_t *vp, boolean_t compare_vfs) 2070Sstevel@tonic-gate { 2080Sstevel@tonic-gate struct acct_globals *ag; 2090Sstevel@tonic-gate vnode_t *realvp; 2100Sstevel@tonic-gate 2110Sstevel@tonic-gate ASSERT(MUTEX_HELD(&acct_list_lock)); 2120Sstevel@tonic-gate ASSERT(vp != NULL); 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate if (VOP_REALVP(vp, &realvp)) 2150Sstevel@tonic-gate realvp = vp; 2160Sstevel@tonic-gate for (ag = list_head(&acct_list); ag != NULL; 2170Sstevel@tonic-gate ag = list_next(&acct_list, ag)) { 2180Sstevel@tonic-gate vnode_t *racctvp; 2190Sstevel@tonic-gate boolean_t found = B_FALSE; 2200Sstevel@tonic-gate 2210Sstevel@tonic-gate mutex_enter(&ag->aclock); 2220Sstevel@tonic-gate if (ag->acctvp == NULL) { 2230Sstevel@tonic-gate mutex_exit(&ag->aclock); 2240Sstevel@tonic-gate continue; 2250Sstevel@tonic-gate } 2260Sstevel@tonic-gate if (VOP_REALVP(ag->acctvp, &racctvp)) 2270Sstevel@tonic-gate racctvp = ag->acctvp; 2280Sstevel@tonic-gate if (compare_vfs) { 2290Sstevel@tonic-gate if (racctvp->v_vfsp == realvp->v_vfsp) 2300Sstevel@tonic-gate found = B_TRUE; 2310Sstevel@tonic-gate } else { 2320Sstevel@tonic-gate if (VN_CMP(realvp, racctvp)) 2330Sstevel@tonic-gate found = B_TRUE; 2340Sstevel@tonic-gate } 2350Sstevel@tonic-gate mutex_exit(&ag->aclock); 2360Sstevel@tonic-gate if (found) 2370Sstevel@tonic-gate return (1); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate return (0); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate 2420Sstevel@tonic-gate /* 2430Sstevel@tonic-gate * Returns 1 if the vfs that vnode resides on is in use for the accounting 2440Sstevel@tonic-gate * subsystem, 0 otherwise. 2450Sstevel@tonic-gate */ 2460Sstevel@tonic-gate int 2470Sstevel@tonic-gate acct_fs_in_use(vnode_t *vp) 2480Sstevel@tonic-gate { 2490Sstevel@tonic-gate int found; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate if (vp == NULL) 2520Sstevel@tonic-gate return (0); 2530Sstevel@tonic-gate mutex_enter(&acct_list_lock); 2540Sstevel@tonic-gate found = acct_find(vp, B_TRUE); 2550Sstevel@tonic-gate mutex_exit(&acct_list_lock); 2560Sstevel@tonic-gate return (found); 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* 2600Sstevel@tonic-gate * Perform process accounting functions. 2610Sstevel@tonic-gate */ 2620Sstevel@tonic-gate int 2630Sstevel@tonic-gate sysacct(char *fname) 2640Sstevel@tonic-gate { 2650Sstevel@tonic-gate struct acct_globals *ag; 2660Sstevel@tonic-gate struct vnode *vp; 2670Sstevel@tonic-gate int error = 0; 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate if (secpolicy_acct(CRED()) != 0) 2700Sstevel@tonic-gate return (set_errno(EPERM)); 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate ag = zone_getspecific(acct_zone_key, curproc->p_zone); 2730Sstevel@tonic-gate ASSERT(ag != NULL); 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate if (fname == NULL) { 2760Sstevel@tonic-gate /* 2770Sstevel@tonic-gate * Close the file and stop accounting. 2780Sstevel@tonic-gate */ 2790Sstevel@tonic-gate mutex_enter(&ag->aclock); 2800Sstevel@tonic-gate vp = ag->acctvp; 2810Sstevel@tonic-gate ag->acctvp = NULL; 2820Sstevel@tonic-gate mutex_exit(&ag->aclock); 2830Sstevel@tonic-gate if (vp) { 2840Sstevel@tonic-gate error = VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED()); 2850Sstevel@tonic-gate VN_RELE(vp); 2860Sstevel@tonic-gate } 2870Sstevel@tonic-gate return (error == 0 ? 0 : set_errno(error)); 2880Sstevel@tonic-gate } 2890Sstevel@tonic-gate 2900Sstevel@tonic-gate /* 2910Sstevel@tonic-gate * Either (a) open a new file and begin accounting -or- (b) 2920Sstevel@tonic-gate * switch accounting from an old to a new file. 2930Sstevel@tonic-gate * 2940Sstevel@tonic-gate * (Open the file without holding aclock in case it 2950Sstevel@tonic-gate * sleeps (holding the lock prevents process exit).) 2960Sstevel@tonic-gate */ 2970Sstevel@tonic-gate if ((error = vn_open(fname, UIO_USERSPACE, FWRITE, 2980Sstevel@tonic-gate 0, &vp, (enum create)0, 0)) != 0) { 2990Sstevel@tonic-gate /* SVID compliance */ 3000Sstevel@tonic-gate if (error == EISDIR) 3010Sstevel@tonic-gate error = EACCES; 3020Sstevel@tonic-gate return (set_errno(error)); 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate if (vp->v_type != VREG) { 3060Sstevel@tonic-gate error = EACCES; 3070Sstevel@tonic-gate } else { 3080Sstevel@tonic-gate mutex_enter(&acct_list_lock); 3090Sstevel@tonic-gate if (acct_find(vp, B_FALSE)) { 3100Sstevel@tonic-gate error = EBUSY; 3110Sstevel@tonic-gate } else { 3120Sstevel@tonic-gate mutex_enter(&ag->aclock); 3130Sstevel@tonic-gate if (ag->acctvp) { 3140Sstevel@tonic-gate vnode_t *oldvp; 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * close old acctvp, and point acct() 3180Sstevel@tonic-gate * at new file by swapping vp and acctvp 3190Sstevel@tonic-gate */ 3200Sstevel@tonic-gate oldvp = ag->acctvp; 3210Sstevel@tonic-gate ag->acctvp = vp; 3220Sstevel@tonic-gate vp = oldvp; 3230Sstevel@tonic-gate } else { 3240Sstevel@tonic-gate /* 3250Sstevel@tonic-gate * no existing file, start accounting .. 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate ag->acctvp = vp; 3280Sstevel@tonic-gate vp = NULL; 3290Sstevel@tonic-gate } 3300Sstevel@tonic-gate mutex_exit(&ag->aclock); 3310Sstevel@tonic-gate } 3320Sstevel@tonic-gate mutex_exit(&acct_list_lock); 3330Sstevel@tonic-gate } 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate if (vp) { 3360Sstevel@tonic-gate (void) VOP_CLOSE(vp, FWRITE, 1, (offset_t)0, CRED()); 3370Sstevel@tonic-gate VN_RELE(vp); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate return (error == 0 ? 0 : set_errno(error)); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate /* 3430Sstevel@tonic-gate * Produce a pseudo-floating point representation 3440Sstevel@tonic-gate * with 3 bits base-8 exponent, 13 bits fraction. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate static comp_t 3470Sstevel@tonic-gate acct_compress(ulong_t t) 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate int exp = 0, round = 0; 3500Sstevel@tonic-gate 3510Sstevel@tonic-gate while (t >= 8192) { 3520Sstevel@tonic-gate exp++; 3530Sstevel@tonic-gate round = t & 04; 3540Sstevel@tonic-gate t >>= 3; 3550Sstevel@tonic-gate } 3560Sstevel@tonic-gate if (round) { 3570Sstevel@tonic-gate t++; 3580Sstevel@tonic-gate if (t >= 8192) { 3590Sstevel@tonic-gate t >>= 3; 3600Sstevel@tonic-gate exp++; 3610Sstevel@tonic-gate } 3620Sstevel@tonic-gate } 3630Sstevel@tonic-gate #ifdef _LP64 3640Sstevel@tonic-gate if (exp > 7) { 3650Sstevel@tonic-gate /* prevent wraparound */ 3660Sstevel@tonic-gate t = 8191; 3670Sstevel@tonic-gate exp = 7; 3680Sstevel@tonic-gate } 3690Sstevel@tonic-gate #endif 3700Sstevel@tonic-gate return ((exp << 13) + t); 3710Sstevel@tonic-gate } 3720Sstevel@tonic-gate 3730Sstevel@tonic-gate /* 3740Sstevel@tonic-gate * On exit, write a record on the accounting file. 3750Sstevel@tonic-gate */ 3760Sstevel@tonic-gate void 3770Sstevel@tonic-gate acct(char st) 3780Sstevel@tonic-gate { 3790Sstevel@tonic-gate struct vnode *vp; 3800Sstevel@tonic-gate struct cred *cr; 3810Sstevel@tonic-gate struct proc *p; 382*3446Smrj user_t *ua; 3830Sstevel@tonic-gate struct vattr va; 3840Sstevel@tonic-gate ssize_t resid = 0; 3850Sstevel@tonic-gate int error; 3860Sstevel@tonic-gate struct acct_globals *ag; 3870Sstevel@tonic-gate 3880Sstevel@tonic-gate ag = zone_getspecific(acct_zone_key, curproc->p_zone); 3890Sstevel@tonic-gate 3900Sstevel@tonic-gate mutex_enter(&ag->aclock); 3910Sstevel@tonic-gate if ((vp = ag->acctvp) == NULL) { 3920Sstevel@tonic-gate mutex_exit(&ag->aclock); 3930Sstevel@tonic-gate return; 3940Sstevel@tonic-gate } 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate /* 3970Sstevel@tonic-gate * This only gets called from exit after all lwp's have exited so no 3980Sstevel@tonic-gate * cred locking is needed. 3990Sstevel@tonic-gate */ 4000Sstevel@tonic-gate p = curproc; 401*3446Smrj ua = PTOU(p); 402*3446Smrj bcopy(ua->u_comm, ag->acctbuf.ac_comm, sizeof (ag->acctbuf.ac_comm)); 403*3446Smrj ag->acctbuf.ac_btime = ua->u_start.tv_sec; 4041235Ssp92102 ag->acctbuf.ac_utime = acct_compress(NSEC_TO_TICK(p->p_acct[LMS_USER])); 4050Sstevel@tonic-gate ag->acctbuf.ac_stime = acct_compress( 4061235Ssp92102 NSEC_TO_TICK(p->p_acct[LMS_SYSTEM] + p->p_acct[LMS_TRAP])); 407*3446Smrj ag->acctbuf.ac_etime = acct_compress(lbolt - ua->u_ticks); 408*3446Smrj ag->acctbuf.ac_mem = acct_compress((ulong_t)ua->u_mem); 4090Sstevel@tonic-gate ag->acctbuf.ac_io = acct_compress((ulong_t)p->p_ru.ioch); 4100Sstevel@tonic-gate ag->acctbuf.ac_rw = acct_compress((ulong_t)(p->p_ru.inblock + 4110Sstevel@tonic-gate p->p_ru.oublock)); 4120Sstevel@tonic-gate cr = CRED(); 4130Sstevel@tonic-gate ag->acctbuf.ac_uid = crgetruid(cr); 4140Sstevel@tonic-gate ag->acctbuf.ac_gid = crgetrgid(cr); 4150Sstevel@tonic-gate (void) cmpldev(&ag->acctbuf.ac_tty, cttydev(p)); 4160Sstevel@tonic-gate ag->acctbuf.ac_stat = st; 417*3446Smrj ag->acctbuf.ac_flag = (ua->u_acflag | AEXPND); 4180Sstevel@tonic-gate 4190Sstevel@tonic-gate /* 4200Sstevel@tonic-gate * Save the size. If the write fails, reset the size to avoid 4210Sstevel@tonic-gate * corrupted acct files. 4220Sstevel@tonic-gate * 4230Sstevel@tonic-gate * Large Files: We deliberately prevent accounting files from 4240Sstevel@tonic-gate * exceeding the 2GB limit as none of the accounting commands are 4250Sstevel@tonic-gate * currently large file aware. 4260Sstevel@tonic-gate */ 4270Sstevel@tonic-gate va.va_mask = AT_SIZE; 4280Sstevel@tonic-gate if (VOP_GETATTR(vp, &va, 0, kcred) == 0) { 4290Sstevel@tonic-gate error = vn_rdwr(UIO_WRITE, vp, (caddr_t)&ag->acctbuf, 4300Sstevel@tonic-gate sizeof (ag->acctbuf), 0LL, UIO_SYSSPACE, FAPPEND, 4310Sstevel@tonic-gate (rlim64_t)MAXOFF32_T, kcred, &resid); 4320Sstevel@tonic-gate if (error || resid) 4330Sstevel@tonic-gate (void) VOP_SETATTR(vp, &va, 0, kcred, NULL); 4340Sstevel@tonic-gate } 4350Sstevel@tonic-gate mutex_exit(&ag->aclock); 4360Sstevel@tonic-gate } 437