xref: /onnv-gate/usr/src/uts/common/fs/proc/prvnops.c (revision 12072:2f8174ed4d92)
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
52789Sfrankho  * Common Development and Distribution License (the "License").
62789Sfrankho  * 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  */
2111940SRoger.Faulkner@Sun.COM 
220Sstevel@tonic-gate /*
23*12072SChris.Baumbauer@Oracle.COM  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
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 #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/param.h>
310Sstevel@tonic-gate #include <sys/time.h>
320Sstevel@tonic-gate #include <sys/cred.h>
330Sstevel@tonic-gate #include <sys/policy.h>
340Sstevel@tonic-gate #include <sys/debug.h>
350Sstevel@tonic-gate #include <sys/dirent.h>
360Sstevel@tonic-gate #include <sys/errno.h>
370Sstevel@tonic-gate #include <sys/file.h>
380Sstevel@tonic-gate #include <sys/inline.h>
390Sstevel@tonic-gate #include <sys/kmem.h>
400Sstevel@tonic-gate #include <sys/pathname.h>
410Sstevel@tonic-gate #include <sys/proc.h>
4211940SRoger.Faulkner@Sun.COM #include <sys/brand.h>
430Sstevel@tonic-gate #include <sys/signal.h>
440Sstevel@tonic-gate #include <sys/stat.h>
450Sstevel@tonic-gate #include <sys/sysmacros.h>
460Sstevel@tonic-gate #include <sys/systm.h>
470Sstevel@tonic-gate #include <sys/zone.h>
480Sstevel@tonic-gate #include <sys/uio.h>
490Sstevel@tonic-gate #include <sys/var.h>
500Sstevel@tonic-gate #include <sys/mode.h>
510Sstevel@tonic-gate #include <sys/poll.h>
520Sstevel@tonic-gate #include <sys/user.h>
530Sstevel@tonic-gate #include <sys/vfs.h>
543898Srsb #include <sys/vfs_opreg.h>
550Sstevel@tonic-gate #include <sys/gfs.h>
560Sstevel@tonic-gate #include <sys/vnode.h>
570Sstevel@tonic-gate #include <sys/fault.h>
580Sstevel@tonic-gate #include <sys/syscall.h>
590Sstevel@tonic-gate #include <sys/procfs.h>
600Sstevel@tonic-gate #include <sys/atomic.h>
610Sstevel@tonic-gate #include <sys/cmn_err.h>
620Sstevel@tonic-gate #include <sys/contract_impl.h>
630Sstevel@tonic-gate #include <sys/ctfs.h>
640Sstevel@tonic-gate #include <sys/avl.h>
650Sstevel@tonic-gate #include <fs/fs_subr.h>
660Sstevel@tonic-gate #include <vm/rm.h>
670Sstevel@tonic-gate #include <vm/as.h>
680Sstevel@tonic-gate #include <vm/seg.h>
690Sstevel@tonic-gate #include <vm/seg_vn.h>
700Sstevel@tonic-gate #include <vm/hat.h>
710Sstevel@tonic-gate #include <fs/proc/prdata.h>
720Sstevel@tonic-gate #if defined(__sparc)
730Sstevel@tonic-gate #include <sys/regset.h>
740Sstevel@tonic-gate #endif
750Sstevel@tonic-gate #if defined(__x86)
760Sstevel@tonic-gate #include <sys/sysi86.h>
770Sstevel@tonic-gate #endif
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate  * Created by prinit.
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate vnodeops_t *prvnodeops;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate  * Directory characteristics (patterned after the s5 file system).
860Sstevel@tonic-gate  */
870Sstevel@tonic-gate #define	PRROOTINO	2
880Sstevel@tonic-gate 
890Sstevel@tonic-gate #define	PRDIRSIZE	14
900Sstevel@tonic-gate struct prdirect {
910Sstevel@tonic-gate 	ushort_t	d_ino;
920Sstevel@tonic-gate 	char		d_name[PRDIRSIZE];
930Sstevel@tonic-gate };
940Sstevel@tonic-gate 
950Sstevel@tonic-gate #define	PRSDSIZE	(sizeof (struct prdirect))
960Sstevel@tonic-gate 
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate  * Directory characteristics.
990Sstevel@tonic-gate  */
1000Sstevel@tonic-gate typedef struct prdirent {
1010Sstevel@tonic-gate 	ino64_t		d_ino;		/* "inode number" of entry */
1020Sstevel@tonic-gate 	off64_t		d_off;		/* offset of disk directory entry */
1030Sstevel@tonic-gate 	unsigned short	d_reclen;	/* length of this record */
1040Sstevel@tonic-gate 	char		d_name[14];	/* name of file */
1050Sstevel@tonic-gate } prdirent_t;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate  * Contents of a /proc/<pid> directory.
1090Sstevel@tonic-gate  * Reuse d_ino field for the /proc file type.
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate static prdirent_t piddir[] = {
1120Sstevel@tonic-gate 	{ PR_PIDDIR,	 1 * sizeof (prdirent_t), sizeof (prdirent_t),
1130Sstevel@tonic-gate 		"." },
1140Sstevel@tonic-gate 	{ PR_PROCDIR,	 2 * sizeof (prdirent_t), sizeof (prdirent_t),
1150Sstevel@tonic-gate 		".." },
1160Sstevel@tonic-gate 	{ PR_AS,	 3 * sizeof (prdirent_t), sizeof (prdirent_t),
1170Sstevel@tonic-gate 		"as" },
1180Sstevel@tonic-gate 	{ PR_CTL,	 4 * sizeof (prdirent_t), sizeof (prdirent_t),
1190Sstevel@tonic-gate 		"ctl" },
1200Sstevel@tonic-gate 	{ PR_STATUS,	 5 * sizeof (prdirent_t), sizeof (prdirent_t),
1210Sstevel@tonic-gate 		"status" },
1220Sstevel@tonic-gate 	{ PR_LSTATUS,	 6 * sizeof (prdirent_t), sizeof (prdirent_t),
1230Sstevel@tonic-gate 		"lstatus" },
1240Sstevel@tonic-gate 	{ PR_PSINFO,	 7 * sizeof (prdirent_t), sizeof (prdirent_t),
1250Sstevel@tonic-gate 		"psinfo" },
1260Sstevel@tonic-gate 	{ PR_LPSINFO,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
1270Sstevel@tonic-gate 		"lpsinfo" },
1280Sstevel@tonic-gate 	{ PR_MAP,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
1290Sstevel@tonic-gate 		"map" },
1300Sstevel@tonic-gate 	{ PR_RMAP,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
1310Sstevel@tonic-gate 		"rmap" },
1320Sstevel@tonic-gate 	{ PR_XMAP,	11 * sizeof (prdirent_t), sizeof (prdirent_t),
1330Sstevel@tonic-gate 		"xmap" },
1340Sstevel@tonic-gate 	{ PR_CRED,	12 * sizeof (prdirent_t), sizeof (prdirent_t),
1350Sstevel@tonic-gate 		"cred" },
1360Sstevel@tonic-gate 	{ PR_SIGACT,	13 * sizeof (prdirent_t), sizeof (prdirent_t),
1370Sstevel@tonic-gate 		"sigact" },
1380Sstevel@tonic-gate 	{ PR_AUXV,	14 * sizeof (prdirent_t), sizeof (prdirent_t),
1390Sstevel@tonic-gate 		"auxv" },
1400Sstevel@tonic-gate 	{ PR_USAGE,	15 * sizeof (prdirent_t), sizeof (prdirent_t),
1410Sstevel@tonic-gate 		"usage" },
1420Sstevel@tonic-gate 	{ PR_LUSAGE,	16 * sizeof (prdirent_t), sizeof (prdirent_t),
1430Sstevel@tonic-gate 		"lusage" },
1440Sstevel@tonic-gate 	{ PR_PAGEDATA,	17 * sizeof (prdirent_t), sizeof (prdirent_t),
1450Sstevel@tonic-gate 		"pagedata" },
1460Sstevel@tonic-gate 	{ PR_WATCH,	18 * sizeof (prdirent_t), sizeof (prdirent_t),
1470Sstevel@tonic-gate 		"watch" },
1480Sstevel@tonic-gate 	{ PR_CURDIR,	19 * sizeof (prdirent_t), sizeof (prdirent_t),
1490Sstevel@tonic-gate 		"cwd" },
1500Sstevel@tonic-gate 	{ PR_ROOTDIR,	20 * sizeof (prdirent_t), sizeof (prdirent_t),
1510Sstevel@tonic-gate 		"root" },
1520Sstevel@tonic-gate 	{ PR_FDDIR,	21 * sizeof (prdirent_t), sizeof (prdirent_t),
1530Sstevel@tonic-gate 		"fd" },
1540Sstevel@tonic-gate 	{ PR_OBJECTDIR,	22 * sizeof (prdirent_t), sizeof (prdirent_t),
1550Sstevel@tonic-gate 		"object" },
1560Sstevel@tonic-gate 	{ PR_LWPDIR,	23 * sizeof (prdirent_t), sizeof (prdirent_t),
1570Sstevel@tonic-gate 		"lwp" },
1580Sstevel@tonic-gate 	{ PR_PRIV,	24 * sizeof (prdirent_t), sizeof (prdirent_t),
1590Sstevel@tonic-gate 		"priv" },
1600Sstevel@tonic-gate 	{ PR_PATHDIR,	25 * sizeof (prdirent_t), sizeof (prdirent_t),
1610Sstevel@tonic-gate 		"path" },
1620Sstevel@tonic-gate 	{ PR_CTDIR,	26 * sizeof (prdirent_t), sizeof (prdirent_t),
1630Sstevel@tonic-gate 		"contracts" },
1640Sstevel@tonic-gate #if defined(__x86)
1650Sstevel@tonic-gate 	{ PR_LDT,	27 * sizeof (prdirent_t), sizeof (prdirent_t),
1660Sstevel@tonic-gate 		"ldt" },
1670Sstevel@tonic-gate #endif
1680Sstevel@tonic-gate };
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate #define	NPIDDIRFILES	(sizeof (piddir) / sizeof (piddir[0]) - 2)
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate  * Contents of a /proc/<pid>/lwp/<lwpid> directory.
1740Sstevel@tonic-gate  */
1750Sstevel@tonic-gate static prdirent_t lwpiddir[] = {
1760Sstevel@tonic-gate 	{ PR_LWPIDDIR,	 1 * sizeof (prdirent_t), sizeof (prdirent_t),
1770Sstevel@tonic-gate 		"." },
1780Sstevel@tonic-gate 	{ PR_LWPDIR,	 2 * sizeof (prdirent_t), sizeof (prdirent_t),
1790Sstevel@tonic-gate 		".." },
1800Sstevel@tonic-gate 	{ PR_LWPCTL,	 3 * sizeof (prdirent_t), sizeof (prdirent_t),
1810Sstevel@tonic-gate 		"lwpctl" },
1820Sstevel@tonic-gate 	{ PR_LWPSTATUS,	 4 * sizeof (prdirent_t), sizeof (prdirent_t),
1830Sstevel@tonic-gate 		"lwpstatus" },
1840Sstevel@tonic-gate 	{ PR_LWPSINFO,	 5 * sizeof (prdirent_t), sizeof (prdirent_t),
1850Sstevel@tonic-gate 		"lwpsinfo" },
1860Sstevel@tonic-gate 	{ PR_LWPUSAGE,	 6 * sizeof (prdirent_t), sizeof (prdirent_t),
1870Sstevel@tonic-gate 		"lwpusage" },
1880Sstevel@tonic-gate 	{ PR_XREGS,	 7 * sizeof (prdirent_t), sizeof (prdirent_t),
1890Sstevel@tonic-gate 		"xregs" },
1900Sstevel@tonic-gate 	{ PR_TMPLDIR,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
1910Sstevel@tonic-gate 		"templates" },
1920Sstevel@tonic-gate #if defined(__sparc)
1930Sstevel@tonic-gate 	{ PR_GWINDOWS,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
1940Sstevel@tonic-gate 		"gwindows" },
1950Sstevel@tonic-gate 	{ PR_ASRS,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
1960Sstevel@tonic-gate 		"asrs" },
1970Sstevel@tonic-gate #endif
1980Sstevel@tonic-gate };
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate #define	NLWPIDDIRFILES	(sizeof (lwpiddir) / sizeof (lwpiddir[0]) - 2)
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * Span of entries in the array files (lstatus, lpsinfo, lusage).
2040Sstevel@tonic-gate  * We make the span larger than the size of the structure on purpose,
2050Sstevel@tonic-gate  * to make sure that programs cannot use the structure size by mistake.
2060Sstevel@tonic-gate  * Align _ILP32 structures at 8 bytes, _LP64 structures at 16 bytes.
2070Sstevel@tonic-gate  */
2080Sstevel@tonic-gate #ifdef _LP64
2090Sstevel@tonic-gate #define	LSPAN(type)	(round16(sizeof (type)) + 16)
2100Sstevel@tonic-gate #define	LSPAN32(type)	(round8(sizeof (type)) + 8)
2110Sstevel@tonic-gate #else
2120Sstevel@tonic-gate #define	LSPAN(type)	(round8(sizeof (type)) + 8)
2130Sstevel@tonic-gate #endif
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate static void rebuild_objdir(struct as *);
2160Sstevel@tonic-gate static void prfreecommon(prcommon_t *);
2175331Samw static int praccess(vnode_t *, int, int, cred_t *, caller_context_t *);
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate static int
propen(vnode_t ** vpp,int flag,cred_t * cr,caller_context_t * ct)2205331Samw propen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
2210Sstevel@tonic-gate {
2220Sstevel@tonic-gate 	vnode_t *vp = *vpp;
2230Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
2240Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_pcommon;
2250Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
2260Sstevel@tonic-gate 	vnode_t *rvp;
2270Sstevel@tonic-gate 	vtype_t vtype;
2280Sstevel@tonic-gate 	proc_t *p;
2290Sstevel@tonic-gate 	int error = 0;
2300Sstevel@tonic-gate 	prnode_t *npnp = NULL;
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	/*
2330Sstevel@tonic-gate 	 * Nothing to do for the /proc directory itself.
2340Sstevel@tonic-gate 	 */
2350Sstevel@tonic-gate 	if (type == PR_PROCDIR)
2360Sstevel@tonic-gate 		return (0);
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	/*
2390Sstevel@tonic-gate 	 * If we are opening an underlying mapped object, reject opens
2400Sstevel@tonic-gate 	 * for writing regardless of the objects's access modes.
2410Sstevel@tonic-gate 	 * If we are opening a file in the /proc/pid/fd directory,
2420Sstevel@tonic-gate 	 * reject the open for any but a regular file or directory.
2430Sstevel@tonic-gate 	 * Just do it if we are opening the current or root directory.
2440Sstevel@tonic-gate 	 */
2450Sstevel@tonic-gate 	switch (type) {
2460Sstevel@tonic-gate 	case PR_OBJECT:
2470Sstevel@tonic-gate 	case PR_FD:
2480Sstevel@tonic-gate 	case PR_CURDIR:
2490Sstevel@tonic-gate 	case PR_ROOTDIR:
2500Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
2510Sstevel@tonic-gate 		vtype = rvp->v_type;
2520Sstevel@tonic-gate 		if ((type == PR_OBJECT && (flag & FWRITE)) ||
2530Sstevel@tonic-gate 		    (type == PR_FD && vtype != VREG && vtype != VDIR))
2540Sstevel@tonic-gate 			error = EACCES;
2550Sstevel@tonic-gate 		else {
2560Sstevel@tonic-gate 			/*
2570Sstevel@tonic-gate 			 * Need to hold rvp since VOP_OPEN() may release it.
2580Sstevel@tonic-gate 			 */
2590Sstevel@tonic-gate 			VN_HOLD(rvp);
2605331Samw 			error = VOP_OPEN(&rvp, flag, cr, ct);
2610Sstevel@tonic-gate 			if (error) {
2620Sstevel@tonic-gate 				VN_RELE(rvp);
2630Sstevel@tonic-gate 			} else {
2640Sstevel@tonic-gate 				*vpp = rvp;
2650Sstevel@tonic-gate 				VN_RELE(vp);
2660Sstevel@tonic-gate 			}
2670Sstevel@tonic-gate 		}
2680Sstevel@tonic-gate 		return (error);
2690Sstevel@tonic-gate 	default:
2700Sstevel@tonic-gate 		break;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	/*
2740Sstevel@tonic-gate 	 * If we are opening the pagedata file, allocate a prnode now
2750Sstevel@tonic-gate 	 * to avoid calling kmem_alloc() while holding p->p_lock.
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	if (type == PR_PAGEDATA || type == PR_OPAGEDATA)
2780Sstevel@tonic-gate 		npnp = prgetnode(vp, type);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * If the process exists, lock it now.
2820Sstevel@tonic-gate 	 * Otherwise we have a race condition with prclose().
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	p = pr_p_lock(pnp);
2850Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
2860Sstevel@tonic-gate 	if (p == NULL) {
2870Sstevel@tonic-gate 		if (npnp != NULL)
2880Sstevel@tonic-gate 			prfreenode(npnp);
2890Sstevel@tonic-gate 		return (ENOENT);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc);
2920Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*
2950Sstevel@tonic-gate 	 * Maintain a count of opens for write.  Allow exactly one
2960Sstevel@tonic-gate 	 * O_WRITE|O_EXCL request and fail subsequent ones.
2970Sstevel@tonic-gate 	 * Don't fail opens of old (bletch!) /proc lwp files.
2980Sstevel@tonic-gate 	 * Special case for open by the process itself:
2990Sstevel@tonic-gate 	 * Always allow the open by self and discount this
3000Sstevel@tonic-gate 	 * open for other opens for writing.
3010Sstevel@tonic-gate 	 */
3020Sstevel@tonic-gate 	if (flag & FWRITE) {
3030Sstevel@tonic-gate 		if (p == curproc) {
3040Sstevel@tonic-gate 			pcp->prc_selfopens++;
3050Sstevel@tonic-gate 			pnp->pr_flags |= PR_ISSELF;
3060Sstevel@tonic-gate 		} else if (type == PR_LWPIDFILE) {
3070Sstevel@tonic-gate 			/* EMPTY */;
3080Sstevel@tonic-gate 		} else if (flag & FEXCL) {
3090Sstevel@tonic-gate 			if (pcp->prc_writers > pcp->prc_selfopens) {
3100Sstevel@tonic-gate 				error = EBUSY;
3110Sstevel@tonic-gate 				goto out;
3120Sstevel@tonic-gate 			}
3130Sstevel@tonic-gate 			/* semantic for old /proc interface */
3140Sstevel@tonic-gate 			if (type == PR_PIDDIR)
3150Sstevel@tonic-gate 				pcp->prc_flags |= PRC_EXCL;
3160Sstevel@tonic-gate 		} else if (pcp->prc_flags & PRC_EXCL) {
3170Sstevel@tonic-gate 			ASSERT(pcp->prc_writers > pcp->prc_selfopens);
3180Sstevel@tonic-gate 			error = secpolicy_proc_excl_open(cr);
3190Sstevel@tonic-gate 			if (error)
3200Sstevel@tonic-gate 				goto out;
3210Sstevel@tonic-gate 		}
3220Sstevel@tonic-gate 		pcp->prc_writers++;
3230Sstevel@tonic-gate 		/*
3240Sstevel@tonic-gate 		 * The vnode may have become invalid between the
3250Sstevel@tonic-gate 		 * VOP_LOOKUP() of the /proc vnode and the VOP_OPEN().
3260Sstevel@tonic-gate 		 * If so, do now what prinvalidate() should have done.
3270Sstevel@tonic-gate 		 */
3280Sstevel@tonic-gate 		if ((pnp->pr_flags & PR_INVAL) ||
3290Sstevel@tonic-gate 		    (type == PR_PIDDIR &&
3300Sstevel@tonic-gate 		    (VTOP(pnp->pr_pidfile)->pr_flags & PR_INVAL))) {
3310Sstevel@tonic-gate 			if (p != curproc)
3320Sstevel@tonic-gate 				pcp->prc_selfopens++;
3330Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens <= pcp->prc_writers);
3340Sstevel@tonic-gate 			if (pcp->prc_selfopens == pcp->prc_writers)
3350Sstevel@tonic-gate 				pcp->prc_flags &= ~PRC_EXCL;
3360Sstevel@tonic-gate 		}
3370Sstevel@tonic-gate 	}
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	/*
3400Sstevel@tonic-gate 	 * Do file-specific things.
3410Sstevel@tonic-gate 	 */
3420Sstevel@tonic-gate 	switch (type) {
3430Sstevel@tonic-gate 	default:
3440Sstevel@tonic-gate 		break;
3450Sstevel@tonic-gate 	case PR_PAGEDATA:
3460Sstevel@tonic-gate 	case PR_OPAGEDATA:
3470Sstevel@tonic-gate 		/*
3480Sstevel@tonic-gate 		 * Enable data collection for page data file;
3490Sstevel@tonic-gate 		 * get unique id from the hat layer.
3500Sstevel@tonic-gate 		 */
3510Sstevel@tonic-gate 		{
3520Sstevel@tonic-gate 			int id;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 			/*
3550Sstevel@tonic-gate 			 * Drop p->p_lock to call hat_startstat()
3560Sstevel@tonic-gate 			 */
3570Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3580Sstevel@tonic-gate 			if ((p->p_flag & SSYS) || p->p_as == &kas ||
3590Sstevel@tonic-gate 			    (id = hat_startstat(p->p_as)) == -1) {
3600Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3610Sstevel@tonic-gate 				error = ENOMEM;
3620Sstevel@tonic-gate 			} else if (pnp->pr_hatid == 0) {
3630Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3640Sstevel@tonic-gate 				pnp->pr_hatid = (uint_t)id;
3650Sstevel@tonic-gate 			} else {
3660Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3670Sstevel@tonic-gate 				/*
3680Sstevel@tonic-gate 				 * Use our newly allocated prnode.
3690Sstevel@tonic-gate 				 */
3700Sstevel@tonic-gate 				npnp->pr_hatid = (uint_t)id;
3710Sstevel@tonic-gate 				/*
3720Sstevel@tonic-gate 				 * prgetnode() initialized most of the prnode.
3730Sstevel@tonic-gate 				 * Duplicate the remainder.
3740Sstevel@tonic-gate 				 */
3750Sstevel@tonic-gate 				npnp->pr_ino = pnp->pr_ino;
3760Sstevel@tonic-gate 				npnp->pr_common = pnp->pr_common;
3770Sstevel@tonic-gate 				npnp->pr_pcommon = pnp->pr_pcommon;
3780Sstevel@tonic-gate 				npnp->pr_parent = pnp->pr_parent;
3790Sstevel@tonic-gate 				VN_HOLD(npnp->pr_parent);
3800Sstevel@tonic-gate 				npnp->pr_index = pnp->pr_index;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 				npnp->pr_next = p->p_plist;
3830Sstevel@tonic-gate 				p->p_plist = PTOV(npnp);
3840Sstevel@tonic-gate 
3850Sstevel@tonic-gate 				VN_RELE(PTOV(pnp));
3860Sstevel@tonic-gate 				pnp = npnp;
3870Sstevel@tonic-gate 				npnp = NULL;
3880Sstevel@tonic-gate 				*vpp = PTOV(pnp);
3890Sstevel@tonic-gate 			}
3900Sstevel@tonic-gate 		}
3910Sstevel@tonic-gate 		break;
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate out:
3950Sstevel@tonic-gate 	prunlock(pnp);
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	if (npnp != NULL)
3980Sstevel@tonic-gate 		prfreenode(npnp);
3990Sstevel@tonic-gate 	return (error);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate /* ARGSUSED */
4030Sstevel@tonic-gate static int
prclose(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)4045331Samw prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
4055331Samw 	caller_context_t *ct)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
4080Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_pcommon;
4090Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
4100Sstevel@tonic-gate 	proc_t *p;
4110Sstevel@tonic-gate 	kthread_t *t;
4120Sstevel@tonic-gate 	user_t *up;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * Nothing to do for the /proc directory itself.
4160Sstevel@tonic-gate 	 */
4170Sstevel@tonic-gate 	if (type == PR_PROCDIR)
4180Sstevel@tonic-gate 		return (0);
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	ASSERT(type != PR_OBJECT && type != PR_FD &&
4215663Sck153898 	    type != PR_CURDIR && type != PR_ROOTDIR);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	/*
4240Sstevel@tonic-gate 	 * If the process exists, lock it now.
4250Sstevel@tonic-gate 	 * Otherwise we have a race condition with propen().
4260Sstevel@tonic-gate 	 * Hold pr_pidlock across the reference to prc_selfopens,
4270Sstevel@tonic-gate 	 * and prc_writers in case there is no process anymore,
4280Sstevel@tonic-gate 	 * to cover the case of concurrent calls to prclose()
4290Sstevel@tonic-gate 	 * after the process has been reaped by freeproc().
4300Sstevel@tonic-gate 	 */
4310Sstevel@tonic-gate 	p = pr_p_lock(pnp);
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	/*
4340Sstevel@tonic-gate 	 * There is nothing more to do until the last close of
4350Sstevel@tonic-gate 	 * the file table entry except to clear the pr_owner
4360Sstevel@tonic-gate 	 * field of the prnode and notify any waiters
4370Sstevel@tonic-gate 	 * (their file descriptor may have just been closed).
4380Sstevel@tonic-gate 	 */
4390Sstevel@tonic-gate 	if (count > 1) {
4400Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
4410Sstevel@tonic-gate 		if (pnp->pr_owner == curproc && !fisopen(vp))
4420Sstevel@tonic-gate 			pnp->pr_owner = NULL;
4430Sstevel@tonic-gate 		if (p != NULL) {
4440Sstevel@tonic-gate 			prnotify(vp);
4450Sstevel@tonic-gate 			prunlock(pnp);
4460Sstevel@tonic-gate 		}
4470Sstevel@tonic-gate 		return (0);
4480Sstevel@tonic-gate 	}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 	/*
4510Sstevel@tonic-gate 	 * Decrement the count of self-opens for writing.
4520Sstevel@tonic-gate 	 * Decrement the total count of opens for writing.
4530Sstevel@tonic-gate 	 * Cancel exclusive opens when only self-opens remain.
4540Sstevel@tonic-gate 	 */
4550Sstevel@tonic-gate 	if (flag & FWRITE) {
4560Sstevel@tonic-gate 		/*
4570Sstevel@tonic-gate 		 * prc_selfopens also contains the count of
4580Sstevel@tonic-gate 		 * invalid writers.  See prinvalidate().
4590Sstevel@tonic-gate 		 */
4600Sstevel@tonic-gate 		if ((pnp->pr_flags & (PR_ISSELF|PR_INVAL)) ||
4610Sstevel@tonic-gate 		    (type == PR_PIDDIR &&
4620Sstevel@tonic-gate 		    (VTOP(pnp->pr_pidfile)->pr_flags & PR_INVAL))) {
4630Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens != 0);
4640Sstevel@tonic-gate 			--pcp->prc_selfopens;
4650Sstevel@tonic-gate 		}
4660Sstevel@tonic-gate 		ASSERT(pcp->prc_writers != 0);
4670Sstevel@tonic-gate 		if (--pcp->prc_writers == pcp->prc_selfopens)
4680Sstevel@tonic-gate 			pcp->prc_flags &= ~PRC_EXCL;
4690Sstevel@tonic-gate 	}
4700Sstevel@tonic-gate 	ASSERT(pcp->prc_writers >= pcp->prc_selfopens);
4710Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
4720Sstevel@tonic-gate 	if (pnp->pr_owner == curproc && !fisopen(vp))
4730Sstevel@tonic-gate 		pnp->pr_owner = NULL;
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/*
4760Sstevel@tonic-gate 	 * If there is no process, there is nothing more to do.
4770Sstevel@tonic-gate 	 */
4780Sstevel@tonic-gate 	if (p == NULL)
4790Sstevel@tonic-gate 		return (0);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc);
4820Sstevel@tonic-gate 	prnotify(vp);	/* notify waiters */
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate 	/*
4850Sstevel@tonic-gate 	 * Do file-specific things.
4860Sstevel@tonic-gate 	 */
4870Sstevel@tonic-gate 	switch (type) {
4880Sstevel@tonic-gate 	default:
4890Sstevel@tonic-gate 		break;
4900Sstevel@tonic-gate 	case PR_PAGEDATA:
4910Sstevel@tonic-gate 	case PR_OPAGEDATA:
4920Sstevel@tonic-gate 		/*
4930Sstevel@tonic-gate 		 * This is a page data file.
4940Sstevel@tonic-gate 		 * Free the hat level statistics.
4950Sstevel@tonic-gate 		 * Drop p->p_lock before calling hat_freestat().
4960Sstevel@tonic-gate 		 */
4970Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
4980Sstevel@tonic-gate 		if (p->p_as != &kas && pnp->pr_hatid != 0)
4990Sstevel@tonic-gate 			hat_freestat(p->p_as, pnp->pr_hatid);
5000Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
5010Sstevel@tonic-gate 		pnp->pr_hatid = 0;
5020Sstevel@tonic-gate 		break;
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * On last close of all writable file descriptors,
5070Sstevel@tonic-gate 	 * perform run-on-last-close and/or kill-on-last-close logic.
5080Sstevel@tonic-gate 	 * Can't do this is the /proc agent lwp still exists.
5090Sstevel@tonic-gate 	 */
5100Sstevel@tonic-gate 	if (pcp->prc_writers == 0 &&
5110Sstevel@tonic-gate 	    p->p_agenttp == NULL &&
5120Sstevel@tonic-gate 	    !(pcp->prc_flags & PRC_DESTROY) &&
5130Sstevel@tonic-gate 	    p->p_stat != SZOMB &&
5140Sstevel@tonic-gate 	    (p->p_proc_flag & (P_PR_RUNLCL|P_PR_KILLCL))) {
5150Sstevel@tonic-gate 		int killproc;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		/*
5180Sstevel@tonic-gate 		 * Cancel any watchpoints currently in effect.
5190Sstevel@tonic-gate 		 * The process might disappear during this operation.
5200Sstevel@tonic-gate 		 */
5210Sstevel@tonic-gate 		if (pr_cancel_watch(pnp) == NULL)
5220Sstevel@tonic-gate 			return (0);
5230Sstevel@tonic-gate 		/*
5240Sstevel@tonic-gate 		 * If any tracing flags are set, clear them.
5250Sstevel@tonic-gate 		 */
5260Sstevel@tonic-gate 		if (p->p_proc_flag & P_PR_TRACE) {
5270Sstevel@tonic-gate 			up = PTOU(p);
5280Sstevel@tonic-gate 			premptyset(&up->u_entrymask);
5290Sstevel@tonic-gate 			premptyset(&up->u_exitmask);
5300Sstevel@tonic-gate 			up->u_systrap = 0;
5310Sstevel@tonic-gate 		}
5320Sstevel@tonic-gate 		premptyset(&p->p_sigmask);
5330Sstevel@tonic-gate 		premptyset(&p->p_fltmask);
5340Sstevel@tonic-gate 		killproc = (p->p_proc_flag & P_PR_KILLCL);
5350Sstevel@tonic-gate 		p->p_proc_flag &= ~(P_PR_RUNLCL|P_PR_KILLCL|P_PR_TRACE);
5360Sstevel@tonic-gate 		/*
5370Sstevel@tonic-gate 		 * Cancel any outstanding single-step requests.
5380Sstevel@tonic-gate 		 */
5390Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
5400Sstevel@tonic-gate 			/*
5410Sstevel@tonic-gate 			 * Drop p_lock because prnostep() touches the stack.
5420Sstevel@tonic-gate 			 * The loop is safe because the process is P_PR_LOCK'd.
5430Sstevel@tonic-gate 			 */
5440Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
5450Sstevel@tonic-gate 			do {
5460Sstevel@tonic-gate 				prnostep(ttolwp(t));
5470Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
5480Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
5490Sstevel@tonic-gate 		}
5500Sstevel@tonic-gate 		/*
5510Sstevel@tonic-gate 		 * Set runnable all lwps stopped by /proc.
5520Sstevel@tonic-gate 		 */
5530Sstevel@tonic-gate 		if (killproc)
5540Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGKILL);
5550Sstevel@tonic-gate 		else
5560Sstevel@tonic-gate 			allsetrun(p);
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	prunlock(pnp);
5600Sstevel@tonic-gate 	return (0);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate /*
5640Sstevel@tonic-gate  * Array of read functions, indexed by /proc file type.
5650Sstevel@tonic-gate  */
5660Sstevel@tonic-gate static int pr_read_inval(), pr_read_as(), pr_read_status(),
5670Sstevel@tonic-gate 	pr_read_lstatus(), pr_read_psinfo(), pr_read_lpsinfo(),
5680Sstevel@tonic-gate 	pr_read_map(), pr_read_rmap(), pr_read_xmap(),
5690Sstevel@tonic-gate 	pr_read_cred(), pr_read_sigact(), pr_read_auxv(),
5700Sstevel@tonic-gate #if defined(__x86)
5710Sstevel@tonic-gate 	pr_read_ldt(),
5720Sstevel@tonic-gate #endif
5730Sstevel@tonic-gate 	pr_read_usage(), pr_read_lusage(), pr_read_pagedata(),
5740Sstevel@tonic-gate 	pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(),
5750Sstevel@tonic-gate 	pr_read_lwpusage(), pr_read_xregs(), pr_read_priv(),
5760Sstevel@tonic-gate #if defined(__sparc)
5770Sstevel@tonic-gate 	pr_read_gwindows(), pr_read_asrs(),
5780Sstevel@tonic-gate #endif
5790Sstevel@tonic-gate 	pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata();
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate static int (*pr_read_function[PR_NFILES])() = {
5820Sstevel@tonic-gate 	pr_read_inval,		/* /proc				*/
5830Sstevel@tonic-gate 	pr_read_inval,		/* /proc/self				*/
5840Sstevel@tonic-gate 	pr_read_piddir,		/* /proc/<pid> (old /proc read())	*/
5850Sstevel@tonic-gate 	pr_read_as,		/* /proc/<pid>/as			*/
5860Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/ctl			*/
5870Sstevel@tonic-gate 	pr_read_status,		/* /proc/<pid>/status			*/
5880Sstevel@tonic-gate 	pr_read_lstatus,	/* /proc/<pid>/lstatus			*/
5890Sstevel@tonic-gate 	pr_read_psinfo,		/* /proc/<pid>/psinfo			*/
5900Sstevel@tonic-gate 	pr_read_lpsinfo,	/* /proc/<pid>/lpsinfo			*/
5910Sstevel@tonic-gate 	pr_read_map,		/* /proc/<pid>/map			*/
5920Sstevel@tonic-gate 	pr_read_rmap,		/* /proc/<pid>/rmap			*/
5930Sstevel@tonic-gate 	pr_read_xmap,		/* /proc/<pid>/xmap			*/
5940Sstevel@tonic-gate 	pr_read_cred,		/* /proc/<pid>/cred			*/
5950Sstevel@tonic-gate 	pr_read_sigact,		/* /proc/<pid>/sigact			*/
5960Sstevel@tonic-gate 	pr_read_auxv,		/* /proc/<pid>/auxv			*/
5970Sstevel@tonic-gate #if defined(__x86)
5980Sstevel@tonic-gate 	pr_read_ldt,		/* /proc/<pid>/ldt			*/
5990Sstevel@tonic-gate #endif
6000Sstevel@tonic-gate 	pr_read_usage,		/* /proc/<pid>/usage			*/
6010Sstevel@tonic-gate 	pr_read_lusage,		/* /proc/<pid>/lusage			*/
6020Sstevel@tonic-gate 	pr_read_pagedata,	/* /proc/<pid>/pagedata			*/
6030Sstevel@tonic-gate 	pr_read_watch,		/* /proc/<pid>/watch			*/
6040Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/cwd			*/
6050Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/root			*/
6060Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd			*/
6070Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd/nn			*/
6080Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object			*/
6090Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object/xxx		*/
6100Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp			*/
6110Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>		*/
6120Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
6130Sstevel@tonic-gate 	pr_read_lwpstatus,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
6140Sstevel@tonic-gate 	pr_read_lwpsinfo,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
6150Sstevel@tonic-gate 	pr_read_lwpusage,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
6160Sstevel@tonic-gate 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
6170Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
6180Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
6190Sstevel@tonic-gate #if defined(__sparc)
6200Sstevel@tonic-gate 	pr_read_gwindows,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
6210Sstevel@tonic-gate 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
6220Sstevel@tonic-gate #endif
6230Sstevel@tonic-gate 	pr_read_priv,		/* /proc/<pid>/priv			*/
6240Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path			*/
6250Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path/xxx			*/
6260Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts		*/
6270Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts/<ctid>		*/
6280Sstevel@tonic-gate 	pr_read_pidfile,	/* old process file			*/
6290Sstevel@tonic-gate 	pr_read_pidfile,	/* old lwp file				*/
6300Sstevel@tonic-gate 	pr_read_opagedata,	/* old pagedata file			*/
6310Sstevel@tonic-gate };
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate /* ARGSUSED */
6340Sstevel@tonic-gate static int
pr_read_inval(prnode_t * pnp,uio_t * uiop)6350Sstevel@tonic-gate pr_read_inval(prnode_t *pnp, uio_t *uiop)
6360Sstevel@tonic-gate {
6370Sstevel@tonic-gate 	/*
6380Sstevel@tonic-gate 	 * No read() on any /proc directory, use getdents(2) instead.
6390Sstevel@tonic-gate 	 * Cannot read a control file either.
6400Sstevel@tonic-gate 	 * An underlying mapped object file cannot get here.
6410Sstevel@tonic-gate 	 */
6420Sstevel@tonic-gate 	return (EINVAL);
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate static int
pr_uioread(void * base,long count,uio_t * uiop)6460Sstevel@tonic-gate pr_uioread(void *base, long count, uio_t *uiop)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	int error = 0;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	ASSERT(count >= 0);
6510Sstevel@tonic-gate 	count -= uiop->uio_offset;
6520Sstevel@tonic-gate 	if (count > 0 && uiop->uio_offset >= 0) {
6530Sstevel@tonic-gate 		error = uiomove((char *)base + uiop->uio_offset,
6540Sstevel@tonic-gate 		    count, UIO_READ, uiop);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	return (error);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate static int
pr_read_as(prnode_t * pnp,uio_t * uiop)6610Sstevel@tonic-gate pr_read_as(prnode_t *pnp, uio_t *uiop)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate 	int error;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AS);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
6680Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
6690Sstevel@tonic-gate 		struct as *as = p->p_as;
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 		/*
6720Sstevel@tonic-gate 		 * /proc I/O cannot be done to a system process.
6730Sstevel@tonic-gate 		 * A 32-bit process cannot read a 64-bit process.
6740Sstevel@tonic-gate 		 */
6750Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || as == &kas) {
6760Sstevel@tonic-gate 			error = 0;
6770Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
6780Sstevel@tonic-gate 		} else if (curproc->p_model == DATAMODEL_ILP32 &&
6790Sstevel@tonic-gate 		    PROCESS_NOT_32BIT(p)) {
6800Sstevel@tonic-gate 			error = EOVERFLOW;
6810Sstevel@tonic-gate #endif
6820Sstevel@tonic-gate 		} else {
6830Sstevel@tonic-gate 			/*
6840Sstevel@tonic-gate 			 * We don't hold p_lock over an i/o operation because
6850Sstevel@tonic-gate 			 * that could lead to deadlock with the clock thread.
6860Sstevel@tonic-gate 			 */
6870Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
6880Sstevel@tonic-gate 			error = prusrio(p, UIO_READ, uiop, 0);
6890Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
6900Sstevel@tonic-gate 		}
6910Sstevel@tonic-gate 		prunlock(pnp);
6920Sstevel@tonic-gate 	}
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	return (error);
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate static int
pr_read_status(prnode_t * pnp,uio_t * uiop)6980Sstevel@tonic-gate pr_read_status(prnode_t *pnp, uio_t *uiop)
6990Sstevel@tonic-gate {
7000Sstevel@tonic-gate 	pstatus_t *sp;
7010Sstevel@tonic-gate 	int error;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_STATUS);
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	/*
7060Sstevel@tonic-gate 	 * We kmem_alloc() the pstatus structure because
7070Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
7080Sstevel@tonic-gate 	 */
7090Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
7100Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
711789Sahrens 		prgetstatus(pnp->pr_common->prc_proc, sp, VTOZONE(PTOV(pnp)));
7120Sstevel@tonic-gate 		prunlock(pnp);
7130Sstevel@tonic-gate 		error = pr_uioread(sp, sizeof (*sp), uiop);
7140Sstevel@tonic-gate 	}
7150Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
7160Sstevel@tonic-gate 	return (error);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate static int
pr_read_lstatus(prnode_t * pnp,uio_t * uiop)7200Sstevel@tonic-gate pr_read_lstatus(prnode_t *pnp, uio_t *uiop)
7210Sstevel@tonic-gate {
7220Sstevel@tonic-gate 	proc_t *p;
7230Sstevel@tonic-gate 	kthread_t *t;
7240Sstevel@tonic-gate 	lwpdir_t *ldp;
7250Sstevel@tonic-gate 	size_t size;
7260Sstevel@tonic-gate 	prheader_t *php;
7270Sstevel@tonic-gate 	lwpstatus_t *sp;
7280Sstevel@tonic-gate 	int error;
7290Sstevel@tonic-gate 	int nlwp;
7300Sstevel@tonic-gate 	int i;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LSTATUS);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
7350Sstevel@tonic-gate 		return (error);
7360Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
7370Sstevel@tonic-gate 	nlwp = p->p_lwpcnt;
7380Sstevel@tonic-gate 	size = sizeof (prheader_t) + nlwp * LSPAN(lwpstatus_t);
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
7410Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
7420Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
7430Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
7440Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
7450Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	php->pr_nent = nlwp;
7480Sstevel@tonic-gate 	php->pr_entsize = LSPAN(lwpstatus_t);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	sp = (lwpstatus_t *)(php + 1);
7510Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
7520Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
7530Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
7540Sstevel@tonic-gate 			continue;
755789Sahrens 		prgetlwpstatus(t, sp, VTOZONE(PTOV(pnp)));
7560Sstevel@tonic-gate 		sp = (lwpstatus_t *)((caddr_t)sp + LSPAN(lwpstatus_t));
7570Sstevel@tonic-gate 	}
7580Sstevel@tonic-gate 	prunlock(pnp);
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
7610Sstevel@tonic-gate 	kmem_free(php, size);
7620Sstevel@tonic-gate 	return (error);
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate static int
pr_read_psinfo(prnode_t * pnp,uio_t * uiop)7660Sstevel@tonic-gate pr_read_psinfo(prnode_t *pnp, uio_t *uiop)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	psinfo_t psinfo;
7690Sstevel@tonic-gate 	proc_t *p;
7700Sstevel@tonic-gate 	int error = 0;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PSINFO);
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	/*
7750Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
7760Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
7770Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
7780Sstevel@tonic-gate 	 */
7790Sstevel@tonic-gate 	p = pr_p_lock(pnp);
7800Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
7810Sstevel@tonic-gate 	if (p == NULL)
7820Sstevel@tonic-gate 		error = ENOENT;
7830Sstevel@tonic-gate 	else {
7840Sstevel@tonic-gate 		ASSERT(p == pnp->pr_common->prc_proc);
7850Sstevel@tonic-gate 		prgetpsinfo(p, &psinfo);
7860Sstevel@tonic-gate 		prunlock(pnp);
7870Sstevel@tonic-gate 		error = pr_uioread(&psinfo, sizeof (psinfo), uiop);
7880Sstevel@tonic-gate 	}
7890Sstevel@tonic-gate 	return (error);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate static int
pr_read_lpsinfo(prnode_t * pnp,uio_t * uiop)7930Sstevel@tonic-gate pr_read_lpsinfo(prnode_t *pnp, uio_t *uiop)
7940Sstevel@tonic-gate {
7950Sstevel@tonic-gate 	proc_t *p;
7960Sstevel@tonic-gate 	kthread_t *t;
7970Sstevel@tonic-gate 	lwpdir_t *ldp;
7980Sstevel@tonic-gate 	lwpent_t *lep;
7990Sstevel@tonic-gate 	size_t size;
8000Sstevel@tonic-gate 	prheader_t *php;
8010Sstevel@tonic-gate 	lwpsinfo_t *sp;
8020Sstevel@tonic-gate 	int error;
8030Sstevel@tonic-gate 	int nlwp;
8040Sstevel@tonic-gate 	int i;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LPSINFO);
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/*
8090Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
8100Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
8110Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
8120Sstevel@tonic-gate 	 */
8130Sstevel@tonic-gate 	p = pr_p_lock(pnp);
8140Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
8150Sstevel@tonic-gate 	if (p == NULL)
8160Sstevel@tonic-gate 		return (ENOENT);
8170Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
8180Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt + p->p_zombcnt) == 0) {
8190Sstevel@tonic-gate 		prunlock(pnp);
8200Sstevel@tonic-gate 		return (ENOENT);
8210Sstevel@tonic-gate 	}
8220Sstevel@tonic-gate 	size = sizeof (prheader_t) + nlwp * LSPAN(lwpsinfo_t);
8230Sstevel@tonic-gate 
8240Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
8250Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
8260Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
8270Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
8280Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
8290Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt + p->p_zombcnt);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	php->pr_nent = nlwp;
8320Sstevel@tonic-gate 	php->pr_entsize = LSPAN(lwpsinfo_t);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	sp = (lwpsinfo_t *)(php + 1);
8350Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
8360Sstevel@tonic-gate 		if ((lep = ldp->ld_entry) == NULL)
8370Sstevel@tonic-gate 			continue;
8380Sstevel@tonic-gate 		if ((t = lep->le_thread) != NULL)
8390Sstevel@tonic-gate 			prgetlwpsinfo(t, sp);
8400Sstevel@tonic-gate 		else {
8410Sstevel@tonic-gate 			bzero(sp, sizeof (*sp));
8420Sstevel@tonic-gate 			sp->pr_lwpid = lep->le_lwpid;
8430Sstevel@tonic-gate 			sp->pr_state = SZOMB;
8440Sstevel@tonic-gate 			sp->pr_sname = 'Z';
8450Sstevel@tonic-gate 			sp->pr_start.tv_sec = lep->le_start;
8460Sstevel@tonic-gate 			sp->pr_bindpro = PBIND_NONE;
8470Sstevel@tonic-gate 			sp->pr_bindpset = PS_NONE;
8480Sstevel@tonic-gate 		}
8490Sstevel@tonic-gate 		sp = (lwpsinfo_t *)((caddr_t)sp + LSPAN(lwpsinfo_t));
8500Sstevel@tonic-gate 	}
8510Sstevel@tonic-gate 	prunlock(pnp);
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
8540Sstevel@tonic-gate 	kmem_free(php, size);
8550Sstevel@tonic-gate 	return (error);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate static int
pr_read_map_common(prnode_t * pnp,uio_t * uiop,prnodetype_t type)8592789Sfrankho pr_read_map_common(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
8600Sstevel@tonic-gate {
8610Sstevel@tonic-gate 	proc_t *p;
8620Sstevel@tonic-gate 	struct as *as;
8632789Sfrankho 	list_t iolhead;
8640Sstevel@tonic-gate 	int error;
8650Sstevel@tonic-gate 
866*12072SChris.Baumbauer@Oracle.COM readmap_common:
8670Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
8680Sstevel@tonic-gate 		return (error);
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
8710Sstevel@tonic-gate 	as = p->p_as;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
8740Sstevel@tonic-gate 		prunlock(pnp);
8750Sstevel@tonic-gate 		return (0);
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
878*12072SChris.Baumbauer@Oracle.COM 	if (!AS_LOCK_TRYENTER(as, &as->a_lock, RW_WRITER)) {
879*12072SChris.Baumbauer@Oracle.COM 		prunlock(pnp);
880*12072SChris.Baumbauer@Oracle.COM 		delay(1);
881*12072SChris.Baumbauer@Oracle.COM 		goto readmap_common;
882*12072SChris.Baumbauer@Oracle.COM 	}
8830Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
884*12072SChris.Baumbauer@Oracle.COM 
8852789Sfrankho 	switch (type) {
8862789Sfrankho 	case PR_XMAP:
8872789Sfrankho 		error = prgetxmap(p, &iolhead);
8882789Sfrankho 		break;
8892789Sfrankho 	case PR_RMAP:
8902789Sfrankho 		error = prgetmap(p, 1, &iolhead);
8912789Sfrankho 		break;
8922789Sfrankho 	case PR_MAP:
8932789Sfrankho 		error = prgetmap(p, 0, &iolhead);
8942789Sfrankho 		break;
8952789Sfrankho 	}
896*12072SChris.Baumbauer@Oracle.COM 
8970Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
8980Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
8990Sstevel@tonic-gate 	prunlock(pnp);
9000Sstevel@tonic-gate 
9012789Sfrankho 	error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
9022789Sfrankho 
9030Sstevel@tonic-gate 	return (error);
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate static int
pr_read_map(prnode_t * pnp,uio_t * uiop)9070Sstevel@tonic-gate pr_read_map(prnode_t *pnp, uio_t *uiop)
9080Sstevel@tonic-gate {
9090Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_MAP);
9102789Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
9110Sstevel@tonic-gate }
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate static int
pr_read_rmap(prnode_t * pnp,uio_t * uiop)9140Sstevel@tonic-gate pr_read_rmap(prnode_t *pnp, uio_t *uiop)
9150Sstevel@tonic-gate {
9160Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_RMAP);
9172789Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate static int
pr_read_xmap(prnode_t * pnp,uio_t * uiop)9210Sstevel@tonic-gate pr_read_xmap(prnode_t *pnp, uio_t *uiop)
9220Sstevel@tonic-gate {
9230Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XMAP);
9242789Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate static int
pr_read_cred(prnode_t * pnp,uio_t * uiop)9280Sstevel@tonic-gate pr_read_cred(prnode_t *pnp, uio_t *uiop)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate 	proc_t *p;
9310Sstevel@tonic-gate 	prcred_t *pcrp;
9320Sstevel@tonic-gate 	int error;
9330Sstevel@tonic-gate 	size_t count;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_CRED);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	/*
9380Sstevel@tonic-gate 	 * We kmem_alloc() the prcred_t structure because
9390Sstevel@tonic-gate 	 * the number of supplementary groups is variable.
9400Sstevel@tonic-gate 	 */
9410Sstevel@tonic-gate 	pcrp =
9420Sstevel@tonic-gate 	    kmem_alloc(sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1),
9430Sstevel@tonic-gate 	    KM_SLEEP);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
9460Sstevel@tonic-gate 		goto out;
9470Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
9480Sstevel@tonic-gate 	ASSERT(p != NULL);
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 	prgetcred(p, pcrp);
9510Sstevel@tonic-gate 	prunlock(pnp);
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate 	count = sizeof (prcred_t);
9540Sstevel@tonic-gate 	if (pcrp->pr_ngroups > 1)
9550Sstevel@tonic-gate 		count += sizeof (gid_t) * (pcrp->pr_ngroups - 1);
9560Sstevel@tonic-gate 	error = pr_uioread(pcrp, count, uiop);
9570Sstevel@tonic-gate out:
9580Sstevel@tonic-gate 	kmem_free(pcrp, sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1));
9590Sstevel@tonic-gate 	return (error);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate static int
pr_read_priv(prnode_t * pnp,uio_t * uiop)9630Sstevel@tonic-gate pr_read_priv(prnode_t *pnp, uio_t *uiop)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate 	proc_t *p;
9660Sstevel@tonic-gate 	size_t psize = prgetprivsize();
9670Sstevel@tonic-gate 	prpriv_t *ppriv = kmem_alloc(psize, KM_SLEEP);
9680Sstevel@tonic-gate 	int error;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PRIV);
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
9730Sstevel@tonic-gate 		goto out;
9740Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
9750Sstevel@tonic-gate 	ASSERT(p != NULL);
9760Sstevel@tonic-gate 
9770Sstevel@tonic-gate 	prgetpriv(p, ppriv);
9780Sstevel@tonic-gate 	prunlock(pnp);
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	error = pr_uioread(ppriv, psize, uiop);
9810Sstevel@tonic-gate out:
9820Sstevel@tonic-gate 	kmem_free(ppriv, psize);
9830Sstevel@tonic-gate 	return (error);
9840Sstevel@tonic-gate }
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate static int
pr_read_sigact(prnode_t * pnp,uio_t * uiop)9870Sstevel@tonic-gate pr_read_sigact(prnode_t *pnp, uio_t *uiop)
9880Sstevel@tonic-gate {
98911940SRoger.Faulkner@Sun.COM 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
9900Sstevel@tonic-gate 	proc_t *p;
9910Sstevel@tonic-gate 	struct sigaction *sap;
9920Sstevel@tonic-gate 	int sig;
9930Sstevel@tonic-gate 	int error;
9940Sstevel@tonic-gate 	user_t *up;
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_SIGACT);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	/*
9990Sstevel@tonic-gate 	 * We kmem_alloc() the sigaction array because
10000Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
10010Sstevel@tonic-gate 	 */
100211940SRoger.Faulkner@Sun.COM 	sap = kmem_alloc((nsig-1) * sizeof (struct sigaction), KM_SLEEP);
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10050Sstevel@tonic-gate 		goto out;
10060Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10070Sstevel@tonic-gate 	ASSERT(p != NULL);
10080Sstevel@tonic-gate 
100911940SRoger.Faulkner@Sun.COM 	if (uiop->uio_offset >= (nsig-1)*sizeof (struct sigaction)) {
10100Sstevel@tonic-gate 		prunlock(pnp);
10110Sstevel@tonic-gate 		goto out;
10120Sstevel@tonic-gate 	}
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	up = PTOU(p);
101511940SRoger.Faulkner@Sun.COM 	for (sig = 1; sig < nsig; sig++)
10160Sstevel@tonic-gate 		prgetaction(p, up, sig, &sap[sig-1]);
10170Sstevel@tonic-gate 	prunlock(pnp);
10180Sstevel@tonic-gate 
101911940SRoger.Faulkner@Sun.COM 	error = pr_uioread(sap, (nsig - 1) * sizeof (struct sigaction), uiop);
10200Sstevel@tonic-gate out:
102111940SRoger.Faulkner@Sun.COM 	kmem_free(sap, (nsig-1) * sizeof (struct sigaction));
10220Sstevel@tonic-gate 	return (error);
10230Sstevel@tonic-gate }
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate static int
pr_read_auxv(prnode_t * pnp,uio_t * uiop)10260Sstevel@tonic-gate pr_read_auxv(prnode_t *pnp, uio_t *uiop)
10270Sstevel@tonic-gate {
10280Sstevel@tonic-gate 	auxv_t auxv[__KERN_NAUXV_IMPL];
10290Sstevel@tonic-gate 	proc_t *p;
10300Sstevel@tonic-gate 	user_t *up;
10310Sstevel@tonic-gate 	int error;
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AUXV);
10340Sstevel@tonic-gate 
10350Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10360Sstevel@tonic-gate 		return (error);
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (auxv)) {
10390Sstevel@tonic-gate 		prunlock(pnp);
10400Sstevel@tonic-gate 		return (0);
10410Sstevel@tonic-gate 	}
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10440Sstevel@tonic-gate 	up = PTOU(p);
10450Sstevel@tonic-gate 	bcopy(up->u_auxv, auxv, sizeof (auxv));
10460Sstevel@tonic-gate 	prunlock(pnp);
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 	return (pr_uioread(auxv, sizeof (auxv), uiop));
10490Sstevel@tonic-gate }
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate #if defined(__x86)
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate  * XX64
10540Sstevel@tonic-gate  *	This is almost certainly broken for the amd64 kernel, because
10550Sstevel@tonic-gate  *	we have two kinds of LDT structures to export -- one for compatibility
10560Sstevel@tonic-gate  *	mode, and one for long mode, sigh.
10570Sstevel@tonic-gate  *
10580Sstevel@tonic-gate  * 	For now lets just have a ldt of size 0 for 64-bit processes.
10590Sstevel@tonic-gate  */
10600Sstevel@tonic-gate static int
pr_read_ldt(prnode_t * pnp,uio_t * uiop)10610Sstevel@tonic-gate pr_read_ldt(prnode_t *pnp, uio_t *uiop)
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate 	proc_t *p;
10640Sstevel@tonic-gate 	struct ssd *ssd;
10650Sstevel@tonic-gate 	size_t size;
10660Sstevel@tonic-gate 	int error;
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LDT);
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10710Sstevel@tonic-gate 		return (error);
10720Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
10750Sstevel@tonic-gate 	mutex_enter(&p->p_ldtlock);
10760Sstevel@tonic-gate 	size = prnldt(p) * sizeof (struct ssd);
10770Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
10780Sstevel@tonic-gate 		mutex_exit(&p->p_ldtlock);
10790Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
10800Sstevel@tonic-gate 		prunlock(pnp);
10810Sstevel@tonic-gate 		return (0);
10820Sstevel@tonic-gate 	}
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate 	ssd = kmem_alloc(size, KM_SLEEP);
10850Sstevel@tonic-gate 	prgetldt(p, ssd);
10860Sstevel@tonic-gate 	mutex_exit(&p->p_ldtlock);
10870Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10880Sstevel@tonic-gate 	prunlock(pnp);
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	error = pr_uioread(ssd, size, uiop);
10910Sstevel@tonic-gate 	kmem_free(ssd, size);
10920Sstevel@tonic-gate 	return (error);
10930Sstevel@tonic-gate }
10940Sstevel@tonic-gate #endif	/* __x86 */
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate static int
pr_read_usage(prnode_t * pnp,uio_t * uiop)10970Sstevel@tonic-gate pr_read_usage(prnode_t *pnp, uio_t *uiop)
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate 	prhusage_t *pup;
11000Sstevel@tonic-gate 	prusage_t *upup;
11010Sstevel@tonic-gate 	proc_t *p;
11020Sstevel@tonic-gate 	kthread_t *t;
11030Sstevel@tonic-gate 	int error;
11040Sstevel@tonic-gate 
11050Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_USAGE);
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	/* allocate now, before locking the process */
11080Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
11090Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	/*
11120Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
11130Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
11140Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
11150Sstevel@tonic-gate 	 */
11160Sstevel@tonic-gate 	p = pr_p_lock(pnp);
11170Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
11180Sstevel@tonic-gate 	if (p == NULL) {
11190Sstevel@tonic-gate 		error = ENOENT;
11200Sstevel@tonic-gate 		goto out;
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
11230Sstevel@tonic-gate 
11240Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage_t)) {
11250Sstevel@tonic-gate 		prunlock(pnp);
11260Sstevel@tonic-gate 		error = 0;
11270Sstevel@tonic-gate 		goto out;
11280Sstevel@tonic-gate 	}
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
11330Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
11340Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
11370Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
11380Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
11390Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
11400Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
11410Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
11420Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
11430Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
11440Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
11450Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
11460Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
11490Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
11500Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
11510Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
11520Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
11530Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
11540Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
11550Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
11560Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
11570Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
11580Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
11590Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	/*
11620Sstevel@tonic-gate 	 * Add the usage information for each active lwp.
11630Sstevel@tonic-gate 	 */
11640Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL &&
11650Sstevel@tonic-gate 	    !(pnp->pr_pcommon->prc_flags & PRC_DESTROY)) {
11660Sstevel@tonic-gate 		do {
11670Sstevel@tonic-gate 			if (t->t_proc_flag & TP_LWPEXIT)
11680Sstevel@tonic-gate 				continue;
11690Sstevel@tonic-gate 			pup->pr_count++;
11700Sstevel@tonic-gate 			praddusage(t, pup);
11710Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
11720Sstevel@tonic-gate 	}
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	prunlock(pnp);
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 	prcvtusage(pup, upup);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage_t), uiop);
11790Sstevel@tonic-gate out:
11800Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
11810Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
11820Sstevel@tonic-gate 	return (error);
11830Sstevel@tonic-gate }
11840Sstevel@tonic-gate 
11850Sstevel@tonic-gate static int
pr_read_lusage(prnode_t * pnp,uio_t * uiop)11860Sstevel@tonic-gate pr_read_lusage(prnode_t *pnp, uio_t *uiop)
11870Sstevel@tonic-gate {
11880Sstevel@tonic-gate 	int nlwp;
11890Sstevel@tonic-gate 	prhusage_t *pup;
11900Sstevel@tonic-gate 	prheader_t *php;
11910Sstevel@tonic-gate 	prusage_t *upup;
11920Sstevel@tonic-gate 	size_t size;
11930Sstevel@tonic-gate 	hrtime_t curtime;
11940Sstevel@tonic-gate 	proc_t *p;
11950Sstevel@tonic-gate 	kthread_t *t;
11960Sstevel@tonic-gate 	lwpdir_t *ldp;
11970Sstevel@tonic-gate 	int error;
11980Sstevel@tonic-gate 	int i;
11990Sstevel@tonic-gate 
12000Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LUSAGE);
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	/*
12030Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
12040Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
12050Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
12060Sstevel@tonic-gate 	 */
12070Sstevel@tonic-gate 	p = pr_p_lock(pnp);
12080Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
12090Sstevel@tonic-gate 	if (p == NULL)
12100Sstevel@tonic-gate 		return (ENOENT);
12110Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
12120Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt) == 0) {
12130Sstevel@tonic-gate 		prunlock(pnp);
12140Sstevel@tonic-gate 		return (ENOENT);
12150Sstevel@tonic-gate 	}
12160Sstevel@tonic-gate 
12170Sstevel@tonic-gate 	size = sizeof (prheader_t) + (nlwp + 1) * LSPAN(prusage_t);
12180Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
12190Sstevel@tonic-gate 		prunlock(pnp);
12200Sstevel@tonic-gate 		return (0);
12210Sstevel@tonic-gate 	}
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
12240Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
12250Sstevel@tonic-gate 	pup = kmem_zalloc(size + sizeof (prhusage_t), KM_SLEEP);
12260Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
12270Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
12280Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	php = (prheader_t *)(pup + 1);
12310Sstevel@tonic-gate 	upup = (prusage_t *)(php + 1);
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	php->pr_nent = nlwp + 1;
12340Sstevel@tonic-gate 	php->pr_entsize = LSPAN(prusage_t);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	curtime = gethrtime();
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	/*
12390Sstevel@tonic-gate 	 * First the summation over defunct lwps.
12400Sstevel@tonic-gate 	 */
12410Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
12420Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
12430Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
12440Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
12470Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
12480Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
12490Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
12500Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
12510Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
12520Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
12530Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
12540Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
12550Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
12560Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
12590Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
12600Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
12610Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
12620Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
12630Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
12640Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
12650Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
12660Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
12670Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
12680Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
12690Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 	prcvtusage(pup, upup);
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	/*
12740Sstevel@tonic-gate 	 * Fill one prusage struct for each active lwp.
12750Sstevel@tonic-gate 	 */
12760Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
12770Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
12780Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
12790Sstevel@tonic-gate 			continue;
12800Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
12810Sstevel@tonic-gate 		ASSERT(nlwp > 0);
12820Sstevel@tonic-gate 		--nlwp;
12830Sstevel@tonic-gate 		upup = (prusage_t *)((caddr_t)upup + LSPAN(prusage_t));
12840Sstevel@tonic-gate 		prgetusage(t, pup);
12850Sstevel@tonic-gate 		prcvtusage(pup, upup);
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 	ASSERT(nlwp == 0);
12880Sstevel@tonic-gate 
12890Sstevel@tonic-gate 	prunlock(pnp);
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
12920Sstevel@tonic-gate 	kmem_free(pup, size + sizeof (prhusage_t));
12930Sstevel@tonic-gate 	return (error);
12940Sstevel@tonic-gate }
12950Sstevel@tonic-gate 
12960Sstevel@tonic-gate static int
pr_read_pagedata(prnode_t * pnp,uio_t * uiop)12970Sstevel@tonic-gate pr_read_pagedata(prnode_t *pnp, uio_t *uiop)
12980Sstevel@tonic-gate {
12990Sstevel@tonic-gate 	proc_t *p;
13000Sstevel@tonic-gate 	int error;
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PAGEDATA);
13030Sstevel@tonic-gate 
13040Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
13050Sstevel@tonic-gate 		return (error);
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
13080Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
13090Sstevel@tonic-gate 		prunlock(pnp);
13100Sstevel@tonic-gate 		return (0);
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13140Sstevel@tonic-gate 	error = prpdread(p, pnp->pr_hatid, uiop);
13150Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate 	prunlock(pnp);
13180Sstevel@tonic-gate 	return (error);
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate static int
pr_read_opagedata(prnode_t * pnp,uio_t * uiop)13220Sstevel@tonic-gate pr_read_opagedata(prnode_t *pnp, uio_t *uiop)
13230Sstevel@tonic-gate {
13240Sstevel@tonic-gate 	proc_t *p;
13250Sstevel@tonic-gate 	struct as *as;
13260Sstevel@tonic-gate 	int error;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OPAGEDATA);
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
13310Sstevel@tonic-gate 		return (error);
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
13340Sstevel@tonic-gate 	as = p->p_as;
13350Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
13360Sstevel@tonic-gate 		prunlock(pnp);
13370Sstevel@tonic-gate 		return (0);
13380Sstevel@tonic-gate 	}
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13410Sstevel@tonic-gate 	error = oprpdread(as, pnp->pr_hatid, uiop);
13420Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	prunlock(pnp);
13450Sstevel@tonic-gate 	return (error);
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate static int
pr_read_watch(prnode_t * pnp,uio_t * uiop)13490Sstevel@tonic-gate pr_read_watch(prnode_t *pnp, uio_t *uiop)
13500Sstevel@tonic-gate {
13510Sstevel@tonic-gate 	proc_t *p;
13520Sstevel@tonic-gate 	int error;
13530Sstevel@tonic-gate 	prwatch_t *Bpwp;
13540Sstevel@tonic-gate 	size_t size;
13550Sstevel@tonic-gate 	prwatch_t *pwp;
13560Sstevel@tonic-gate 	int nwarea;
13570Sstevel@tonic-gate 	struct watched_area *pwarea;
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_WATCH);
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
13620Sstevel@tonic-gate 		return (error);
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
13650Sstevel@tonic-gate 	nwarea = avl_numnodes(&p->p_warea);
13660Sstevel@tonic-gate 	size = nwarea * sizeof (prwatch_t);
13670Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
13680Sstevel@tonic-gate 		prunlock(pnp);
13690Sstevel@tonic-gate 		return (0);
13700Sstevel@tonic-gate 	}
13710Sstevel@tonic-gate 
13720Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
13730Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13740Sstevel@tonic-gate 	Bpwp = pwp = kmem_zalloc(size, KM_SLEEP);
13750Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13760Sstevel@tonic-gate 	/* p->p_nwarea can't change while process is locked */
13770Sstevel@tonic-gate 	ASSERT(nwarea == avl_numnodes(&p->p_warea));
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	/* gather the watched areas */
13800Sstevel@tonic-gate 	for (pwarea = avl_first(&p->p_warea); pwarea != NULL;
13810Sstevel@tonic-gate 	    pwarea = AVL_NEXT(&p->p_warea, pwarea), pwp++) {
13820Sstevel@tonic-gate 		pwp->pr_vaddr = (uintptr_t)pwarea->wa_vaddr;
13830Sstevel@tonic-gate 		pwp->pr_size = pwarea->wa_eaddr - pwarea->wa_vaddr;
13840Sstevel@tonic-gate 		pwp->pr_wflags = (int)pwarea->wa_flags;
13850Sstevel@tonic-gate 	}
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	prunlock(pnp);
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	error = pr_uioread(Bpwp, size, uiop);
13900Sstevel@tonic-gate 	kmem_free(Bpwp, size);
13910Sstevel@tonic-gate 	return (error);
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate 
13940Sstevel@tonic-gate static int
pr_read_lwpstatus(prnode_t * pnp,uio_t * uiop)13950Sstevel@tonic-gate pr_read_lwpstatus(prnode_t *pnp, uio_t *uiop)
13960Sstevel@tonic-gate {
13970Sstevel@tonic-gate 	lwpstatus_t *sp;
13980Sstevel@tonic-gate 	int error;
13990Sstevel@tonic-gate 
14000Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSTATUS);
14010Sstevel@tonic-gate 
14020Sstevel@tonic-gate 	/*
14030Sstevel@tonic-gate 	 * We kmem_alloc() the lwpstatus structure because
14040Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
14050Sstevel@tonic-gate 	 */
14060Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
14090Sstevel@tonic-gate 		goto out;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (*sp)) {
14120Sstevel@tonic-gate 		prunlock(pnp);
14130Sstevel@tonic-gate 		goto out;
14140Sstevel@tonic-gate 	}
14150Sstevel@tonic-gate 
1416789Sahrens 	prgetlwpstatus(pnp->pr_common->prc_thread, sp, VTOZONE(PTOV(pnp)));
14170Sstevel@tonic-gate 	prunlock(pnp);
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 	error = pr_uioread(sp, sizeof (*sp), uiop);
14200Sstevel@tonic-gate out:
14210Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
14220Sstevel@tonic-gate 	return (error);
14230Sstevel@tonic-gate }
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate static int
pr_read_lwpsinfo(prnode_t * pnp,uio_t * uiop)14260Sstevel@tonic-gate pr_read_lwpsinfo(prnode_t *pnp, uio_t *uiop)
14270Sstevel@tonic-gate {
14280Sstevel@tonic-gate 	lwpsinfo_t lwpsinfo;
14290Sstevel@tonic-gate 	proc_t *p;
14300Sstevel@tonic-gate 	kthread_t *t;
14310Sstevel@tonic-gate 	lwpent_t *lep;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSINFO);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	/*
14360Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
14370Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
14380Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
14390Sstevel@tonic-gate 	 */
14400Sstevel@tonic-gate 	p = pr_p_lock(pnp);
14410Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
14420Sstevel@tonic-gate 	if (p == NULL)
14430Sstevel@tonic-gate 		return (ENOENT);
14440Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
14450Sstevel@tonic-gate 	if (pnp->pr_common->prc_tslot == -1) {
14460Sstevel@tonic-gate 		prunlock(pnp);
14470Sstevel@tonic-gate 		return (ENOENT);
14480Sstevel@tonic-gate 	}
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpsinfo)) {
14510Sstevel@tonic-gate 		prunlock(pnp);
14520Sstevel@tonic-gate 		return (0);
14530Sstevel@tonic-gate 	}
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	if ((t = pnp->pr_common->prc_thread) != NULL)
14560Sstevel@tonic-gate 		prgetlwpsinfo(t, &lwpsinfo);
14570Sstevel@tonic-gate 	else {
14580Sstevel@tonic-gate 		lep = p->p_lwpdir[pnp->pr_common->prc_tslot].ld_entry;
14590Sstevel@tonic-gate 		bzero(&lwpsinfo, sizeof (lwpsinfo));
14600Sstevel@tonic-gate 		lwpsinfo.pr_lwpid = lep->le_lwpid;
14610Sstevel@tonic-gate 		lwpsinfo.pr_state = SZOMB;
14620Sstevel@tonic-gate 		lwpsinfo.pr_sname = 'Z';
14630Sstevel@tonic-gate 		lwpsinfo.pr_start.tv_sec = lep->le_start;
14640Sstevel@tonic-gate 		lwpsinfo.pr_bindpro = PBIND_NONE;
14650Sstevel@tonic-gate 		lwpsinfo.pr_bindpset = PS_NONE;
14660Sstevel@tonic-gate 	}
14670Sstevel@tonic-gate 	prunlock(pnp);
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	return (pr_uioread(&lwpsinfo, sizeof (lwpsinfo), uiop));
14700Sstevel@tonic-gate }
14710Sstevel@tonic-gate 
14720Sstevel@tonic-gate static int
pr_read_lwpusage(prnode_t * pnp,uio_t * uiop)14730Sstevel@tonic-gate pr_read_lwpusage(prnode_t *pnp, uio_t *uiop)
14740Sstevel@tonic-gate {
14750Sstevel@tonic-gate 	prhusage_t *pup;
14760Sstevel@tonic-gate 	prusage_t *upup;
14770Sstevel@tonic-gate 	proc_t *p;
14780Sstevel@tonic-gate 	int error;
14790Sstevel@tonic-gate 
14800Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPUSAGE);
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 	/* allocate now, before locking the process */
14830Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
14840Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	/*
14870Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
14880Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
14890Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
14900Sstevel@tonic-gate 	 */
14910Sstevel@tonic-gate 	p = pr_p_lock(pnp);
14920Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
14930Sstevel@tonic-gate 	if (p == NULL) {
14940Sstevel@tonic-gate 		error = ENOENT;
14950Sstevel@tonic-gate 		goto out;
14960Sstevel@tonic-gate 	}
14970Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
14980Sstevel@tonic-gate 	if (pnp->pr_common->prc_thread == NULL) {
14990Sstevel@tonic-gate 		prunlock(pnp);
15000Sstevel@tonic-gate 		error = ENOENT;
15010Sstevel@tonic-gate 		goto out;
15020Sstevel@tonic-gate 	}
15030Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage_t)) {
15040Sstevel@tonic-gate 		prunlock(pnp);
15050Sstevel@tonic-gate 		error = 0;
15060Sstevel@tonic-gate 		goto out;
15070Sstevel@tonic-gate 	}
15080Sstevel@tonic-gate 
15090Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
15100Sstevel@tonic-gate 	prgetusage(pnp->pr_common->prc_thread, pup);
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	prunlock(pnp);
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 	prcvtusage(pup, upup);
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage_t), uiop);
15170Sstevel@tonic-gate out:
15180Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
15190Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
15200Sstevel@tonic-gate 	return (error);
15210Sstevel@tonic-gate }
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate /* ARGSUSED */
15240Sstevel@tonic-gate static int
pr_read_xregs(prnode_t * pnp,uio_t * uiop)15250Sstevel@tonic-gate pr_read_xregs(prnode_t *pnp, uio_t *uiop)
15260Sstevel@tonic-gate {
15270Sstevel@tonic-gate #if defined(__sparc)
15280Sstevel@tonic-gate 	proc_t *p;
15290Sstevel@tonic-gate 	kthread_t *t;
15300Sstevel@tonic-gate 	int error;
15310Sstevel@tonic-gate 	char *xreg;
15320Sstevel@tonic-gate 	size_t size;
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XREGS);
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	xreg = kmem_zalloc(sizeof (prxregset_t), KM_SLEEP);
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
15390Sstevel@tonic-gate 		goto out;
15400Sstevel@tonic-gate 
15410Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
15420Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
15430Sstevel@tonic-gate 
15440Sstevel@tonic-gate 	size = prhasx(p)? prgetprxregsize(p) : 0;
15450Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
15460Sstevel@tonic-gate 		prunlock(pnp);
15470Sstevel@tonic-gate 		goto out;
15480Sstevel@tonic-gate 	}
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	/* drop p->p_lock while (possibly) touching the stack */
15510Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
15520Sstevel@tonic-gate 	prgetprxregs(ttolwp(t), xreg);
15530Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
15540Sstevel@tonic-gate 	prunlock(pnp);
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	error = pr_uioread(xreg, size, uiop);
15570Sstevel@tonic-gate out:
15580Sstevel@tonic-gate 	kmem_free(xreg, sizeof (prxregset_t));
15590Sstevel@tonic-gate 	return (error);
15600Sstevel@tonic-gate #else
15610Sstevel@tonic-gate 	return (0);
15620Sstevel@tonic-gate #endif
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate #if defined(__sparc)
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate static int
pr_read_gwindows(prnode_t * pnp,uio_t * uiop)15680Sstevel@tonic-gate pr_read_gwindows(prnode_t *pnp, uio_t *uiop)
15690Sstevel@tonic-gate {
15700Sstevel@tonic-gate 	proc_t *p;
15710Sstevel@tonic-gate 	kthread_t *t;
15720Sstevel@tonic-gate 	gwindows_t *gwp;
15730Sstevel@tonic-gate 	int error;
15740Sstevel@tonic-gate 	size_t size;
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_GWINDOWS);
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	gwp = kmem_zalloc(sizeof (gwindows_t), KM_SLEEP);
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
15810Sstevel@tonic-gate 		goto out;
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
15840Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
15850Sstevel@tonic-gate 
15860Sstevel@tonic-gate 	/*
15870Sstevel@tonic-gate 	 * Drop p->p_lock while touching the stack.
15880Sstevel@tonic-gate 	 * The P_PR_LOCK flag prevents the lwp from
15890Sstevel@tonic-gate 	 * disappearing while we do this.
15900Sstevel@tonic-gate 	 */
15910Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
15920Sstevel@tonic-gate 	if ((size = prnwindows(ttolwp(t))) != 0)
15930Sstevel@tonic-gate 		size = sizeof (gwindows_t) -
15940Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW - size) * sizeof (struct rwindow);
15950Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
15960Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
15970Sstevel@tonic-gate 		prunlock(pnp);
15980Sstevel@tonic-gate 		goto out;
15990Sstevel@tonic-gate 	}
16000Sstevel@tonic-gate 	prgetwindows(ttolwp(t), gwp);
16010Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
16020Sstevel@tonic-gate 	prunlock(pnp);
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 	error = pr_uioread(gwp, size, uiop);
16050Sstevel@tonic-gate out:
16060Sstevel@tonic-gate 	kmem_free(gwp, sizeof (gwindows_t));
16070Sstevel@tonic-gate 	return (error);
16080Sstevel@tonic-gate }
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate /* ARGSUSED */
16110Sstevel@tonic-gate static int
pr_read_asrs(prnode_t * pnp,uio_t * uiop)16120Sstevel@tonic-gate pr_read_asrs(prnode_t *pnp, uio_t *uiop)
16130Sstevel@tonic-gate {
16140Sstevel@tonic-gate 	int error;
16150Sstevel@tonic-gate 
16160Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_ASRS);
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 	/* the asrs file exists only for sparc v9 _LP64 processes */
16190Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
16200Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
16210Sstevel@tonic-gate 		kthread_t *t = pnp->pr_common->prc_thread;
16220Sstevel@tonic-gate 		asrset_t asrset;
16230Sstevel@tonic-gate 
16240Sstevel@tonic-gate 		if (p->p_model != DATAMODEL_LP64 ||
16250Sstevel@tonic-gate 		    uiop->uio_offset >= sizeof (asrset_t)) {
16260Sstevel@tonic-gate 			prunlock(pnp);
16270Sstevel@tonic-gate 			return (0);
16280Sstevel@tonic-gate 		}
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 		/*
16310Sstevel@tonic-gate 		 * Drop p->p_lock while touching the stack.
16320Sstevel@tonic-gate 		 * The P_PR_LOCK flag prevents the lwp from
16330Sstevel@tonic-gate 		 * disappearing while we do this.
16340Sstevel@tonic-gate 		 */
16350Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
16360Sstevel@tonic-gate 		prgetasregs(ttolwp(t), asrset);
16370Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
16380Sstevel@tonic-gate 		prunlock(pnp);
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 		error = pr_uioread(&asrset[0], sizeof (asrset_t), uiop);
16410Sstevel@tonic-gate 	}
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 	return (error);
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate #endif	/* __sparc */
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate static int
pr_read_piddir(prnode_t * pnp,uio_t * uiop)16490Sstevel@tonic-gate pr_read_piddir(prnode_t *pnp, uio_t *uiop)
16500Sstevel@tonic-gate {
16510Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDDIR);
16520Sstevel@tonic-gate 	ASSERT(pnp->pr_pidfile != NULL);
16530Sstevel@tonic-gate 
16540Sstevel@tonic-gate 	/* use the underlying PR_PIDFILE to read the process */
16550Sstevel@tonic-gate 	pnp = VTOP(pnp->pr_pidfile);
16560Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDFILE);
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	return (pr_read_pidfile(pnp, uiop));
16590Sstevel@tonic-gate }
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate static int
pr_read_pidfile(prnode_t * pnp,uio_t * uiop)16620Sstevel@tonic-gate pr_read_pidfile(prnode_t *pnp, uio_t *uiop)
16630Sstevel@tonic-gate {
16640Sstevel@tonic-gate 	int error;
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDFILE || pnp->pr_type == PR_LWPIDFILE);
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
16690Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
16700Sstevel@tonic-gate 		struct as *as = p->p_as;
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || as == &kas) {
16730Sstevel@tonic-gate 			/*
16740Sstevel@tonic-gate 			 * /proc I/O cannot be done to a system process.
16750Sstevel@tonic-gate 			 */
16760Sstevel@tonic-gate 			error = EIO;	/* old /proc semantics */
16770Sstevel@tonic-gate 		} else {
16780Sstevel@tonic-gate 			/*
16790Sstevel@tonic-gate 			 * We drop p_lock because we don't want to hold
16800Sstevel@tonic-gate 			 * it over an I/O operation because that could
16810Sstevel@tonic-gate 			 * lead to deadlock with the clock thread.
16820Sstevel@tonic-gate 			 * The process will not disappear and its address
16830Sstevel@tonic-gate 			 * space will not change because it is marked P_PR_LOCK.
16840Sstevel@tonic-gate 			 */
16850Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
16860Sstevel@tonic-gate 			error = prusrio(p, UIO_READ, uiop, 1);
16870Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
16880Sstevel@tonic-gate 		}
16890Sstevel@tonic-gate 		prunlock(pnp);
16900Sstevel@tonic-gate 	}
16910Sstevel@tonic-gate 
16920Sstevel@tonic-gate 	return (error);
16930Sstevel@tonic-gate }
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate /*
16980Sstevel@tonic-gate  * Array of ILP32 read functions, indexed by /proc file type.
16990Sstevel@tonic-gate  */
17000Sstevel@tonic-gate static int pr_read_status_32(),
17010Sstevel@tonic-gate 	pr_read_lstatus_32(), pr_read_psinfo_32(), pr_read_lpsinfo_32(),
17020Sstevel@tonic-gate 	pr_read_map_32(), pr_read_rmap_32(), pr_read_xmap_32(),
17030Sstevel@tonic-gate 	pr_read_sigact_32(), pr_read_auxv_32(),
17040Sstevel@tonic-gate 	pr_read_usage_32(), pr_read_lusage_32(), pr_read_pagedata_32(),
17050Sstevel@tonic-gate 	pr_read_watch_32(), pr_read_lwpstatus_32(), pr_read_lwpsinfo_32(),
17060Sstevel@tonic-gate 	pr_read_lwpusage_32(),
17070Sstevel@tonic-gate #if defined(__sparc)
17080Sstevel@tonic-gate 	pr_read_gwindows_32(),
17090Sstevel@tonic-gate #endif
17100Sstevel@tonic-gate 	pr_read_opagedata_32();
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate static int (*pr_read_function_32[PR_NFILES])() = {
17130Sstevel@tonic-gate 	pr_read_inval,		/* /proc				*/
17140Sstevel@tonic-gate 	pr_read_inval,		/* /proc/self				*/
17150Sstevel@tonic-gate 	pr_read_piddir,		/* /proc/<pid> (old /proc read())	*/
17160Sstevel@tonic-gate 	pr_read_as,		/* /proc/<pid>/as			*/
17170Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/ctl			*/
17180Sstevel@tonic-gate 	pr_read_status_32,	/* /proc/<pid>/status			*/
17190Sstevel@tonic-gate 	pr_read_lstatus_32,	/* /proc/<pid>/lstatus			*/
17200Sstevel@tonic-gate 	pr_read_psinfo_32,	/* /proc/<pid>/psinfo			*/
17210Sstevel@tonic-gate 	pr_read_lpsinfo_32,	/* /proc/<pid>/lpsinfo			*/
17220Sstevel@tonic-gate 	pr_read_map_32,		/* /proc/<pid>/map			*/
17230Sstevel@tonic-gate 	pr_read_rmap_32,	/* /proc/<pid>/rmap			*/
17240Sstevel@tonic-gate 	pr_read_xmap_32,	/* /proc/<pid>/xmap			*/
17250Sstevel@tonic-gate 	pr_read_cred,		/* /proc/<pid>/cred			*/
17260Sstevel@tonic-gate 	pr_read_sigact_32,	/* /proc/<pid>/sigact			*/
17270Sstevel@tonic-gate 	pr_read_auxv_32,	/* /proc/<pid>/auxv			*/
17280Sstevel@tonic-gate #if defined(__x86)
17290Sstevel@tonic-gate 	pr_read_ldt,		/* /proc/<pid>/ldt			*/
17300Sstevel@tonic-gate #endif
17310Sstevel@tonic-gate 	pr_read_usage_32,	/* /proc/<pid>/usage			*/
17320Sstevel@tonic-gate 	pr_read_lusage_32,	/* /proc/<pid>/lusage			*/
17330Sstevel@tonic-gate 	pr_read_pagedata_32,	/* /proc/<pid>/pagedata			*/
17340Sstevel@tonic-gate 	pr_read_watch_32,	/* /proc/<pid>/watch			*/
17350Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/cwd			*/
17360Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/root			*/
17370Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd			*/
17380Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd/nn			*/
17390Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object			*/
17400Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object/xxx		*/
17410Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp			*/
17420Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>		*/
17430Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
17440Sstevel@tonic-gate 	pr_read_lwpstatus_32,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
17450Sstevel@tonic-gate 	pr_read_lwpsinfo_32,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
17460Sstevel@tonic-gate 	pr_read_lwpusage_32,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
17470Sstevel@tonic-gate 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
17480Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
17490Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
17500Sstevel@tonic-gate #if defined(__sparc)
17510Sstevel@tonic-gate 	pr_read_gwindows_32,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
17520Sstevel@tonic-gate 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
17530Sstevel@tonic-gate #endif
17540Sstevel@tonic-gate 	pr_read_priv,		/* /proc/<pid>/priv			*/
17550Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path			*/
17560Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path/xxx			*/
17570Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts		*/
17580Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts/<ctid>		*/
17590Sstevel@tonic-gate 	pr_read_pidfile,	/* old process file			*/
17600Sstevel@tonic-gate 	pr_read_pidfile,	/* old lwp file				*/
17610Sstevel@tonic-gate 	pr_read_opagedata_32,	/* old pagedata file			*/
17620Sstevel@tonic-gate };
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate static int
pr_read_status_32(prnode_t * pnp,uio_t * uiop)17650Sstevel@tonic-gate pr_read_status_32(prnode_t *pnp, uio_t *uiop)
17660Sstevel@tonic-gate {
17670Sstevel@tonic-gate 	pstatus32_t *sp;
17680Sstevel@tonic-gate 	proc_t *p;
17690Sstevel@tonic-gate 	int error;
17700Sstevel@tonic-gate 
17710Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_STATUS);
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	/*
17740Sstevel@tonic-gate 	 * We kmem_alloc() the pstatus structure because
17750Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
17760Sstevel@tonic-gate 	 */
17770Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
17780Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
17790Sstevel@tonic-gate 		/*
17800Sstevel@tonic-gate 		 * A 32-bit process cannot get the status of a 64-bit process.
17810Sstevel@tonic-gate 		 * The fields for the 64-bit quantities are not large enough.
17820Sstevel@tonic-gate 		 */
17830Sstevel@tonic-gate 		p = pnp->pr_common->prc_proc;
17840Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p)) {
17850Sstevel@tonic-gate 			prunlock(pnp);
17860Sstevel@tonic-gate 			error = EOVERFLOW;
17870Sstevel@tonic-gate 		} else {
17880Sstevel@tonic-gate 			prgetstatus32(pnp->pr_common->prc_proc, sp,
1789789Sahrens 			    VTOZONE(PTOV(pnp)));
17900Sstevel@tonic-gate 			prunlock(pnp);
17910Sstevel@tonic-gate 			error = pr_uioread(sp, sizeof (*sp), uiop);
17920Sstevel@tonic-gate 		}
17930Sstevel@tonic-gate 	}
17940Sstevel@tonic-gate 	kmem_free((caddr_t)sp, sizeof (*sp));
17950Sstevel@tonic-gate 	return (error);
17960Sstevel@tonic-gate }
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate static int
pr_read_lstatus_32(prnode_t * pnp,uio_t * uiop)17990Sstevel@tonic-gate pr_read_lstatus_32(prnode_t *pnp, uio_t *uiop)
18000Sstevel@tonic-gate {
18010Sstevel@tonic-gate 	proc_t *p;
18020Sstevel@tonic-gate 	kthread_t *t;
18030Sstevel@tonic-gate 	lwpdir_t *ldp;
18040Sstevel@tonic-gate 	size_t size;
18050Sstevel@tonic-gate 	prheader32_t *php;
18060Sstevel@tonic-gate 	lwpstatus32_t *sp;
18070Sstevel@tonic-gate 	int error;
18080Sstevel@tonic-gate 	int nlwp;
18090Sstevel@tonic-gate 	int i;
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LSTATUS);
18120Sstevel@tonic-gate 
18130Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
18140Sstevel@tonic-gate 		return (error);
18150Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
18160Sstevel@tonic-gate 	/*
18170Sstevel@tonic-gate 	 * A 32-bit process cannot get the status of a 64-bit process.
18180Sstevel@tonic-gate 	 * The fields for the 64-bit quantities are not large enough.
18190Sstevel@tonic-gate 	 */
18200Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
18210Sstevel@tonic-gate 		prunlock(pnp);
18220Sstevel@tonic-gate 		return (EOVERFLOW);
18230Sstevel@tonic-gate 	}
18240Sstevel@tonic-gate 	nlwp = p->p_lwpcnt;
18250Sstevel@tonic-gate 	size = sizeof (prheader32_t) + nlwp * LSPAN32(lwpstatus32_t);
18260Sstevel@tonic-gate 
18270Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
18280Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
18290Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
18300Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18310Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
18320Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 	php->pr_nent = nlwp;
18350Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(lwpstatus32_t);
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	sp = (lwpstatus32_t *)(php + 1);
18380Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
18390Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
18400Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
18410Sstevel@tonic-gate 			continue;
1842789Sahrens 		prgetlwpstatus32(t, sp, VTOZONE(PTOV(pnp)));
18430Sstevel@tonic-gate 		sp = (lwpstatus32_t *)((caddr_t)sp + LSPAN32(lwpstatus32_t));
18440Sstevel@tonic-gate 	}
18450Sstevel@tonic-gate 	prunlock(pnp);
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
18480Sstevel@tonic-gate 	kmem_free(php, size);
18490Sstevel@tonic-gate 	return (error);
18500Sstevel@tonic-gate }
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate static int
pr_read_psinfo_32(prnode_t * pnp,uio_t * uiop)18530Sstevel@tonic-gate pr_read_psinfo_32(prnode_t *pnp, uio_t *uiop)
18540Sstevel@tonic-gate {
18550Sstevel@tonic-gate 	psinfo32_t psinfo;
18560Sstevel@tonic-gate 	proc_t *p;
18570Sstevel@tonic-gate 	int error = 0;
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PSINFO);
18600Sstevel@tonic-gate 
18610Sstevel@tonic-gate 	/*
18620Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
18630Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
18640Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
18650Sstevel@tonic-gate 	 */
18660Sstevel@tonic-gate 	p = pr_p_lock(pnp);
18670Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
18680Sstevel@tonic-gate 	if (p == NULL)
18690Sstevel@tonic-gate 		error = ENOENT;
18700Sstevel@tonic-gate 	else {
18710Sstevel@tonic-gate 		ASSERT(p == pnp->pr_common->prc_proc);
18720Sstevel@tonic-gate 		prgetpsinfo32(p, &psinfo);
18730Sstevel@tonic-gate 		prunlock(pnp);
18740Sstevel@tonic-gate 		error = pr_uioread(&psinfo, sizeof (psinfo), uiop);
18750Sstevel@tonic-gate 	}
18760Sstevel@tonic-gate 	return (error);
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate static int
pr_read_lpsinfo_32(prnode_t * pnp,uio_t * uiop)18800Sstevel@tonic-gate pr_read_lpsinfo_32(prnode_t *pnp, uio_t *uiop)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	proc_t *p;
18830Sstevel@tonic-gate 	kthread_t *t;
18840Sstevel@tonic-gate 	lwpdir_t *ldp;
18850Sstevel@tonic-gate 	lwpent_t *lep;
18860Sstevel@tonic-gate 	size_t size;
18870Sstevel@tonic-gate 	prheader32_t *php;
18880Sstevel@tonic-gate 	lwpsinfo32_t *sp;
18890Sstevel@tonic-gate 	int error;
18900Sstevel@tonic-gate 	int nlwp;
18910Sstevel@tonic-gate 	int i;
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LPSINFO);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	/*
18960Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
18970Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
18980Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
18990Sstevel@tonic-gate 	 */
19000Sstevel@tonic-gate 	p = pr_p_lock(pnp);
19010Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
19020Sstevel@tonic-gate 	if (p == NULL)
19030Sstevel@tonic-gate 		return (ENOENT);
19040Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
19050Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt + p->p_zombcnt) == 0) {
19060Sstevel@tonic-gate 		prunlock(pnp);
19070Sstevel@tonic-gate 		return (ENOENT);
19080Sstevel@tonic-gate 	}
19090Sstevel@tonic-gate 	size = sizeof (prheader32_t) + nlwp * LSPAN32(lwpsinfo32_t);
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
19120Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
19130Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
19140Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
19150Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
19160Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt + p->p_zombcnt);
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	php->pr_nent = nlwp;
19190Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(lwpsinfo32_t);
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 	sp = (lwpsinfo32_t *)(php + 1);
19220Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
19230Sstevel@tonic-gate 		if ((lep = ldp->ld_entry) == NULL)
19240Sstevel@tonic-gate 			continue;
19250Sstevel@tonic-gate 		if ((t = lep->le_thread) != NULL)
19260Sstevel@tonic-gate 			prgetlwpsinfo32(t, sp);
19270Sstevel@tonic-gate 		else {
19280Sstevel@tonic-gate 			bzero(sp, sizeof (*sp));
19290Sstevel@tonic-gate 			sp->pr_lwpid = lep->le_lwpid;
19300Sstevel@tonic-gate 			sp->pr_state = SZOMB;
19310Sstevel@tonic-gate 			sp->pr_sname = 'Z';
19320Sstevel@tonic-gate 			sp->pr_start.tv_sec = (time32_t)lep->le_start;
19330Sstevel@tonic-gate 		}
19340Sstevel@tonic-gate 		sp = (lwpsinfo32_t *)((caddr_t)sp + LSPAN32(lwpsinfo32_t));
19350Sstevel@tonic-gate 	}
19360Sstevel@tonic-gate 	prunlock(pnp);
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
19390Sstevel@tonic-gate 	kmem_free(php, size);
19400Sstevel@tonic-gate 	return (error);
19410Sstevel@tonic-gate }
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate static int
pr_read_map_common_32(prnode_t * pnp,uio_t * uiop,prnodetype_t type)19442789Sfrankho pr_read_map_common_32(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
19450Sstevel@tonic-gate {
19460Sstevel@tonic-gate 	proc_t *p;
19470Sstevel@tonic-gate 	struct as *as;
19482789Sfrankho 	list_t	iolhead;
19490Sstevel@tonic-gate 	int error;
19500Sstevel@tonic-gate 
1951*12072SChris.Baumbauer@Oracle.COM readmap32_common:
19520Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
19530Sstevel@tonic-gate 		return (error);
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
19560Sstevel@tonic-gate 	as = p->p_as;
19570Sstevel@tonic-gate 
19580Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
19590Sstevel@tonic-gate 		prunlock(pnp);
19600Sstevel@tonic-gate 		return (0);
19610Sstevel@tonic-gate 	}
19620Sstevel@tonic-gate 
19630Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
19640Sstevel@tonic-gate 		prunlock(pnp);
19650Sstevel@tonic-gate 		return (EOVERFLOW);
19660Sstevel@tonic-gate 	}
19670Sstevel@tonic-gate 
1968*12072SChris.Baumbauer@Oracle.COM 	if (!AS_LOCK_TRYENTER(as, &as->a_lock, RW_WRITER)) {
1969*12072SChris.Baumbauer@Oracle.COM 		prunlock(pnp);
1970*12072SChris.Baumbauer@Oracle.COM 		delay(1);
1971*12072SChris.Baumbauer@Oracle.COM 		goto readmap32_common;
1972*12072SChris.Baumbauer@Oracle.COM 	}
19730Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
1974*12072SChris.Baumbauer@Oracle.COM 
19752789Sfrankho 	switch (type) {
19762789Sfrankho 	case PR_XMAP:
19772789Sfrankho 		error = prgetxmap32(p, &iolhead);
19782789Sfrankho 		break;
19792789Sfrankho 	case PR_RMAP:
19802789Sfrankho 		error = prgetmap32(p, 1, &iolhead);
19812789Sfrankho 		break;
19822789Sfrankho 	case PR_MAP:
19832789Sfrankho 		error = prgetmap32(p, 0, &iolhead);
19842789Sfrankho 		break;
19852789Sfrankho 	}
19860Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
19870Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
19880Sstevel@tonic-gate 	prunlock(pnp);
19890Sstevel@tonic-gate 
19902789Sfrankho 	error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
19912789Sfrankho 
19920Sstevel@tonic-gate 	return (error);
19930Sstevel@tonic-gate }
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate static int
pr_read_map_32(prnode_t * pnp,uio_t * uiop)19960Sstevel@tonic-gate pr_read_map_32(prnode_t *pnp, uio_t *uiop)
19970Sstevel@tonic-gate {
19980Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_MAP);
19992789Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
20000Sstevel@tonic-gate }
20010Sstevel@tonic-gate 
20020Sstevel@tonic-gate static int
pr_read_rmap_32(prnode_t * pnp,uio_t * uiop)20030Sstevel@tonic-gate pr_read_rmap_32(prnode_t *pnp, uio_t *uiop)
20040Sstevel@tonic-gate {
20050Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_RMAP);
20062789Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
20070Sstevel@tonic-gate }
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate static int
pr_read_xmap_32(prnode_t * pnp,uio_t * uiop)20100Sstevel@tonic-gate pr_read_xmap_32(prnode_t *pnp, uio_t *uiop)
20110Sstevel@tonic-gate {
20120Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XMAP);
20132789Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
20140Sstevel@tonic-gate }
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate static int
pr_read_sigact_32(prnode_t * pnp,uio_t * uiop)20170Sstevel@tonic-gate pr_read_sigact_32(prnode_t *pnp, uio_t *uiop)
20180Sstevel@tonic-gate {
201911940SRoger.Faulkner@Sun.COM 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
20200Sstevel@tonic-gate 	proc_t *p;
20210Sstevel@tonic-gate 	struct sigaction32 *sap;
20220Sstevel@tonic-gate 	int sig;
20230Sstevel@tonic-gate 	int error;
20240Sstevel@tonic-gate 	user_t *up;
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_SIGACT);
20270Sstevel@tonic-gate 
20280Sstevel@tonic-gate 	/*
20290Sstevel@tonic-gate 	 * We kmem_alloc() the sigaction32 array because
20300Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
20310Sstevel@tonic-gate 	 */
203211940SRoger.Faulkner@Sun.COM 	sap = kmem_alloc((nsig-1) * sizeof (struct sigaction32), KM_SLEEP);
20330Sstevel@tonic-gate 
20340Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
20350Sstevel@tonic-gate 		goto out;
20360Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
20370Sstevel@tonic-gate 
20380Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
20390Sstevel@tonic-gate 		prunlock(pnp);
20400Sstevel@tonic-gate 		error = EOVERFLOW;
20410Sstevel@tonic-gate 		goto out;
20420Sstevel@tonic-gate 	}
20430Sstevel@tonic-gate 
204411940SRoger.Faulkner@Sun.COM 	if (uiop->uio_offset >= (nsig-1) * sizeof (struct sigaction32)) {
20450Sstevel@tonic-gate 		prunlock(pnp);
20460Sstevel@tonic-gate 		goto out;
20470Sstevel@tonic-gate 	}
20480Sstevel@tonic-gate 
20490Sstevel@tonic-gate 	up = PTOU(p);
205011940SRoger.Faulkner@Sun.COM 	for (sig = 1; sig < nsig; sig++)
20510Sstevel@tonic-gate 		prgetaction32(p, up, sig, &sap[sig-1]);
20520Sstevel@tonic-gate 	prunlock(pnp);
20530Sstevel@tonic-gate 
205411940SRoger.Faulkner@Sun.COM 	error = pr_uioread(sap, (nsig - 1) * sizeof (struct sigaction32), uiop);
20550Sstevel@tonic-gate out:
205611940SRoger.Faulkner@Sun.COM 	kmem_free(sap, (nsig-1) * sizeof (struct sigaction32));
20570Sstevel@tonic-gate 	return (error);
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate static int
pr_read_auxv_32(prnode_t * pnp,uio_t * uiop)20610Sstevel@tonic-gate pr_read_auxv_32(prnode_t *pnp, uio_t *uiop)
20620Sstevel@tonic-gate {
20630Sstevel@tonic-gate 	auxv32_t auxv[__KERN_NAUXV_IMPL];
20640Sstevel@tonic-gate 	proc_t *p;
20650Sstevel@tonic-gate 	user_t *up;
20660Sstevel@tonic-gate 	int error;
20670Sstevel@tonic-gate 	int i;
20680Sstevel@tonic-gate 
20690Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AUXV);
20700Sstevel@tonic-gate 
20710Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
20720Sstevel@tonic-gate 		return (error);
20730Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
20760Sstevel@tonic-gate 		prunlock(pnp);
20770Sstevel@tonic-gate 		return (EOVERFLOW);
20780Sstevel@tonic-gate 	}
20790Sstevel@tonic-gate 
20800Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (auxv)) {
20810Sstevel@tonic-gate 		prunlock(pnp);
20820Sstevel@tonic-gate 		return (0);
20830Sstevel@tonic-gate 	}
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	up = PTOU(p);
20860Sstevel@tonic-gate 	for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
20870Sstevel@tonic-gate 		auxv[i].a_type = (int32_t)up->u_auxv[i].a_type;
20880Sstevel@tonic-gate 		auxv[i].a_un.a_val = (int32_t)up->u_auxv[i].a_un.a_val;
20890Sstevel@tonic-gate 	}
20900Sstevel@tonic-gate 	prunlock(pnp);
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 	return (pr_uioread(auxv, sizeof (auxv), uiop));
20930Sstevel@tonic-gate }
20940Sstevel@tonic-gate 
20950Sstevel@tonic-gate static int
pr_read_usage_32(prnode_t * pnp,uio_t * uiop)20960Sstevel@tonic-gate pr_read_usage_32(prnode_t *pnp, uio_t *uiop)
20970Sstevel@tonic-gate {
20980Sstevel@tonic-gate 	prhusage_t *pup;
20990Sstevel@tonic-gate 	prusage32_t *upup;
21000Sstevel@tonic-gate 	proc_t *p;
21010Sstevel@tonic-gate 	kthread_t *t;
21020Sstevel@tonic-gate 	int error;
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_USAGE);
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	/* allocate now, before locking the process */
21070Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
21080Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
21090Sstevel@tonic-gate 
21100Sstevel@tonic-gate 	/*
21110Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
21120Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
21130Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
21140Sstevel@tonic-gate 	 */
21150Sstevel@tonic-gate 	p = pr_p_lock(pnp);
21160Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
21170Sstevel@tonic-gate 	if (p == NULL) {
21180Sstevel@tonic-gate 		error = ENOENT;
21190Sstevel@tonic-gate 		goto out;
21200Sstevel@tonic-gate 	}
21210Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
21220Sstevel@tonic-gate 
21230Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage32_t)) {
21240Sstevel@tonic-gate 		prunlock(pnp);
21250Sstevel@tonic-gate 		error = 0;
21260Sstevel@tonic-gate 		goto out;
21270Sstevel@tonic-gate 	}
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
21320Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
21330Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
21340Sstevel@tonic-gate 
21350Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
21360Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
21370Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
21380Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
21390Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
21400Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
21410Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
21420Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
21430Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
21440Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
21450Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
21460Sstevel@tonic-gate 
21470Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
21480Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
21490Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
21500Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
21510Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
21520Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
21530Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
21540Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
21550Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
21560Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
21570Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
21580Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 	/*
21610Sstevel@tonic-gate 	 * Add the usage information for each active lwp.
21620Sstevel@tonic-gate 	 */
21630Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL &&
21640Sstevel@tonic-gate 	    !(pnp->pr_pcommon->prc_flags & PRC_DESTROY)) {
21650Sstevel@tonic-gate 		do {
21660Sstevel@tonic-gate 			if (t->t_proc_flag & TP_LWPEXIT)
21670Sstevel@tonic-gate 				continue;
21680Sstevel@tonic-gate 			pup->pr_count++;
21690Sstevel@tonic-gate 			praddusage(t, pup);
21700Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
21710Sstevel@tonic-gate 	}
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 	prunlock(pnp);
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	prcvtusage32(pup, upup);
21760Sstevel@tonic-gate 
21770Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage32_t), uiop);
21780Sstevel@tonic-gate out:
21790Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
21800Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
21810Sstevel@tonic-gate 	return (error);
21820Sstevel@tonic-gate }
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate static int
pr_read_lusage_32(prnode_t * pnp,uio_t * uiop)21850Sstevel@tonic-gate pr_read_lusage_32(prnode_t *pnp, uio_t *uiop)
21860Sstevel@tonic-gate {
21870Sstevel@tonic-gate 	int nlwp;
21880Sstevel@tonic-gate 	prhusage_t *pup;
21890Sstevel@tonic-gate 	prheader32_t *php;
21900Sstevel@tonic-gate 	prusage32_t *upup;
21910Sstevel@tonic-gate 	size_t size;
21920Sstevel@tonic-gate 	hrtime_t curtime;
21930Sstevel@tonic-gate 	proc_t *p;
21940Sstevel@tonic-gate 	kthread_t *t;
21950Sstevel@tonic-gate 	lwpdir_t *ldp;
21960Sstevel@tonic-gate 	int error;
21970Sstevel@tonic-gate 	int i;
21980Sstevel@tonic-gate 
21990Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LUSAGE);
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	/*
22020Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
22030Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
22040Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
22050Sstevel@tonic-gate 	 */
22060Sstevel@tonic-gate 	p = pr_p_lock(pnp);
22070Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
22080Sstevel@tonic-gate 	if (p == NULL)
22090Sstevel@tonic-gate 		return (ENOENT);
22100Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
22110Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt) == 0) {
22120Sstevel@tonic-gate 		prunlock(pnp);
22130Sstevel@tonic-gate 		return (ENOENT);
22140Sstevel@tonic-gate 	}
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	size = sizeof (prheader32_t) + (nlwp + 1) * LSPAN32(prusage32_t);
22170Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
22180Sstevel@tonic-gate 		prunlock(pnp);
22190Sstevel@tonic-gate 		return (0);
22200Sstevel@tonic-gate 	}
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
22230Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
22240Sstevel@tonic-gate 	pup = kmem_zalloc(size + sizeof (prhusage_t), KM_SLEEP);
22250Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22260Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
22270Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 	php = (prheader32_t *)(pup + 1);
22300Sstevel@tonic-gate 	upup = (prusage32_t *)(php + 1);
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 	php->pr_nent = nlwp + 1;
22330Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(prusage32_t);
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate 	curtime = gethrtime();
22360Sstevel@tonic-gate 
22370Sstevel@tonic-gate 	/*
22380Sstevel@tonic-gate 	 * First the summation over defunct lwps.
22390Sstevel@tonic-gate 	 */
22400Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
22410Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
22420Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
22430Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
22440Sstevel@tonic-gate 
22450Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
22460Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
22470Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
22480Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
22490Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
22500Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
22510Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
22520Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
22530Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
22540Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
22550Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
22580Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
22590Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
22600Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
22610Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
22620Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
22630Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
22640Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
22650Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
22660Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
22670Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
22680Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	prcvtusage32(pup, upup);
22710Sstevel@tonic-gate 
22720Sstevel@tonic-gate 	/*
22730Sstevel@tonic-gate 	 * Fill one prusage struct for each active lwp.
22740Sstevel@tonic-gate 	 */
22750Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
22760Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
22770Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
22780Sstevel@tonic-gate 			continue;
22790Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
22800Sstevel@tonic-gate 		ASSERT(nlwp > 0);
22810Sstevel@tonic-gate 		--nlwp;
22820Sstevel@tonic-gate 		upup = (prusage32_t *)
22835663Sck153898 		    ((caddr_t)upup + LSPAN32(prusage32_t));
22840Sstevel@tonic-gate 		prgetusage(t, pup);
22850Sstevel@tonic-gate 		prcvtusage32(pup, upup);
22860Sstevel@tonic-gate 	}
22870Sstevel@tonic-gate 	ASSERT(nlwp == 0);
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate 	prunlock(pnp);
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
22920Sstevel@tonic-gate 	kmem_free(pup, size + sizeof (prhusage_t));
22930Sstevel@tonic-gate 	return (error);
22940Sstevel@tonic-gate }
22950Sstevel@tonic-gate 
22960Sstevel@tonic-gate static int
pr_read_pagedata_32(prnode_t * pnp,uio_t * uiop)22970Sstevel@tonic-gate pr_read_pagedata_32(prnode_t *pnp, uio_t *uiop)
22980Sstevel@tonic-gate {
22990Sstevel@tonic-gate 	proc_t *p;
23000Sstevel@tonic-gate 	int error;
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PAGEDATA);
23030Sstevel@tonic-gate 
23040Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
23050Sstevel@tonic-gate 		return (error);
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
23080Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
23090Sstevel@tonic-gate 		prunlock(pnp);
23100Sstevel@tonic-gate 		return (0);
23110Sstevel@tonic-gate 	}
23120Sstevel@tonic-gate 
23130Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
23140Sstevel@tonic-gate 		prunlock(pnp);
23150Sstevel@tonic-gate 		return (EOVERFLOW);
23160Sstevel@tonic-gate 	}
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
23190Sstevel@tonic-gate 	error = prpdread32(p, pnp->pr_hatid, uiop);
23200Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	prunlock(pnp);
23230Sstevel@tonic-gate 	return (error);
23240Sstevel@tonic-gate }
23250Sstevel@tonic-gate 
23260Sstevel@tonic-gate static int
pr_read_opagedata_32(prnode_t * pnp,uio_t * uiop)23270Sstevel@tonic-gate pr_read_opagedata_32(prnode_t *pnp, uio_t *uiop)
23280Sstevel@tonic-gate {
23290Sstevel@tonic-gate 	proc_t *p;
23300Sstevel@tonic-gate 	struct as *as;
23310Sstevel@tonic-gate 	int error;
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OPAGEDATA);
23340Sstevel@tonic-gate 
23350Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
23360Sstevel@tonic-gate 		return (error);
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
23390Sstevel@tonic-gate 	as = p->p_as;
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
23420Sstevel@tonic-gate 		prunlock(pnp);
23430Sstevel@tonic-gate 		return (0);
23440Sstevel@tonic-gate 	}
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
23470Sstevel@tonic-gate 		prunlock(pnp);
23480Sstevel@tonic-gate 		return (EOVERFLOW);
23490Sstevel@tonic-gate 	}
23500Sstevel@tonic-gate 
23510Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
23520Sstevel@tonic-gate 	error = oprpdread32(as, pnp->pr_hatid, uiop);
23530Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	prunlock(pnp);
23560Sstevel@tonic-gate 	return (error);
23570Sstevel@tonic-gate }
23580Sstevel@tonic-gate 
23590Sstevel@tonic-gate static int
pr_read_watch_32(prnode_t * pnp,uio_t * uiop)23600Sstevel@tonic-gate pr_read_watch_32(prnode_t *pnp, uio_t *uiop)
23610Sstevel@tonic-gate {
23620Sstevel@tonic-gate 	proc_t *p;
23630Sstevel@tonic-gate 	int error;
23640Sstevel@tonic-gate 	prwatch32_t *Bpwp;
23650Sstevel@tonic-gate 	size_t size;
23660Sstevel@tonic-gate 	prwatch32_t *pwp;
23670Sstevel@tonic-gate 	int nwarea;
23680Sstevel@tonic-gate 	struct watched_area *pwarea;
23690Sstevel@tonic-gate 
23700Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_WATCH);
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
23730Sstevel@tonic-gate 		return (error);
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
23760Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
23770Sstevel@tonic-gate 		prunlock(pnp);
23780Sstevel@tonic-gate 		return (EOVERFLOW);
23790Sstevel@tonic-gate 	}
23800Sstevel@tonic-gate 	nwarea = avl_numnodes(&p->p_warea);
23810Sstevel@tonic-gate 	size = nwarea * sizeof (prwatch32_t);
23820Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
23830Sstevel@tonic-gate 		prunlock(pnp);
23840Sstevel@tonic-gate 		return (0);
23850Sstevel@tonic-gate 	}
23860Sstevel@tonic-gate 
23870Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
23880Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
23890Sstevel@tonic-gate 	Bpwp = pwp = kmem_zalloc(size, KM_SLEEP);
23900Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23910Sstevel@tonic-gate 	/* p->p_nwarea can't change while process is locked */
23920Sstevel@tonic-gate 	ASSERT(nwarea == avl_numnodes(&p->p_warea));
23930Sstevel@tonic-gate 
23940Sstevel@tonic-gate 	/* gather the watched areas */
23950Sstevel@tonic-gate 	for (pwarea = avl_first(&p->p_warea); pwarea != NULL;
23960Sstevel@tonic-gate 	    pwarea = AVL_NEXT(&p->p_warea, pwarea), pwp++) {
23970Sstevel@tonic-gate 		pwp->pr_vaddr = (caddr32_t)(uintptr_t)pwarea->wa_vaddr;
23980Sstevel@tonic-gate 		pwp->pr_size = (size32_t)(pwarea->wa_eaddr - pwarea->wa_vaddr);
23990Sstevel@tonic-gate 		pwp->pr_wflags = (int)pwarea->wa_flags;
24000Sstevel@tonic-gate 	}
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate 	prunlock(pnp);
24030Sstevel@tonic-gate 
24040Sstevel@tonic-gate 	error = pr_uioread(Bpwp, size, uiop);
24050Sstevel@tonic-gate 	kmem_free(Bpwp, size);
24060Sstevel@tonic-gate 	return (error);
24070Sstevel@tonic-gate }
24080Sstevel@tonic-gate 
24090Sstevel@tonic-gate static int
pr_read_lwpstatus_32(prnode_t * pnp,uio_t * uiop)24100Sstevel@tonic-gate pr_read_lwpstatus_32(prnode_t *pnp, uio_t *uiop)
24110Sstevel@tonic-gate {
24120Sstevel@tonic-gate 	lwpstatus32_t *sp;
24130Sstevel@tonic-gate 	proc_t *p;
24140Sstevel@tonic-gate 	int error;
24150Sstevel@tonic-gate 
24160Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSTATUS);
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 	/*
24190Sstevel@tonic-gate 	 * We kmem_alloc() the lwpstatus structure because
24200Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
24210Sstevel@tonic-gate 	 */
24220Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
24250Sstevel@tonic-gate 		goto out;
24260Sstevel@tonic-gate 
24270Sstevel@tonic-gate 	/*
24280Sstevel@tonic-gate 	 * A 32-bit process cannot get the status of a 64-bit process.
24290Sstevel@tonic-gate 	 * The fields for the 64-bit quantities are not large enough.
24300Sstevel@tonic-gate 	 */
24310Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
24320Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
24330Sstevel@tonic-gate 		prunlock(pnp);
24340Sstevel@tonic-gate 		error = EOVERFLOW;
24350Sstevel@tonic-gate 		goto out;
24360Sstevel@tonic-gate 	}
24370Sstevel@tonic-gate 
24380Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (*sp)) {
24390Sstevel@tonic-gate 		prunlock(pnp);
24400Sstevel@tonic-gate 		goto out;
24410Sstevel@tonic-gate 	}
24420Sstevel@tonic-gate 
2443789Sahrens 	prgetlwpstatus32(pnp->pr_common->prc_thread, sp, VTOZONE(PTOV(pnp)));
24440Sstevel@tonic-gate 	prunlock(pnp);
24450Sstevel@tonic-gate 
24460Sstevel@tonic-gate 	error = pr_uioread(sp, sizeof (*sp), uiop);
24470Sstevel@tonic-gate out:
24480Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
24490Sstevel@tonic-gate 	return (error);
24500Sstevel@tonic-gate }
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate static int
pr_read_lwpsinfo_32(prnode_t * pnp,uio_t * uiop)24530Sstevel@tonic-gate pr_read_lwpsinfo_32(prnode_t *pnp, uio_t *uiop)
24540Sstevel@tonic-gate {
24550Sstevel@tonic-gate 	lwpsinfo32_t lwpsinfo;
24560Sstevel@tonic-gate 	proc_t *p;
24570Sstevel@tonic-gate 	kthread_t *t;
24580Sstevel@tonic-gate 	lwpent_t *lep;
24590Sstevel@tonic-gate 
24600Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSINFO);
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	/*
24630Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
24640Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
24650Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
24660Sstevel@tonic-gate 	 */
24670Sstevel@tonic-gate 	p = pr_p_lock(pnp);
24680Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
24690Sstevel@tonic-gate 	if (p == NULL)
24700Sstevel@tonic-gate 		return (ENOENT);
24710Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
24720Sstevel@tonic-gate 	if (pnp->pr_common->prc_tslot == -1) {
24730Sstevel@tonic-gate 		prunlock(pnp);
24740Sstevel@tonic-gate 		return (ENOENT);
24750Sstevel@tonic-gate 	}
24760Sstevel@tonic-gate 
24770Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpsinfo)) {
24780Sstevel@tonic-gate 		prunlock(pnp);
24790Sstevel@tonic-gate 		return (0);
24800Sstevel@tonic-gate 	}
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 	if ((t = pnp->pr_common->prc_thread) != NULL)
24830Sstevel@tonic-gate 		prgetlwpsinfo32(t, &lwpsinfo);
24840Sstevel@tonic-gate 	else {
24850Sstevel@tonic-gate 		lep = p->p_lwpdir[pnp->pr_common->prc_tslot].ld_entry;
24860Sstevel@tonic-gate 		bzero(&lwpsinfo, sizeof (lwpsinfo));
24870Sstevel@tonic-gate 		lwpsinfo.pr_lwpid = lep->le_lwpid;
24880Sstevel@tonic-gate 		lwpsinfo.pr_state = SZOMB;
24890Sstevel@tonic-gate 		lwpsinfo.pr_sname = 'Z';
24900Sstevel@tonic-gate 		lwpsinfo.pr_start.tv_sec = (time32_t)lep->le_start;
24910Sstevel@tonic-gate 	}
24920Sstevel@tonic-gate 	prunlock(pnp);
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 	return (pr_uioread(&lwpsinfo, sizeof (lwpsinfo), uiop));
24950Sstevel@tonic-gate }
24960Sstevel@tonic-gate 
24970Sstevel@tonic-gate static int
pr_read_lwpusage_32(prnode_t * pnp,uio_t * uiop)24980Sstevel@tonic-gate pr_read_lwpusage_32(prnode_t *pnp, uio_t *uiop)
24990Sstevel@tonic-gate {
25000Sstevel@tonic-gate 	prhusage_t *pup;
25010Sstevel@tonic-gate 	prusage32_t *upup;
25020Sstevel@tonic-gate 	proc_t *p;
25030Sstevel@tonic-gate 	int error;
25040Sstevel@tonic-gate 
25050Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPUSAGE);
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 	/* allocate now, before locking the process */
25080Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
25090Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	/*
25120Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
25130Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
25140Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
25150Sstevel@tonic-gate 	 */
25160Sstevel@tonic-gate 	p = pr_p_lock(pnp);
25170Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
25180Sstevel@tonic-gate 	if (p == NULL) {
25190Sstevel@tonic-gate 		error = ENOENT;
25200Sstevel@tonic-gate 		goto out;
25210Sstevel@tonic-gate 	}
25220Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
25230Sstevel@tonic-gate 	if (pnp->pr_common->prc_thread == NULL) {
25240Sstevel@tonic-gate 		prunlock(pnp);
25250Sstevel@tonic-gate 		error = ENOENT;
25260Sstevel@tonic-gate 		goto out;
25270Sstevel@tonic-gate 	}
25280Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage32_t)) {
25290Sstevel@tonic-gate 		prunlock(pnp);
25300Sstevel@tonic-gate 		error = 0;
25310Sstevel@tonic-gate 		goto out;
25320Sstevel@tonic-gate 	}
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
25350Sstevel@tonic-gate 	prgetusage(pnp->pr_common->prc_thread, pup);
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 	prunlock(pnp);
25380Sstevel@tonic-gate 
25390Sstevel@tonic-gate 	prcvtusage32(pup, upup);
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage32_t), uiop);
25420Sstevel@tonic-gate out:
25430Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
25440Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
25450Sstevel@tonic-gate 	return (error);
25460Sstevel@tonic-gate }
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate #if defined(__sparc)
25490Sstevel@tonic-gate static int
pr_read_gwindows_32(prnode_t * pnp,uio_t * uiop)25500Sstevel@tonic-gate pr_read_gwindows_32(prnode_t *pnp, uio_t *uiop)
25510Sstevel@tonic-gate {
25520Sstevel@tonic-gate 	proc_t *p;
25530Sstevel@tonic-gate 	kthread_t *t;
25540Sstevel@tonic-gate 	gwindows32_t *gwp;
25550Sstevel@tonic-gate 	int error;
25560Sstevel@tonic-gate 	size_t size;
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_GWINDOWS);
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 	gwp = kmem_zalloc(sizeof (gwindows32_t), KM_SLEEP);
25610Sstevel@tonic-gate 
25620Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
25630Sstevel@tonic-gate 		goto out;
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
25660Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
25690Sstevel@tonic-gate 		prunlock(pnp);
25700Sstevel@tonic-gate 		error = EOVERFLOW;
25710Sstevel@tonic-gate 		goto out;
25720Sstevel@tonic-gate 	}
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 	/*
25750Sstevel@tonic-gate 	 * Drop p->p_lock while touching the stack.
25760Sstevel@tonic-gate 	 * The P_PR_LOCK flag prevents the lwp from
25770Sstevel@tonic-gate 	 * disappearing while we do this.
25780Sstevel@tonic-gate 	 */
25790Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
25800Sstevel@tonic-gate 	if ((size = prnwindows(ttolwp(t))) != 0)
25810Sstevel@tonic-gate 		size = sizeof (gwindows32_t) -
25820Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW - size) * sizeof (struct rwindow32);
25830Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
25840Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
25850Sstevel@tonic-gate 		prunlock(pnp);
25860Sstevel@tonic-gate 		goto out;
25870Sstevel@tonic-gate 	}
25880Sstevel@tonic-gate 	prgetwindows32(ttolwp(t), gwp);
25890Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
25900Sstevel@tonic-gate 	prunlock(pnp);
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate 	error = pr_uioread(gwp, size, uiop);
25930Sstevel@tonic-gate out:
25940Sstevel@tonic-gate 	kmem_free(gwp, sizeof (gwindows32_t));
25950Sstevel@tonic-gate 	return (error);
25960Sstevel@tonic-gate }
25970Sstevel@tonic-gate #endif	/* __sparc */
25980Sstevel@tonic-gate 
25990Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate /* ARGSUSED */
26020Sstevel@tonic-gate static int
prread(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)26030Sstevel@tonic-gate prread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
26040Sstevel@tonic-gate {
26050Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
26080Sstevel@tonic-gate 
26090Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
26100Sstevel@tonic-gate 	/*
26110Sstevel@tonic-gate 	 * What is read from the /proc files depends on the data
26120Sstevel@tonic-gate 	 * model of the caller.  An LP64 process will see LP64
26130Sstevel@tonic-gate 	 * data.  An ILP32 process will see ILP32 data.
26140Sstevel@tonic-gate 	 */
26150Sstevel@tonic-gate 	if (curproc->p_model == DATAMODEL_LP64)
26160Sstevel@tonic-gate 		return (pr_read_function[pnp->pr_type](pnp, uiop));
26170Sstevel@tonic-gate 	else
26180Sstevel@tonic-gate 		return (pr_read_function_32[pnp->pr_type](pnp, uiop));
26190Sstevel@tonic-gate #else
26200Sstevel@tonic-gate 	return (pr_read_function[pnp->pr_type](pnp, uiop));
26210Sstevel@tonic-gate #endif
26220Sstevel@tonic-gate }
26230Sstevel@tonic-gate 
26240Sstevel@tonic-gate /* ARGSUSED */
26250Sstevel@tonic-gate static int
prwrite(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)26260Sstevel@tonic-gate prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
26270Sstevel@tonic-gate {
26280Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
26290Sstevel@tonic-gate 	int old = 0;
26300Sstevel@tonic-gate 	int error;
26310Sstevel@tonic-gate 	ssize_t resid;
26320Sstevel@tonic-gate 
26330Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
26340Sstevel@tonic-gate 
26350Sstevel@tonic-gate 	/*
26360Sstevel@tonic-gate 	 * Only a handful of /proc files are writable, enumerate them here.
26370Sstevel@tonic-gate 	 */
26380Sstevel@tonic-gate 	switch (pnp->pr_type) {
26390Sstevel@tonic-gate 	case PR_PIDDIR:		/* directory write()s: visceral revulsion. */
26400Sstevel@tonic-gate 		ASSERT(pnp->pr_pidfile != NULL);
26410Sstevel@tonic-gate 		/* use the underlying PR_PIDFILE to write the process */
26420Sstevel@tonic-gate 		vp = pnp->pr_pidfile;
26430Sstevel@tonic-gate 		pnp = VTOP(vp);
26440Sstevel@tonic-gate 		ASSERT(pnp->pr_type == PR_PIDFILE);
26450Sstevel@tonic-gate 		/* FALLTHROUGH */
26460Sstevel@tonic-gate 	case PR_PIDFILE:
26470Sstevel@tonic-gate 	case PR_LWPIDFILE:
26480Sstevel@tonic-gate 		old = 1;
26490Sstevel@tonic-gate 		/* FALLTHROUGH */
26500Sstevel@tonic-gate 	case PR_AS:
26510Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) == 0) {
26520Sstevel@tonic-gate 			proc_t *p = pnp->pr_common->prc_proc;
26530Sstevel@tonic-gate 			struct as *as = p->p_as;
26540Sstevel@tonic-gate 
26550Sstevel@tonic-gate 			if ((p->p_flag & SSYS) || as == &kas) {
26560Sstevel@tonic-gate 				/*
26570Sstevel@tonic-gate 				 * /proc I/O cannot be done to a system process.
26580Sstevel@tonic-gate 				 */
26590Sstevel@tonic-gate 				error = EIO;
26600Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
26610Sstevel@tonic-gate 			} else if (curproc->p_model == DATAMODEL_ILP32 &&
26620Sstevel@tonic-gate 			    PROCESS_NOT_32BIT(p)) {
26630Sstevel@tonic-gate 				error = EOVERFLOW;
26640Sstevel@tonic-gate #endif
26650Sstevel@tonic-gate 			} else {
26660Sstevel@tonic-gate 				/*
26670Sstevel@tonic-gate 				 * See comments above (pr_read_pidfile)
26680Sstevel@tonic-gate 				 * about this locking dance.
26690Sstevel@tonic-gate 				 */
26700Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
26710Sstevel@tonic-gate 				error = prusrio(p, UIO_WRITE, uiop, old);
26720Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
26730Sstevel@tonic-gate 			}
26740Sstevel@tonic-gate 			prunlock(pnp);
26750Sstevel@tonic-gate 		}
26760Sstevel@tonic-gate 		return (error);
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 	case PR_CTL:
26790Sstevel@tonic-gate 	case PR_LWPCTL:
26800Sstevel@tonic-gate 		resid = uiop->uio_resid;
26810Sstevel@tonic-gate 		/*
26820Sstevel@tonic-gate 		 * Perform the action on the control file
26830Sstevel@tonic-gate 		 * by passing curthreads credentials
26840Sstevel@tonic-gate 		 * and not target process's credentials.
26850Sstevel@tonic-gate 		 */
26860Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
26870Sstevel@tonic-gate 		if (curproc->p_model == DATAMODEL_ILP32)
26880Sstevel@tonic-gate 			error = prwritectl32(vp, uiop, CRED());
26890Sstevel@tonic-gate 		else
26900Sstevel@tonic-gate 			error = prwritectl(vp, uiop, CRED());
26910Sstevel@tonic-gate #else
26920Sstevel@tonic-gate 		error = prwritectl(vp, uiop, CRED());
26930Sstevel@tonic-gate #endif
26940Sstevel@tonic-gate 		/*
26950Sstevel@tonic-gate 		 * This hack makes sure that the EINTR is passed
26960Sstevel@tonic-gate 		 * all the way back to the caller's write() call.
26970Sstevel@tonic-gate 		 */
26980Sstevel@tonic-gate 		if (error == EINTR)
26990Sstevel@tonic-gate 			uiop->uio_resid = resid;
27000Sstevel@tonic-gate 		return (error);
27010Sstevel@tonic-gate 
27020Sstevel@tonic-gate 	default:
27030Sstevel@tonic-gate 		return ((vp->v_type == VDIR)? EISDIR : EBADF);
27040Sstevel@tonic-gate 	}
27050Sstevel@tonic-gate 	/* NOTREACHED */
27060Sstevel@tonic-gate }
27070Sstevel@tonic-gate 
27080Sstevel@tonic-gate static int
prgetattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)27095331Samw prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
27105331Samw 	caller_context_t *ct)
27110Sstevel@tonic-gate {
27120Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
27130Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
27140Sstevel@tonic-gate 	prcommon_t *pcp;
27150Sstevel@tonic-gate 	proc_t *p;
27160Sstevel@tonic-gate 	struct as *as;
27170Sstevel@tonic-gate 	int error;
27180Sstevel@tonic-gate 	vnode_t *rvp;
27190Sstevel@tonic-gate 	timestruc_t now;
27200Sstevel@tonic-gate 	extern uint_t nproc;
27210Sstevel@tonic-gate 	int ngroups;
272211940SRoger.Faulkner@Sun.COM 	int nsig;
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	/*
27250Sstevel@tonic-gate 	 * This ugly bit of code allows us to keep both versions of this
27260Sstevel@tonic-gate 	 * function from the same source.
27270Sstevel@tonic-gate 	 */
27280Sstevel@tonic-gate #ifdef _LP64
27290Sstevel@tonic-gate 	int iam32bit = (curproc->p_model == DATAMODEL_ILP32);
27300Sstevel@tonic-gate #define	PR_OBJSIZE(obj32, obj64)	\
27310Sstevel@tonic-gate 	(iam32bit ? sizeof (obj32) : sizeof (obj64))
27320Sstevel@tonic-gate #define	PR_OBJSPAN(obj32, obj64)	\
27330Sstevel@tonic-gate 	(iam32bit ? LSPAN32(obj32) : LSPAN(obj64))
27340Sstevel@tonic-gate #else
27350Sstevel@tonic-gate #define	PR_OBJSIZE(obj32, obj64)	\
27360Sstevel@tonic-gate 	(sizeof (obj64))
27370Sstevel@tonic-gate #define	PR_OBJSPAN(obj32, obj64)	\
27380Sstevel@tonic-gate 	(LSPAN(obj64))
27390Sstevel@tonic-gate #endif
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 	/*
27420Sstevel@tonic-gate 	 * Return all the attributes.  Should be refined
27430Sstevel@tonic-gate 	 * so that it returns only those asked for.
27440Sstevel@tonic-gate 	 * Most of this is complete fakery anyway.
27450Sstevel@tonic-gate 	 */
27460Sstevel@tonic-gate 
27470Sstevel@tonic-gate 	/*
27480Sstevel@tonic-gate 	 * For files in the /proc/<pid>/object directory,
27490Sstevel@tonic-gate 	 * return the attributes of the underlying object.
27500Sstevel@tonic-gate 	 * For files in the /proc/<pid>/fd directory,
27510Sstevel@tonic-gate 	 * return the attributes of the underlying file, but
27520Sstevel@tonic-gate 	 * make it look inaccessible if it is not a regular file.
27530Sstevel@tonic-gate 	 * Make directories look like symlinks.
27540Sstevel@tonic-gate 	 */
27550Sstevel@tonic-gate 	switch (type) {
27560Sstevel@tonic-gate 	case PR_CURDIR:
27570Sstevel@tonic-gate 	case PR_ROOTDIR:
27580Sstevel@tonic-gate 		if (!(flags & ATTR_REAL))
27590Sstevel@tonic-gate 			break;
27600Sstevel@tonic-gate 		/* restrict full knowledge of the attributes to owner or root */
27615331Samw 		if ((error = praccess(vp, 0, 0, cr, ct)) != 0)
27620Sstevel@tonic-gate 			return (error);
27630Sstevel@tonic-gate 		/* FALLTHROUGH */
27640Sstevel@tonic-gate 	case PR_OBJECT:
27650Sstevel@tonic-gate 	case PR_FD:
27660Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
27675331Samw 		error = VOP_GETATTR(rvp, vap, flags, cr, ct);
27680Sstevel@tonic-gate 		if (error)
27690Sstevel@tonic-gate 			return (error);
27700Sstevel@tonic-gate 		if (type == PR_FD) {
27710Sstevel@tonic-gate 			if (rvp->v_type != VREG && rvp->v_type != VDIR)
27720Sstevel@tonic-gate 				vap->va_mode = 0;
27730Sstevel@tonic-gate 			else
27740Sstevel@tonic-gate 				vap->va_mode &= pnp->pr_mode;
27750Sstevel@tonic-gate 		}
27760Sstevel@tonic-gate 		if (type == PR_OBJECT)
27770Sstevel@tonic-gate 			vap->va_mode &= 07555;
27780Sstevel@tonic-gate 		if (rvp->v_type == VDIR && !(flags & ATTR_REAL)) {
27790Sstevel@tonic-gate 			vap->va_type = VLNK;
27800Sstevel@tonic-gate 			vap->va_size = 0;
27810Sstevel@tonic-gate 			vap->va_nlink = 1;
27820Sstevel@tonic-gate 		}
27830Sstevel@tonic-gate 		return (0);
27840Sstevel@tonic-gate 	default:
27850Sstevel@tonic-gate 		break;
27860Sstevel@tonic-gate 	}
27870Sstevel@tonic-gate 
27880Sstevel@tonic-gate 	bzero(vap, sizeof (*vap));
27890Sstevel@tonic-gate 	/*
27900Sstevel@tonic-gate 	 * Large Files: Internally proc now uses VPROC to indicate
27910Sstevel@tonic-gate 	 * a proc file. Since we have been returning VREG through
27920Sstevel@tonic-gate 	 * VOP_GETATTR() until now, we continue to do this so as
27930Sstevel@tonic-gate 	 * not to break apps depending on this return value.
27940Sstevel@tonic-gate 	 */
27950Sstevel@tonic-gate 	vap->va_type = (vp->v_type == VPROC) ? VREG : vp->v_type;
27960Sstevel@tonic-gate 	vap->va_mode = pnp->pr_mode;
27970Sstevel@tonic-gate 	vap->va_fsid = vp->v_vfsp->vfs_dev;
27980Sstevel@tonic-gate 	vap->va_blksize = DEV_BSIZE;
27990Sstevel@tonic-gate 	vap->va_rdev = 0;
28000Sstevel@tonic-gate 	vap->va_seq = 0;
28010Sstevel@tonic-gate 
28020Sstevel@tonic-gate 	if (type == PR_PROCDIR) {
28030Sstevel@tonic-gate 		vap->va_uid = 0;
28040Sstevel@tonic-gate 		vap->va_gid = 0;
28050Sstevel@tonic-gate 		vap->va_nlink = nproc + 2;
28060Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)PRROOTINO;
28070Sstevel@tonic-gate 		gethrestime(&now);
28080Sstevel@tonic-gate 		vap->va_atime = vap->va_mtime = vap->va_ctime = now;
28090Sstevel@tonic-gate 		vap->va_size = (v.v_proc + 2) * PRSDSIZE;
28100Sstevel@tonic-gate 		vap->va_nblocks = btod(vap->va_size);
28110Sstevel@tonic-gate 		return (0);
28120Sstevel@tonic-gate 	}
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate 	/*
28150Sstevel@tonic-gate 	 * /proc/<pid>/self is a symbolic link, and has no prcommon member
28160Sstevel@tonic-gate 	 */
28170Sstevel@tonic-gate 	if (type == PR_SELF) {
28180Sstevel@tonic-gate 		vap->va_uid = crgetruid(CRED());
28190Sstevel@tonic-gate 		vap->va_gid = crgetrgid(CRED());
28200Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)PR_SELF;
28210Sstevel@tonic-gate 		gethrestime(&now);
28220Sstevel@tonic-gate 		vap->va_atime = vap->va_mtime = vap->va_ctime = now;
28230Sstevel@tonic-gate 		vap->va_nlink = 1;
28240Sstevel@tonic-gate 		vap->va_type = VLNK;
28250Sstevel@tonic-gate 		vap->va_size = 0;
28260Sstevel@tonic-gate 		return (0);
28270Sstevel@tonic-gate 	}
28280Sstevel@tonic-gate 
28290Sstevel@tonic-gate 	p = pr_p_lock(pnp);
28300Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
28310Sstevel@tonic-gate 	if (p == NULL)
28320Sstevel@tonic-gate 		return (ENOENT);
28330Sstevel@tonic-gate 	pcp = pnp->pr_common;
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
28360Sstevel@tonic-gate 	vap->va_uid = crgetruid(p->p_cred);
28370Sstevel@tonic-gate 	vap->va_gid = crgetrgid(p->p_cred);
28380Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
28390Sstevel@tonic-gate 
28400Sstevel@tonic-gate 	vap->va_nlink = 1;
28410Sstevel@tonic-gate 	vap->va_nodeid = pnp->pr_ino? pnp->pr_ino :
28425663Sck153898 	    pmkino(pcp->prc_tslot, pcp->prc_slot, pnp->pr_type);
28430Sstevel@tonic-gate 	if ((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot != -1) {
28440Sstevel@tonic-gate 		vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
28450Sstevel@tonic-gate 		    vap->va_ctime.tv_sec =
28460Sstevel@tonic-gate 		    p->p_lwpdir[pcp->prc_tslot].ld_entry->le_start;
28470Sstevel@tonic-gate 		vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec =
28480Sstevel@tonic-gate 		    vap->va_ctime.tv_nsec = 0;
28490Sstevel@tonic-gate 	} else {
28500Sstevel@tonic-gate 		user_t *up = PTOU(p);
28510Sstevel@tonic-gate 		vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
28520Sstevel@tonic-gate 		    vap->va_ctime.tv_sec = up->u_start.tv_sec;
28530Sstevel@tonic-gate 		vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec =
28540Sstevel@tonic-gate 		    vap->va_ctime.tv_nsec = up->u_start.tv_nsec;
28550Sstevel@tonic-gate 	}
28560Sstevel@tonic-gate 
28570Sstevel@tonic-gate 	switch (type) {
28580Sstevel@tonic-gate 	case PR_PIDDIR:
28590Sstevel@tonic-gate 		/* va_nlink: count 'lwp', 'object' and 'fd' directory links */
28600Sstevel@tonic-gate 		vap->va_nlink = 5;
28610Sstevel@tonic-gate 		vap->va_size = sizeof (piddir);
28620Sstevel@tonic-gate 		break;
28630Sstevel@tonic-gate 	case PR_OBJECTDIR:
28640Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
28650Sstevel@tonic-gate 			vap->va_size = 2 * PRSDSIZE;
28660Sstevel@tonic-gate 		else {
28670Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
28680Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
28690Sstevel@tonic-gate 			if (as->a_updatedir)
28700Sstevel@tonic-gate 				rebuild_objdir(as);
28710Sstevel@tonic-gate 			vap->va_size = (as->a_sizedir + 2) * PRSDSIZE;
28720Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
28730Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
28740Sstevel@tonic-gate 		}
28750Sstevel@tonic-gate 		vap->va_nlink = 2;
28760Sstevel@tonic-gate 		break;
28770Sstevel@tonic-gate 	case PR_PATHDIR:
28780Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
28790Sstevel@tonic-gate 			vap->va_size = (P_FINFO(p)->fi_nfiles + 4) * PRSDSIZE;
28800Sstevel@tonic-gate 		else {
28810Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
28820Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
28830Sstevel@tonic-gate 			if (as->a_updatedir)
28840Sstevel@tonic-gate 				rebuild_objdir(as);
28850Sstevel@tonic-gate 			vap->va_size = (as->a_sizedir + 4 +
28860Sstevel@tonic-gate 			    P_FINFO(p)->fi_nfiles) * PRSDSIZE;
28870Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
28880Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
28890Sstevel@tonic-gate 		}
28900Sstevel@tonic-gate 		vap->va_nlink = 2;
28910Sstevel@tonic-gate 		break;
28920Sstevel@tonic-gate 	case PR_PATH:
28930Sstevel@tonic-gate 	case PR_CURDIR:
28940Sstevel@tonic-gate 	case PR_ROOTDIR:
28950Sstevel@tonic-gate 	case PR_CT:
28960Sstevel@tonic-gate 		vap->va_type = VLNK;
28970Sstevel@tonic-gate 		vap->va_size = 0;
28980Sstevel@tonic-gate 		break;
28990Sstevel@tonic-gate 	case PR_FDDIR:
29000Sstevel@tonic-gate 		vap->va_nlink = 2;
29010Sstevel@tonic-gate 		vap->va_size = (P_FINFO(p)->fi_nfiles + 2) * PRSDSIZE;
29020Sstevel@tonic-gate 		break;
29030Sstevel@tonic-gate 	case PR_LWPDIR:
29040Sstevel@tonic-gate 		/*
29050Sstevel@tonic-gate 		 * va_nlink: count each lwp as a directory link.
29060Sstevel@tonic-gate 		 * va_size: size of p_lwpdir + 2
29070Sstevel@tonic-gate 		 */
29080Sstevel@tonic-gate 		vap->va_nlink = p->p_lwpcnt + p->p_zombcnt + 2;
29090Sstevel@tonic-gate 		vap->va_size = (p->p_lwpdir_sz + 2) * PRSDSIZE;
29100Sstevel@tonic-gate 		break;
29110Sstevel@tonic-gate 	case PR_LWPIDDIR:
29120Sstevel@tonic-gate 		vap->va_nlink = 2;
29130Sstevel@tonic-gate 		vap->va_size = sizeof (lwpiddir);
29140Sstevel@tonic-gate 		break;
29150Sstevel@tonic-gate 	case PR_CTDIR:
29160Sstevel@tonic-gate 		vap->va_nlink = 2;
29170Sstevel@tonic-gate 		vap->va_size = (avl_numnodes(&p->p_ct_held) + 2) * PRSDSIZE;
29180Sstevel@tonic-gate 		break;
29190Sstevel@tonic-gate 	case PR_TMPLDIR:
29200Sstevel@tonic-gate 		vap->va_nlink = 2;
29210Sstevel@tonic-gate 		vap->va_size = (ct_ntypes + 2) * PRSDSIZE;
29220Sstevel@tonic-gate 		break;
29230Sstevel@tonic-gate 	case PR_AS:
29240Sstevel@tonic-gate 	case PR_PIDFILE:
29250Sstevel@tonic-gate 	case PR_LWPIDFILE:
29260Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
29270Sstevel@tonic-gate 			vap->va_size = 0;
292810169SSudheer.Abdul-Salam@Sun.COM 		else
292910169SSudheer.Abdul-Salam@Sun.COM 			vap->va_size = as->a_resvsize;
29300Sstevel@tonic-gate 		break;
29310Sstevel@tonic-gate 	case PR_STATUS:
29320Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(pstatus32_t, pstatus_t);
29330Sstevel@tonic-gate 		break;
29340Sstevel@tonic-gate 	case PR_LSTATUS:
29350Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
29360Sstevel@tonic-gate 		    p->p_lwpcnt * PR_OBJSPAN(lwpstatus32_t, lwpstatus_t);
29370Sstevel@tonic-gate 		break;
29380Sstevel@tonic-gate 	case PR_PSINFO:
29390Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(psinfo32_t, psinfo_t);
29400Sstevel@tonic-gate 		break;
29410Sstevel@tonic-gate 	case PR_LPSINFO:
29420Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
29430Sstevel@tonic-gate 		    (p->p_lwpcnt + p->p_zombcnt) *
29440Sstevel@tonic-gate 		    PR_OBJSPAN(lwpsinfo32_t, lwpsinfo_t);
29450Sstevel@tonic-gate 		break;
29460Sstevel@tonic-gate 	case PR_MAP:
29470Sstevel@tonic-gate 	case PR_RMAP:
29480Sstevel@tonic-gate 	case PR_XMAP:
29490Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
29500Sstevel@tonic-gate 			vap->va_size = 0;
29510Sstevel@tonic-gate 		else {
29520Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
29530Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
29540Sstevel@tonic-gate 			if (type == PR_MAP)
29550Sstevel@tonic-gate 				vap->va_mtime = as->a_updatetime;
29560Sstevel@tonic-gate 			if (type == PR_XMAP)
29570Sstevel@tonic-gate 				vap->va_size = prnsegs(as, 0) *
29580Sstevel@tonic-gate 				    PR_OBJSIZE(prxmap32_t, prxmap_t);
29590Sstevel@tonic-gate 			else
29600Sstevel@tonic-gate 				vap->va_size = prnsegs(as, type == PR_RMAP) *
29610Sstevel@tonic-gate 				    PR_OBJSIZE(prmap32_t, prmap_t);
29620Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
29630Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
29640Sstevel@tonic-gate 		}
29650Sstevel@tonic-gate 		break;
29660Sstevel@tonic-gate 	case PR_CRED:
29670Sstevel@tonic-gate 		mutex_enter(&p->p_crlock);
29680Sstevel@tonic-gate 		vap->va_size = sizeof (prcred_t);
29690Sstevel@tonic-gate 		ngroups = crgetngroups(p->p_cred);
29700Sstevel@tonic-gate 		if (ngroups > 1)
29710Sstevel@tonic-gate 			vap->va_size += (ngroups - 1) * sizeof (gid_t);
29720Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
29730Sstevel@tonic-gate 		break;
29740Sstevel@tonic-gate 	case PR_PRIV:
29750Sstevel@tonic-gate 		vap->va_size = prgetprivsize();
29760Sstevel@tonic-gate 		break;
29770Sstevel@tonic-gate 	case PR_SIGACT:
297811940SRoger.Faulkner@Sun.COM 		nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
297911940SRoger.Faulkner@Sun.COM 		vap->va_size = (nsig-1) *
29800Sstevel@tonic-gate 		    PR_OBJSIZE(struct sigaction32, struct sigaction);
29810Sstevel@tonic-gate 		break;
29820Sstevel@tonic-gate 	case PR_AUXV:
29830Sstevel@tonic-gate 		vap->va_size = __KERN_NAUXV_IMPL * PR_OBJSIZE(auxv32_t, auxv_t);
29840Sstevel@tonic-gate 		break;
29850Sstevel@tonic-gate #if defined(__x86)
29860Sstevel@tonic-gate 	case PR_LDT:
29878921SVamsi.Krishna@Sun.COM 		mutex_exit(&p->p_lock);
29880Sstevel@tonic-gate 		mutex_enter(&p->p_ldtlock);
29890Sstevel@tonic-gate 		vap->va_size = prnldt(p) * sizeof (struct ssd);
29900Sstevel@tonic-gate 		mutex_exit(&p->p_ldtlock);
29918921SVamsi.Krishna@Sun.COM 		mutex_enter(&p->p_lock);
29920Sstevel@tonic-gate 		break;
29930Sstevel@tonic-gate #endif
29940Sstevel@tonic-gate 	case PR_USAGE:
29950Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prusage32_t, prusage_t);
29960Sstevel@tonic-gate 		break;
29970Sstevel@tonic-gate 	case PR_LUSAGE:
29980Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
29990Sstevel@tonic-gate 		    (p->p_lwpcnt + 1) * PR_OBJSPAN(prusage32_t, prusage_t);
30000Sstevel@tonic-gate 		break;
30010Sstevel@tonic-gate 	case PR_PAGEDATA:
30020Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
30030Sstevel@tonic-gate 			vap->va_size = 0;
30040Sstevel@tonic-gate 		else {
30050Sstevel@tonic-gate 			/*
30060Sstevel@tonic-gate 			 * We can drop p->p_lock before grabbing the
30070Sstevel@tonic-gate 			 * address space lock because p->p_as will not
30080Sstevel@tonic-gate 			 * change while the process is marked P_PR_LOCK.
30090Sstevel@tonic-gate 			 */
30100Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
30110Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
30120Sstevel@tonic-gate #ifdef _LP64
30130Sstevel@tonic-gate 			vap->va_size = iam32bit?
30140Sstevel@tonic-gate 			    prpdsize32(as) : prpdsize(as);
30150Sstevel@tonic-gate #else
30160Sstevel@tonic-gate 			vap->va_size = prpdsize(as);
30170Sstevel@tonic-gate #endif
30180Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
30190Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
30200Sstevel@tonic-gate 		}
30210Sstevel@tonic-gate 		break;
30220Sstevel@tonic-gate 	case PR_OPAGEDATA:
30230Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
30240Sstevel@tonic-gate 			vap->va_size = 0;
30250Sstevel@tonic-gate 		else {
30260Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
30270Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
30280Sstevel@tonic-gate #ifdef _LP64
30290Sstevel@tonic-gate 			vap->va_size = iam32bit?
30300Sstevel@tonic-gate 			    oprpdsize32(as) : oprpdsize(as);
30310Sstevel@tonic-gate #else
30320Sstevel@tonic-gate 			vap->va_size = oprpdsize(as);
30330Sstevel@tonic-gate #endif
30340Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
30350Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
30360Sstevel@tonic-gate 		}
30370Sstevel@tonic-gate 		break;
30380Sstevel@tonic-gate 	case PR_WATCH:
30390Sstevel@tonic-gate 		vap->va_size = avl_numnodes(&p->p_warea) *
30400Sstevel@tonic-gate 		    PR_OBJSIZE(prwatch32_t, prwatch_t);
30410Sstevel@tonic-gate 		break;
30420Sstevel@tonic-gate 	case PR_LWPSTATUS:
30430Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(lwpstatus32_t, lwpstatus_t);
30440Sstevel@tonic-gate 		break;
30450Sstevel@tonic-gate 	case PR_LWPSINFO:
30460Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(lwpsinfo32_t, lwpsinfo_t);
30470Sstevel@tonic-gate 		break;
30480Sstevel@tonic-gate 	case PR_LWPUSAGE:
30490Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prusage32_t, prusage_t);
30500Sstevel@tonic-gate 		break;
30510Sstevel@tonic-gate 	case PR_XREGS:
30520Sstevel@tonic-gate 		if (prhasx(p))
30530Sstevel@tonic-gate 			vap->va_size = prgetprxregsize(p);
30540Sstevel@tonic-gate 		else
30550Sstevel@tonic-gate 			vap->va_size = 0;
30560Sstevel@tonic-gate 		break;
30570Sstevel@tonic-gate #if defined(__sparc)
30580Sstevel@tonic-gate 	case PR_GWINDOWS:
30590Sstevel@tonic-gate 	{
30600Sstevel@tonic-gate 		kthread_t *t;
30610Sstevel@tonic-gate 		int n;
30620Sstevel@tonic-gate 
30630Sstevel@tonic-gate 		/*
30640Sstevel@tonic-gate 		 * If there is no lwp then just make the size zero.
30650Sstevel@tonic-gate 		 * This can happen if the lwp exits between the VOP_LOOKUP()
30660Sstevel@tonic-gate 		 * of the /proc/<pid>/lwp/<lwpid>/gwindows file and the
30670Sstevel@tonic-gate 		 * VOP_GETATTR() of the resulting vnode.
30680Sstevel@tonic-gate 		 */
30690Sstevel@tonic-gate 		if ((t = pcp->prc_thread) == NULL) {
30700Sstevel@tonic-gate 			vap->va_size = 0;
30710Sstevel@tonic-gate 			break;
30720Sstevel@tonic-gate 		}
30730Sstevel@tonic-gate 		/*
30740Sstevel@tonic-gate 		 * Drop p->p_lock while touching the stack.
30750Sstevel@tonic-gate 		 * The P_PR_LOCK flag prevents the lwp from
30760Sstevel@tonic-gate 		 * disappearing while we do this.
30770Sstevel@tonic-gate 		 */
30780Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
30790Sstevel@tonic-gate 		if ((n = prnwindows(ttolwp(t))) == 0)
30800Sstevel@tonic-gate 			vap->va_size = 0;
30810Sstevel@tonic-gate 		else
30820Sstevel@tonic-gate 			vap->va_size = PR_OBJSIZE(gwindows32_t, gwindows_t) -
30830Sstevel@tonic-gate 			    (SPARC_MAXREGWINDOW - n) *
30840Sstevel@tonic-gate 			    PR_OBJSIZE(struct rwindow32, struct rwindow);
30850Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
30860Sstevel@tonic-gate 		break;
30870Sstevel@tonic-gate 	}
30880Sstevel@tonic-gate 	case PR_ASRS:
30890Sstevel@tonic-gate #ifdef _LP64
30900Sstevel@tonic-gate 		if (p->p_model == DATAMODEL_LP64)
30910Sstevel@tonic-gate 			vap->va_size = sizeof (asrset_t);
30920Sstevel@tonic-gate 		else
30930Sstevel@tonic-gate #endif
30940Sstevel@tonic-gate 			vap->va_size = 0;
30950Sstevel@tonic-gate 		break;
30960Sstevel@tonic-gate #endif
30970Sstevel@tonic-gate 	case PR_CTL:
30980Sstevel@tonic-gate 	case PR_LWPCTL:
30990Sstevel@tonic-gate 	default:
31000Sstevel@tonic-gate 		vap->va_size = 0;
31010Sstevel@tonic-gate 		break;
31020Sstevel@tonic-gate 	}
31030Sstevel@tonic-gate 
31040Sstevel@tonic-gate 	prunlock(pnp);
31050Sstevel@tonic-gate 	vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
31060Sstevel@tonic-gate 	return (0);
31070Sstevel@tonic-gate }
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate static int
praccess(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)31105331Samw praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
31110Sstevel@tonic-gate {
31120Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
31130Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
31140Sstevel@tonic-gate 	int vmode;
31150Sstevel@tonic-gate 	vtype_t vtype;
31160Sstevel@tonic-gate 	proc_t *p;
31170Sstevel@tonic-gate 	int error = 0;
31180Sstevel@tonic-gate 	vnode_t *rvp;
31190Sstevel@tonic-gate 	vnode_t *xvp;
31200Sstevel@tonic-gate 
31210Sstevel@tonic-gate 	if ((mode & VWRITE) && vn_is_readonly(vp))
31220Sstevel@tonic-gate 		return (EROFS);
31230Sstevel@tonic-gate 
31240Sstevel@tonic-gate 	switch (type) {
31250Sstevel@tonic-gate 	case PR_PROCDIR:
31260Sstevel@tonic-gate 		break;
31270Sstevel@tonic-gate 
31280Sstevel@tonic-gate 	case PR_OBJECT:
31290Sstevel@tonic-gate 	case PR_FD:
31300Sstevel@tonic-gate 		/*
31310Sstevel@tonic-gate 		 * Disallow write access to the underlying objects.
31320Sstevel@tonic-gate 		 * Disallow access to underlying non-regular-file fds.
31330Sstevel@tonic-gate 		 * Disallow access to fds with other than existing open modes.
31340Sstevel@tonic-gate 		 */
31350Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
31360Sstevel@tonic-gate 		vtype = rvp->v_type;
31370Sstevel@tonic-gate 		vmode = pnp->pr_mode;
31380Sstevel@tonic-gate 		if ((type == PR_OBJECT && (mode & VWRITE)) ||
31390Sstevel@tonic-gate 		    (type == PR_FD && vtype != VREG && vtype != VDIR) ||
31400Sstevel@tonic-gate 		    (type == PR_FD && (vmode & mode) != mode &&
31410Sstevel@tonic-gate 		    secpolicy_proc_access(cr) != 0))
31420Sstevel@tonic-gate 			return (EACCES);
31435331Samw 		return (VOP_ACCESS(rvp, mode, flags, cr, ct));
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 	case PR_PSINFO:		/* these files can be read by anyone */
31460Sstevel@tonic-gate 	case PR_LPSINFO:
31470Sstevel@tonic-gate 	case PR_LWPSINFO:
31480Sstevel@tonic-gate 	case PR_LWPDIR:
31490Sstevel@tonic-gate 	case PR_LWPIDDIR:
31500Sstevel@tonic-gate 	case PR_USAGE:
31510Sstevel@tonic-gate 	case PR_LUSAGE:
31520Sstevel@tonic-gate 	case PR_LWPUSAGE:
31530Sstevel@tonic-gate 		p = pr_p_lock(pnp);
31540Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
31550Sstevel@tonic-gate 		if (p == NULL)
31560Sstevel@tonic-gate 			return (ENOENT);
31570Sstevel@tonic-gate 		prunlock(pnp);
31580Sstevel@tonic-gate 		break;
31590Sstevel@tonic-gate 
31600Sstevel@tonic-gate 	default:
31610Sstevel@tonic-gate 		/*
31620Sstevel@tonic-gate 		 * Except for the world-readable files above,
31630Sstevel@tonic-gate 		 * only /proc/pid exists if the process is a zombie.
31640Sstevel@tonic-gate 		 */
31650Sstevel@tonic-gate 		if ((error = prlock(pnp,
31660Sstevel@tonic-gate 		    (type == PR_PIDDIR)? ZYES : ZNO)) != 0)
31670Sstevel@tonic-gate 			return (error);
31680Sstevel@tonic-gate 		p = pnp->pr_common->prc_proc;
31690Sstevel@tonic-gate 		if (p != curproc)
31700Sstevel@tonic-gate 			error = priv_proc_cred_perm(cr, p, NULL, mode);
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate 		if (error != 0 || p == curproc || (p->p_flag & SSYS) ||
31736134Scasper 		    p->p_as == &kas || (xvp = p->p_exec) == NULL) {
31740Sstevel@tonic-gate 			prunlock(pnp);
31750Sstevel@tonic-gate 		} else {
31760Sstevel@tonic-gate 			/*
31770Sstevel@tonic-gate 			 * Determine if the process's executable is readable.
31786134Scasper 			 * We have to drop p->p_lock before the secpolicy
31796134Scasper 			 * and VOP operation.
31800Sstevel@tonic-gate 			 */
31810Sstevel@tonic-gate 			VN_HOLD(xvp);
31820Sstevel@tonic-gate 			prunlock(pnp);
31836134Scasper 			if (secpolicy_proc_access(cr) != 0)
31846134Scasper 				error = VOP_ACCESS(xvp, VREAD, 0, cr, ct);
31850Sstevel@tonic-gate 			VN_RELE(xvp);
31860Sstevel@tonic-gate 		}
31870Sstevel@tonic-gate 		if (error)
31880Sstevel@tonic-gate 			return (error);
31890Sstevel@tonic-gate 		break;
31900Sstevel@tonic-gate 	}
31910Sstevel@tonic-gate 
31920Sstevel@tonic-gate 	if (type == PR_CURDIR || type == PR_ROOTDIR) {
31930Sstevel@tonic-gate 		/*
31940Sstevel@tonic-gate 		 * Final access check on the underlying directory vnode.
31950Sstevel@tonic-gate 		 */
31965331Samw 		return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr, ct));
31970Sstevel@tonic-gate 	}
31980Sstevel@tonic-gate 
31990Sstevel@tonic-gate 	/*
32000Sstevel@tonic-gate 	 * Visceral revulsion:  For compatibility with old /proc,
32010Sstevel@tonic-gate 	 * allow the /proc/<pid> directory to be opened for writing.
32020Sstevel@tonic-gate 	 */
32030Sstevel@tonic-gate 	vmode = pnp->pr_mode;
32040Sstevel@tonic-gate 	if (type == PR_PIDDIR)
32050Sstevel@tonic-gate 		vmode |= VWRITE;
32060Sstevel@tonic-gate 	if ((vmode & mode) != mode)
32070Sstevel@tonic-gate 		error = secpolicy_proc_access(cr);
32080Sstevel@tonic-gate 	return (error);
32090Sstevel@tonic-gate }
32100Sstevel@tonic-gate 
32110Sstevel@tonic-gate /*
32120Sstevel@tonic-gate  * Array of lookup functions, indexed by /proc file type.
32130Sstevel@tonic-gate  */
32140Sstevel@tonic-gate static vnode_t *pr_lookup_notdir(), *pr_lookup_procdir(), *pr_lookup_piddir(),
32150Sstevel@tonic-gate 	*pr_lookup_objectdir(), *pr_lookup_lwpdir(), *pr_lookup_lwpiddir(),
32160Sstevel@tonic-gate 	*pr_lookup_fddir(), *pr_lookup_pathdir(), *pr_lookup_tmpldir(),
32170Sstevel@tonic-gate 	*pr_lookup_ctdir();
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
32200Sstevel@tonic-gate 	pr_lookup_procdir,	/* /proc				*/
32210Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/self				*/
32220Sstevel@tonic-gate 	pr_lookup_piddir,	/* /proc/<pid>				*/
32230Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/as			*/
32240Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/ctl			*/
32250Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/status			*/
32260Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lstatus			*/
32270Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/psinfo			*/
32280Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lpsinfo			*/
32290Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/map			*/
32300Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/rmap			*/
32310Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/xmap			*/
32320Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/cred			*/
32330Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/sigact			*/
32340Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/auxv			*/
32350Sstevel@tonic-gate #if defined(__x86)
32360Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/ldt			*/
32370Sstevel@tonic-gate #endif
32380Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/usage			*/
32390Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lusage			*/
32400Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/pagedata			*/
32410Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/watch			*/
32420Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/cwd			*/
32430Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/root			*/
32440Sstevel@tonic-gate 	pr_lookup_fddir,	/* /proc/<pid>/fd			*/
32450Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/fd/nn			*/
32460Sstevel@tonic-gate 	pr_lookup_objectdir,	/* /proc/<pid>/object			*/
32470Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/object/xxx		*/
32480Sstevel@tonic-gate 	pr_lookup_lwpdir,	/* /proc/<pid>/lwp			*/
32490Sstevel@tonic-gate 	pr_lookup_lwpiddir,	/* /proc/<pid>/lwp/<lwpid>		*/
32500Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
32510Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
32520Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
32530Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
32540Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
32550Sstevel@tonic-gate 	pr_lookup_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
32560Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
32570Sstevel@tonic-gate #if defined(__sparc)
32580Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
32590Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
32600Sstevel@tonic-gate #endif
32610Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/priv			*/
32620Sstevel@tonic-gate 	pr_lookup_pathdir,	/* /proc/<pid>/path			*/
32630Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/path/xxx			*/
32640Sstevel@tonic-gate 	pr_lookup_ctdir,	/* /proc/<pid>/contracts		*/
32650Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/contracts/<ctid>		*/
32660Sstevel@tonic-gate 	pr_lookup_notdir,	/* old process file			*/
32670Sstevel@tonic-gate 	pr_lookup_notdir,	/* old lwp file				*/
32680Sstevel@tonic-gate 	pr_lookup_notdir,	/* old pagedata file			*/
32690Sstevel@tonic-gate };
32700Sstevel@tonic-gate 
32710Sstevel@tonic-gate static int
prlookup(vnode_t * dp,char * comp,vnode_t ** vpp,pathname_t * pathp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)32720Sstevel@tonic-gate prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
32735331Samw 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
32745331Samw 	int *direntflags, pathname_t *realpnp)
32750Sstevel@tonic-gate {
32760Sstevel@tonic-gate 	prnode_t *pnp = VTOP(dp);
32770Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
32780Sstevel@tonic-gate 	int error;
32790Sstevel@tonic-gate 
32800Sstevel@tonic-gate 	ASSERT(dp->v_type == VDIR);
32810Sstevel@tonic-gate 	ASSERT(type < PR_NFILES);
32820Sstevel@tonic-gate 
32830Sstevel@tonic-gate 	if (type != PR_PROCDIR && strcmp(comp, "..") == 0) {
32840Sstevel@tonic-gate 		VN_HOLD(pnp->pr_parent);
32850Sstevel@tonic-gate 		*vpp = pnp->pr_parent;
32860Sstevel@tonic-gate 		return (0);
32870Sstevel@tonic-gate 	}
32880Sstevel@tonic-gate 
32890Sstevel@tonic-gate 	if (*comp == '\0' ||
32900Sstevel@tonic-gate 	    strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) {
32910Sstevel@tonic-gate 		VN_HOLD(dp);
32920Sstevel@tonic-gate 		*vpp = dp;
32930Sstevel@tonic-gate 		return (0);
32940Sstevel@tonic-gate 	}
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	switch (type) {
32970Sstevel@tonic-gate 	case PR_CURDIR:
32980Sstevel@tonic-gate 	case PR_ROOTDIR:
32990Sstevel@tonic-gate 		/* restrict lookup permission to owner or root */
33005331Samw 		if ((error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
33010Sstevel@tonic-gate 			return (error);
33020Sstevel@tonic-gate 		/* FALLTHROUGH */
33030Sstevel@tonic-gate 	case PR_FD:
33040Sstevel@tonic-gate 		dp = pnp->pr_realvp;
33055331Samw 		return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr, ct,
33065331Samw 		    direntflags, realpnp));
33070Sstevel@tonic-gate 	default:
33080Sstevel@tonic-gate 		break;
33090Sstevel@tonic-gate 	}
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 	if ((type == PR_OBJECTDIR || type == PR_FDDIR || type == PR_PATHDIR) &&
33125331Samw 	    (error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
33130Sstevel@tonic-gate 		return (error);
33140Sstevel@tonic-gate 
33155331Samw 	/* XXX - Do we need to pass ct, direntflags, or realpnp? */
33160Sstevel@tonic-gate 	*vpp = (pr_lookup_function[type](dp, comp));
33170Sstevel@tonic-gate 
33180Sstevel@tonic-gate 	return ((*vpp == NULL) ? ENOENT : 0);
33190Sstevel@tonic-gate }
33200Sstevel@tonic-gate 
33210Sstevel@tonic-gate /* ARGSUSED */
33220Sstevel@tonic-gate static int
prcreate(vnode_t * dp,char * comp,vattr_t * vap,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)33230Sstevel@tonic-gate prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
33245331Samw 	int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
33255331Samw 	vsecattr_t *vsecp)
33260Sstevel@tonic-gate {
33270Sstevel@tonic-gate 	int error;
33280Sstevel@tonic-gate 
33295331Samw 	if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr,
33305331Samw 	    ct, NULL, NULL)) != 0) {
33310Sstevel@tonic-gate 		if (error == ENOENT)	/* can't O_CREAT nonexistent files */
33320Sstevel@tonic-gate 			error = EACCES;		/* unwriteable directories */
33330Sstevel@tonic-gate 	} else {
33340Sstevel@tonic-gate 		if (excl == EXCL)			/* O_EXCL */
33350Sstevel@tonic-gate 			error = EEXIST;
33360Sstevel@tonic-gate 		else if (vap->va_mask & AT_SIZE) {	/* O_TRUNC */
33370Sstevel@tonic-gate 			vnode_t *vp = *vpp;
33380Sstevel@tonic-gate 			uint_t mask;
33390Sstevel@tonic-gate 
33400Sstevel@tonic-gate 			if (vp->v_type == VDIR)
33410Sstevel@tonic-gate 				error = EISDIR;
33420Sstevel@tonic-gate 			else if (vp->v_type != VPROC ||
33430Sstevel@tonic-gate 			    VTOP(vp)->pr_type != PR_FD)
33440Sstevel@tonic-gate 				error = EACCES;
33450Sstevel@tonic-gate 			else {		/* /proc/<pid>/fd/<n> */
33460Sstevel@tonic-gate 				vp = VTOP(vp)->pr_realvp;
33470Sstevel@tonic-gate 				mask = vap->va_mask;
33480Sstevel@tonic-gate 				vap->va_mask = AT_SIZE;
33495331Samw 				error = VOP_SETATTR(vp, vap, 0, cr, ct);
33500Sstevel@tonic-gate 				vap->va_mask = mask;
33510Sstevel@tonic-gate 			}
33520Sstevel@tonic-gate 		}
33530Sstevel@tonic-gate 		if (error) {
33540Sstevel@tonic-gate 			VN_RELE(*vpp);
33550Sstevel@tonic-gate 			*vpp = NULL;
33560Sstevel@tonic-gate 		}
33570Sstevel@tonic-gate 	}
33580Sstevel@tonic-gate 	return (error);
33590Sstevel@tonic-gate }
33600Sstevel@tonic-gate 
33610Sstevel@tonic-gate /* ARGSUSED */
33620Sstevel@tonic-gate static vnode_t *
pr_lookup_notdir(vnode_t * dp,char * comp)33630Sstevel@tonic-gate pr_lookup_notdir(vnode_t *dp, char *comp)
33640Sstevel@tonic-gate {
33650Sstevel@tonic-gate 	return (NULL);
33660Sstevel@tonic-gate }
33670Sstevel@tonic-gate 
33680Sstevel@tonic-gate /*
33690Sstevel@tonic-gate  * Find or construct a process vnode for the given pid.
33700Sstevel@tonic-gate  */
33710Sstevel@tonic-gate static vnode_t *
pr_lookup_procdir(vnode_t * dp,char * comp)33720Sstevel@tonic-gate pr_lookup_procdir(vnode_t *dp, char *comp)
33730Sstevel@tonic-gate {
33740Sstevel@tonic-gate 	pid_t pid;
33750Sstevel@tonic-gate 	prnode_t *pnp;
33760Sstevel@tonic-gate 	prcommon_t *pcp;
33770Sstevel@tonic-gate 	vnode_t *vp;
33780Sstevel@tonic-gate 	proc_t *p;
33790Sstevel@tonic-gate 	int c;
33800Sstevel@tonic-gate 
33810Sstevel@tonic-gate 	ASSERT(VTOP(dp)->pr_type == PR_PROCDIR);
33820Sstevel@tonic-gate 
33830Sstevel@tonic-gate 	if (strcmp(comp, "self") == 0) {
33840Sstevel@tonic-gate 		pnp = prgetnode(dp, PR_SELF);
33850Sstevel@tonic-gate 		return (PTOV(pnp));
33860Sstevel@tonic-gate 	} else {
33870Sstevel@tonic-gate 		pid = 0;
33880Sstevel@tonic-gate 		while ((c = *comp++) != '\0') {
33890Sstevel@tonic-gate 			if (c < '0' || c > '9')
33900Sstevel@tonic-gate 				return (NULL);
33910Sstevel@tonic-gate 			pid = 10*pid + c - '0';
33920Sstevel@tonic-gate 			if (pid > maxpid)
33930Sstevel@tonic-gate 				return (NULL);
33940Sstevel@tonic-gate 		}
33950Sstevel@tonic-gate 	}
33960Sstevel@tonic-gate 
33970Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_PIDDIR);
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate 	mutex_enter(&pidlock);
34000Sstevel@tonic-gate 	if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
34010Sstevel@tonic-gate 		mutex_exit(&pidlock);
34020Sstevel@tonic-gate 		prfreenode(pnp);
34030Sstevel@tonic-gate 		return (NULL);
34040Sstevel@tonic-gate 	}
34050Sstevel@tonic-gate 	ASSERT(p->p_stat != 0);
34066134Scasper 
34076134Scasper 	/* NOTE: we're holding pidlock across the policy call. */
34086134Scasper 	if (secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
34096134Scasper 		mutex_exit(&pidlock);
34106134Scasper 		prfreenode(pnp);
34116134Scasper 		return (NULL);
34126134Scasper 	}
34136134Scasper 
34140Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
34150Sstevel@tonic-gate 	mutex_exit(&pidlock);
34160Sstevel@tonic-gate 
34170Sstevel@tonic-gate 	/*
34180Sstevel@tonic-gate 	 * If a process vnode already exists and it is not invalid
34190Sstevel@tonic-gate 	 * and it was created by the current process and it belongs
34200Sstevel@tonic-gate 	 * to the same /proc mount point as our parent vnode, then
34210Sstevel@tonic-gate 	 * just use it and discard the newly-allocated prnode.
34220Sstevel@tonic-gate 	 */
34230Sstevel@tonic-gate 	for (vp = p->p_trace; vp != NULL; vp = VTOP(vp)->pr_next) {
34240Sstevel@tonic-gate 		if (!(VTOP(VTOP(vp)->pr_pidfile)->pr_flags & PR_INVAL) &&
34250Sstevel@tonic-gate 		    VTOP(vp)->pr_owner == curproc &&
34260Sstevel@tonic-gate 		    vp->v_vfsp == dp->v_vfsp) {
34270Sstevel@tonic-gate 			ASSERT(!(VTOP(vp)->pr_flags & PR_INVAL));
34280Sstevel@tonic-gate 			VN_HOLD(vp);
34290Sstevel@tonic-gate 			prfreenode(pnp);
34300Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
34310Sstevel@tonic-gate 			return (vp);
34320Sstevel@tonic-gate 		}
34330Sstevel@tonic-gate 	}
34340Sstevel@tonic-gate 	pnp->pr_owner = curproc;
34350Sstevel@tonic-gate 
34360Sstevel@tonic-gate 	/*
34370Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
34380Sstevel@tonic-gate 	 * Finish the job.
34390Sstevel@tonic-gate 	 */
34400Sstevel@tonic-gate 	pcp = pnp->pr_common;	/* the newly-allocated prcommon struct */
34410Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
34420Sstevel@tonic-gate 		/* discard the new prcommon and use the existing prcommon */
34430Sstevel@tonic-gate 		prfreecommon(pcp);
34440Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
34450Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
34460Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt > 0);
34470Sstevel@tonic-gate 		pcp->prc_refcnt++;
34480Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
34490Sstevel@tonic-gate 		pnp->pr_common = pcp;
34500Sstevel@tonic-gate 	} else {
34510Sstevel@tonic-gate 		/* initialize the new prcommon struct */
34520Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || p->p_as == &kas)
34530Sstevel@tonic-gate 			pcp->prc_flags |= PRC_SYS;
34540Sstevel@tonic-gate 		if (p->p_stat == SZOMB)
34550Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
34560Sstevel@tonic-gate 		pcp->prc_proc = p;
34570Sstevel@tonic-gate 		pcp->prc_datamodel = p->p_model;
34580Sstevel@tonic-gate 		pcp->prc_pid = p->p_pid;
34590Sstevel@tonic-gate 		pcp->prc_slot = p->p_slot;
34600Sstevel@tonic-gate 	}
34610Sstevel@tonic-gate 	pnp->pr_pcommon = pcp;
34620Sstevel@tonic-gate 	pnp->pr_parent = dp;
34630Sstevel@tonic-gate 	VN_HOLD(dp);
34640Sstevel@tonic-gate 	/*
34650Sstevel@tonic-gate 	 * Link in the old, invalid directory vnode so we
34660Sstevel@tonic-gate 	 * can later determine the last close of the file.
34670Sstevel@tonic-gate 	 */
34680Sstevel@tonic-gate 	pnp->pr_next = p->p_trace;
34690Sstevel@tonic-gate 	p->p_trace = dp = PTOV(pnp);
34700Sstevel@tonic-gate 
34710Sstevel@tonic-gate 	/*
34720Sstevel@tonic-gate 	 * Kludge for old /proc: initialize the PR_PIDFILE as well.
34730Sstevel@tonic-gate 	 */
34740Sstevel@tonic-gate 	vp = pnp->pr_pidfile;
34750Sstevel@tonic-gate 	pnp = VTOP(vp);
34760Sstevel@tonic-gate 	pnp->pr_ino = ptoi(pcp->prc_pid);
34770Sstevel@tonic-gate 	pnp->pr_common = pcp;
34780Sstevel@tonic-gate 	pnp->pr_pcommon = pcp;
34790Sstevel@tonic-gate 	pnp->pr_parent = dp;
34800Sstevel@tonic-gate 	pnp->pr_next = p->p_plist;
34810Sstevel@tonic-gate 	p->p_plist = vp;
34820Sstevel@tonic-gate 
34830Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
34840Sstevel@tonic-gate 	return (dp);
34850Sstevel@tonic-gate }
34860Sstevel@tonic-gate 
34870Sstevel@tonic-gate static vnode_t *
pr_lookup_piddir(vnode_t * dp,char * comp)34880Sstevel@tonic-gate pr_lookup_piddir(vnode_t *dp, char *comp)
34890Sstevel@tonic-gate {
34900Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
34910Sstevel@tonic-gate 	vnode_t *vp;
34920Sstevel@tonic-gate 	prnode_t *pnp;
34930Sstevel@tonic-gate 	proc_t *p;
34940Sstevel@tonic-gate 	user_t *up;
34950Sstevel@tonic-gate 	prdirent_t *dirp;
34960Sstevel@tonic-gate 	int i;
34970Sstevel@tonic-gate 	enum prnodetype type;
34980Sstevel@tonic-gate 
34990Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_PIDDIR);
35000Sstevel@tonic-gate 
35010Sstevel@tonic-gate 	for (i = 0; i < NPIDDIRFILES; i++) {
35020Sstevel@tonic-gate 		/* Skip "." and ".." */
35030Sstevel@tonic-gate 		dirp = &piddir[i+2];
35040Sstevel@tonic-gate 		if (strcmp(comp, dirp->d_name) == 0)
35050Sstevel@tonic-gate 			break;
35060Sstevel@tonic-gate 	}
35070Sstevel@tonic-gate 
35080Sstevel@tonic-gate 	if (i >= NPIDDIRFILES)
35090Sstevel@tonic-gate 		return (NULL);
35100Sstevel@tonic-gate 
35110Sstevel@tonic-gate 	type = (int)dirp->d_ino;
35120Sstevel@tonic-gate 	pnp = prgetnode(dp, type);
35130Sstevel@tonic-gate 
35140Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
35150Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
35160Sstevel@tonic-gate 	if (p == NULL) {
35170Sstevel@tonic-gate 		prfreenode(pnp);
35180Sstevel@tonic-gate 		return (NULL);
35190Sstevel@tonic-gate 	}
35200Sstevel@tonic-gate 	if (dpnp->pr_pcommon->prc_flags & PRC_DESTROY) {
35210Sstevel@tonic-gate 		switch (type) {
35220Sstevel@tonic-gate 		case PR_PSINFO:
35230Sstevel@tonic-gate 		case PR_USAGE:
35240Sstevel@tonic-gate 			break;
35250Sstevel@tonic-gate 		default:
35260Sstevel@tonic-gate 			prunlock(dpnp);
35270Sstevel@tonic-gate 			prfreenode(pnp);
35280Sstevel@tonic-gate 			return (NULL);
35290Sstevel@tonic-gate 		}
35300Sstevel@tonic-gate 	}
35310Sstevel@tonic-gate 
35320Sstevel@tonic-gate 	switch (type) {
35330Sstevel@tonic-gate 	case PR_CURDIR:
35340Sstevel@tonic-gate 	case PR_ROOTDIR:
35350Sstevel@tonic-gate 		up = PTOU(p);
35360Sstevel@tonic-gate 		vp = (type == PR_CURDIR)? up->u_cdir :
35375663Sck153898 		    (up->u_rdir? up->u_rdir : rootdir);
35380Sstevel@tonic-gate 
35390Sstevel@tonic-gate 		if (vp == NULL) {	/* can't happen? */
35400Sstevel@tonic-gate 			prunlock(dpnp);
35410Sstevel@tonic-gate 			prfreenode(pnp);
35420Sstevel@tonic-gate 			return (NULL);
35430Sstevel@tonic-gate 		}
35440Sstevel@tonic-gate 		/*
35450Sstevel@tonic-gate 		 * Fill in the prnode so future references will
35460Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
35470Sstevel@tonic-gate 		 */
35480Sstevel@tonic-gate 		VN_HOLD(vp);
35490Sstevel@tonic-gate 		pnp->pr_realvp = vp;
35500Sstevel@tonic-gate 		break;
35510Sstevel@tonic-gate 	default:
35520Sstevel@tonic-gate 		break;
35530Sstevel@tonic-gate 	}
35540Sstevel@tonic-gate 
35550Sstevel@tonic-gate 	mutex_enter(&dpnp->pr_mutex);
35560Sstevel@tonic-gate 
35570Sstevel@tonic-gate 	if ((vp = dpnp->pr_files[i]) != NULL &&
35580Sstevel@tonic-gate 	    !(VTOP(vp)->pr_flags & PR_INVAL)) {
35590Sstevel@tonic-gate 		VN_HOLD(vp);
35600Sstevel@tonic-gate 		mutex_exit(&dpnp->pr_mutex);
35610Sstevel@tonic-gate 		prunlock(dpnp);
35620Sstevel@tonic-gate 		prfreenode(pnp);
35630Sstevel@tonic-gate 		return (vp);
35640Sstevel@tonic-gate 	}
35650Sstevel@tonic-gate 
35660Sstevel@tonic-gate 	/*
35670Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
35680Sstevel@tonic-gate 	 * Finish the job.
35690Sstevel@tonic-gate 	 */
35700Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
35710Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
35720Sstevel@tonic-gate 	pnp->pr_parent = dp;
35730Sstevel@tonic-gate 	VN_HOLD(dp);
35740Sstevel@tonic-gate 	pnp->pr_index = i;
35750Sstevel@tonic-gate 
35760Sstevel@tonic-gate 	dpnp->pr_files[i] = vp = PTOV(pnp);
35770Sstevel@tonic-gate 
35780Sstevel@tonic-gate 	/*
35790Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
35800Sstevel@tonic-gate 	 */
35810Sstevel@tonic-gate 	if (vp->v_type == VPROC) {
35820Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
35830Sstevel@tonic-gate 		p->p_plist = vp;
35840Sstevel@tonic-gate 	}
35850Sstevel@tonic-gate 	mutex_exit(&dpnp->pr_mutex);
35860Sstevel@tonic-gate 	prunlock(dpnp);
35870Sstevel@tonic-gate 	return (vp);
35880Sstevel@tonic-gate }
35890Sstevel@tonic-gate 
35900Sstevel@tonic-gate static vnode_t *
pr_lookup_objectdir(vnode_t * dp,char * comp)35910Sstevel@tonic-gate pr_lookup_objectdir(vnode_t *dp, char *comp)
35920Sstevel@tonic-gate {
35930Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
35940Sstevel@tonic-gate 	prnode_t *pnp;
35950Sstevel@tonic-gate 	proc_t *p;
35960Sstevel@tonic-gate 	struct seg *seg;
35970Sstevel@tonic-gate 	struct as *as;
35980Sstevel@tonic-gate 	vnode_t *vp;
35990Sstevel@tonic-gate 	vattr_t vattr;
36000Sstevel@tonic-gate 
36010Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_OBJECTDIR);
36020Sstevel@tonic-gate 
36030Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_OBJECT);
36040Sstevel@tonic-gate 
36050Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
36060Sstevel@tonic-gate 		prfreenode(pnp);
36070Sstevel@tonic-gate 		return (NULL);
36080Sstevel@tonic-gate 	}
36090Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
36100Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
36110Sstevel@tonic-gate 		prunlock(dpnp);
36120Sstevel@tonic-gate 		prfreenode(pnp);
36130Sstevel@tonic-gate 		return (NULL);
36140Sstevel@tonic-gate 	}
36150Sstevel@tonic-gate 
36160Sstevel@tonic-gate 	/*
36170Sstevel@tonic-gate 	 * We drop p_lock before grabbing the address space lock
36180Sstevel@tonic-gate 	 * in order to avoid a deadlock with the clock thread.
36190Sstevel@tonic-gate 	 * The process will not disappear and its address space
36200Sstevel@tonic-gate 	 * will not change because it is marked P_PR_LOCK.
36210Sstevel@tonic-gate 	 */
36220Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
36230Sstevel@tonic-gate 	AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
36240Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
36250Sstevel@tonic-gate 		vp = NULL;
36260Sstevel@tonic-gate 		goto out;
36270Sstevel@tonic-gate 	}
36280Sstevel@tonic-gate 	if (strcmp(comp, "a.out") == 0) {
36290Sstevel@tonic-gate 		vp = p->p_exec;
36300Sstevel@tonic-gate 		goto out;
36310Sstevel@tonic-gate 	}
36320Sstevel@tonic-gate 	do {
36330Sstevel@tonic-gate 		/*
36340Sstevel@tonic-gate 		 * Manufacture a filename for the "object" directory.
36350Sstevel@tonic-gate 		 */
36360Sstevel@tonic-gate 		vattr.va_mask = AT_FSID|AT_NODEID;
36370Sstevel@tonic-gate 		if (seg->s_ops == &segvn_ops &&
36380Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
36390Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
36405331Samw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
36410Sstevel@tonic-gate 			char name[64];
36420Sstevel@tonic-gate 
36430Sstevel@tonic-gate 			if (vp == p->p_exec)	/* "a.out" */
36440Sstevel@tonic-gate 				continue;
36450Sstevel@tonic-gate 			pr_object_name(name, vp, &vattr);
36460Sstevel@tonic-gate 			if (strcmp(name, comp) == 0)
36470Sstevel@tonic-gate 				goto out;
36480Sstevel@tonic-gate 		}
36490Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
36500Sstevel@tonic-gate 
36510Sstevel@tonic-gate 	vp = NULL;
36520Sstevel@tonic-gate out:
36530Sstevel@tonic-gate 	if (vp != NULL) {
36540Sstevel@tonic-gate 		VN_HOLD(vp);
36550Sstevel@tonic-gate 	}
36560Sstevel@tonic-gate 	AS_LOCK_EXIT(as, &as->a_lock);
36570Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
36580Sstevel@tonic-gate 	prunlock(dpnp);
36590Sstevel@tonic-gate 
36600Sstevel@tonic-gate 	if (vp == NULL)
36610Sstevel@tonic-gate 		prfreenode(pnp);
36620Sstevel@tonic-gate 	else {
36630Sstevel@tonic-gate 		/*
36640Sstevel@tonic-gate 		 * Fill in the prnode so future references will
36650Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
36660Sstevel@tonic-gate 		 * Don't link this prnode into the list of all
36670Sstevel@tonic-gate 		 * prnodes for the process; this is a one-use node.
36680Sstevel@tonic-gate 		 * Its use is entirely to catch and fail opens for writing.
36690Sstevel@tonic-gate 		 */
36700Sstevel@tonic-gate 		pnp->pr_realvp = vp;
36710Sstevel@tonic-gate 		vp = PTOV(pnp);
36720Sstevel@tonic-gate 	}
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 	return (vp);
36750Sstevel@tonic-gate }
36760Sstevel@tonic-gate 
36770Sstevel@tonic-gate /*
36780Sstevel@tonic-gate  * Find or construct an lwp vnode for the given lwpid.
36790Sstevel@tonic-gate  */
36800Sstevel@tonic-gate static vnode_t *
pr_lookup_lwpdir(vnode_t * dp,char * comp)36810Sstevel@tonic-gate pr_lookup_lwpdir(vnode_t *dp, char *comp)
36820Sstevel@tonic-gate {
36830Sstevel@tonic-gate 	id_t tid;	/* same type as t->t_tid */
36840Sstevel@tonic-gate 	int want_agent;
36850Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
36860Sstevel@tonic-gate 	prnode_t *pnp;
36870Sstevel@tonic-gate 	prcommon_t *pcp;
36880Sstevel@tonic-gate 	vnode_t *vp;
36890Sstevel@tonic-gate 	proc_t *p;
36900Sstevel@tonic-gate 	kthread_t *t;
36910Sstevel@tonic-gate 	lwpdir_t *ldp;
36920Sstevel@tonic-gate 	lwpent_t *lep;
36930Sstevel@tonic-gate 	int tslot;
36940Sstevel@tonic-gate 	int c;
36950Sstevel@tonic-gate 
36960Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_LWPDIR);
36970Sstevel@tonic-gate 
36980Sstevel@tonic-gate 	tid = 0;
36990Sstevel@tonic-gate 	if (strcmp(comp, "agent") == 0)
37000Sstevel@tonic-gate 		want_agent = 1;
37010Sstevel@tonic-gate 	else {
37020Sstevel@tonic-gate 		want_agent = 0;
37030Sstevel@tonic-gate 		while ((c = *comp++) != '\0') {
37040Sstevel@tonic-gate 			id_t otid;
37050Sstevel@tonic-gate 
37060Sstevel@tonic-gate 			if (c < '0' || c > '9')
37070Sstevel@tonic-gate 				return (NULL);
37080Sstevel@tonic-gate 			otid = tid;
37090Sstevel@tonic-gate 			tid = 10*tid + c - '0';
37100Sstevel@tonic-gate 			if (tid/10 != otid)	/* integer overflow */
37110Sstevel@tonic-gate 				return (NULL);
37120Sstevel@tonic-gate 		}
37130Sstevel@tonic-gate 	}
37140Sstevel@tonic-gate 
37150Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_LWPIDDIR);
37160Sstevel@tonic-gate 
37170Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
37180Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
37190Sstevel@tonic-gate 	if (p == NULL) {
37200Sstevel@tonic-gate 		prfreenode(pnp);
37210Sstevel@tonic-gate 		return (NULL);
37220Sstevel@tonic-gate 	}
37230Sstevel@tonic-gate 
37240Sstevel@tonic-gate 	if (want_agent) {
37250Sstevel@tonic-gate 		if ((t = p->p_agenttp) == NULL)
37260Sstevel@tonic-gate 			lep = NULL;
37270Sstevel@tonic-gate 		else {
37280Sstevel@tonic-gate 			tid = t->t_tid;
37290Sstevel@tonic-gate 			tslot = t->t_dslot;
37300Sstevel@tonic-gate 			lep = p->p_lwpdir[tslot].ld_entry;
37310Sstevel@tonic-gate 		}
37320Sstevel@tonic-gate 	} else {
37330Sstevel@tonic-gate 		if ((ldp = lwp_hash_lookup(p, tid)) == NULL)
37340Sstevel@tonic-gate 			lep = NULL;
37350Sstevel@tonic-gate 		else {
37360Sstevel@tonic-gate 			tslot = (int)(ldp - p->p_lwpdir);
37370Sstevel@tonic-gate 			lep = ldp->ld_entry;
37380Sstevel@tonic-gate 		}
37390Sstevel@tonic-gate 	}
37400Sstevel@tonic-gate 
37410Sstevel@tonic-gate 	if (lep == NULL) {
37420Sstevel@tonic-gate 		prunlock(dpnp);
37430Sstevel@tonic-gate 		prfreenode(pnp);
37440Sstevel@tonic-gate 		return (NULL);
37450Sstevel@tonic-gate 	}
37460Sstevel@tonic-gate 
37470Sstevel@tonic-gate 	/*
37480Sstevel@tonic-gate 	 * If an lwp vnode already exists and it is not invalid
37490Sstevel@tonic-gate 	 * and it was created by the current process and it belongs
37500Sstevel@tonic-gate 	 * to the same /proc mount point as our parent vnode, then
37510Sstevel@tonic-gate 	 * just use it and discard the newly-allocated prnode.
37520Sstevel@tonic-gate 	 */
37530Sstevel@tonic-gate 	for (vp = lep->le_trace; vp != NULL; vp = VTOP(vp)->pr_next) {
37540Sstevel@tonic-gate 		if (!(VTOP(vp)->pr_flags & PR_INVAL) &&
37550Sstevel@tonic-gate 		    VTOP(vp)->pr_owner == curproc &&
37560Sstevel@tonic-gate 		    vp->v_vfsp == dp->v_vfsp) {
37570Sstevel@tonic-gate 			VN_HOLD(vp);
37580Sstevel@tonic-gate 			prunlock(dpnp);
37590Sstevel@tonic-gate 			prfreenode(pnp);
37600Sstevel@tonic-gate 			return (vp);
37610Sstevel@tonic-gate 		}
37620Sstevel@tonic-gate 	}
37630Sstevel@tonic-gate 	pnp->pr_owner = curproc;
37640Sstevel@tonic-gate 
37650Sstevel@tonic-gate 	/*
37660Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
37670Sstevel@tonic-gate 	 * Finish the job.
37680Sstevel@tonic-gate 	 */
37690Sstevel@tonic-gate 	pcp = pnp->pr_common;	/* the newly-allocated prcommon struct */
37700Sstevel@tonic-gate 	if ((vp = lep->le_trace) != NULL) {
37710Sstevel@tonic-gate 		/* discard the new prcommon and use the existing prcommon */
37720Sstevel@tonic-gate 		prfreecommon(pcp);
37730Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
37740Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
37750Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt > 0);
37760Sstevel@tonic-gate 		pcp->prc_refcnt++;
37770Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
37780Sstevel@tonic-gate 		pnp->pr_common = pcp;
37790Sstevel@tonic-gate 	} else {
37800Sstevel@tonic-gate 		/* initialize the new prcommon struct */
37810Sstevel@tonic-gate 		pcp->prc_flags |= PRC_LWP;
37820Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || p->p_as == &kas)
37830Sstevel@tonic-gate 			pcp->prc_flags |= PRC_SYS;
37840Sstevel@tonic-gate 		if ((t = lep->le_thread) == NULL)
37850Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
37860Sstevel@tonic-gate 		pcp->prc_proc = p;
37870Sstevel@tonic-gate 		pcp->prc_datamodel = dpnp->pr_pcommon->prc_datamodel;
37880Sstevel@tonic-gate 		pcp->prc_pid = p->p_pid;
37890Sstevel@tonic-gate 		pcp->prc_slot = p->p_slot;
37900Sstevel@tonic-gate 		pcp->prc_thread = t;
37910Sstevel@tonic-gate 		pcp->prc_tid = tid;
37920Sstevel@tonic-gate 		pcp->prc_tslot = tslot;
37930Sstevel@tonic-gate 	}
37940Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
37950Sstevel@tonic-gate 	pnp->pr_parent = dp;
37960Sstevel@tonic-gate 	VN_HOLD(dp);
37970Sstevel@tonic-gate 	/*
37980Sstevel@tonic-gate 	 * Link in the old, invalid directory vnode so we
37990Sstevel@tonic-gate 	 * can later determine the last close of the file.
38000Sstevel@tonic-gate 	 */
38010Sstevel@tonic-gate 	pnp->pr_next = lep->le_trace;
38020Sstevel@tonic-gate 	lep->le_trace = vp = PTOV(pnp);
38030Sstevel@tonic-gate 	prunlock(dpnp);
38040Sstevel@tonic-gate 	return (vp);
38050Sstevel@tonic-gate }
38060Sstevel@tonic-gate 
38070Sstevel@tonic-gate static vnode_t *
pr_lookup_lwpiddir(vnode_t * dp,char * comp)38080Sstevel@tonic-gate pr_lookup_lwpiddir(vnode_t *dp, char *comp)
38090Sstevel@tonic-gate {
38100Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
38110Sstevel@tonic-gate 	vnode_t *vp;
38120Sstevel@tonic-gate 	prnode_t *pnp;
38130Sstevel@tonic-gate 	proc_t *p;
38140Sstevel@tonic-gate 	prdirent_t *dirp;
38150Sstevel@tonic-gate 	int i;
38160Sstevel@tonic-gate 	enum prnodetype type;
38170Sstevel@tonic-gate 
38180Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_LWPIDDIR);
38190Sstevel@tonic-gate 
38200Sstevel@tonic-gate 	for (i = 0; i < NLWPIDDIRFILES; i++) {
38210Sstevel@tonic-gate 		/* Skip "." and ".." */
38220Sstevel@tonic-gate 		dirp = &lwpiddir[i+2];
38230Sstevel@tonic-gate 		if (strcmp(comp, dirp->d_name) == 0)
38240Sstevel@tonic-gate 			break;
38250Sstevel@tonic-gate 	}
38260Sstevel@tonic-gate 
38270Sstevel@tonic-gate 	if (i >= NLWPIDDIRFILES)
38280Sstevel@tonic-gate 		return (NULL);
38290Sstevel@tonic-gate 
38300Sstevel@tonic-gate 	type = (int)dirp->d_ino;
38310Sstevel@tonic-gate 	pnp = prgetnode(dp, type);
38320Sstevel@tonic-gate 
38330Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
38340Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
38350Sstevel@tonic-gate 	if (p == NULL) {
38360Sstevel@tonic-gate 		prfreenode(pnp);
38370Sstevel@tonic-gate 		return (NULL);
38380Sstevel@tonic-gate 	}
38390Sstevel@tonic-gate 	if (dpnp->pr_common->prc_flags & PRC_DESTROY) {
38400Sstevel@tonic-gate 		/*
38410Sstevel@tonic-gate 		 * Only the lwpsinfo file is present for zombie lwps.
38420Sstevel@tonic-gate 		 * Nothing is present if the lwp has been reaped.
38430Sstevel@tonic-gate 		 */
38440Sstevel@tonic-gate 		if (dpnp->pr_common->prc_tslot == -1 ||
38450Sstevel@tonic-gate 		    type != PR_LWPSINFO) {
38460Sstevel@tonic-gate 			prunlock(dpnp);
38470Sstevel@tonic-gate 			prfreenode(pnp);
38480Sstevel@tonic-gate 			return (NULL);
38490Sstevel@tonic-gate 		}
38500Sstevel@tonic-gate 	}
38510Sstevel@tonic-gate 
38520Sstevel@tonic-gate #if defined(__sparc)
38530Sstevel@tonic-gate 	/* the asrs file exists only for sparc v9 _LP64 processes */
38540Sstevel@tonic-gate 	if (type == PR_ASRS && p->p_model != DATAMODEL_LP64) {
38550Sstevel@tonic-gate 		prunlock(dpnp);
38560Sstevel@tonic-gate 		prfreenode(pnp);
38570Sstevel@tonic-gate 		return (NULL);
38580Sstevel@tonic-gate 	}
38590Sstevel@tonic-gate #endif
38600Sstevel@tonic-gate 
38610Sstevel@tonic-gate 	mutex_enter(&dpnp->pr_mutex);
38620Sstevel@tonic-gate 
38630Sstevel@tonic-gate 	if ((vp = dpnp->pr_files[i]) != NULL &&
38640Sstevel@tonic-gate 	    !(VTOP(vp)->pr_flags & PR_INVAL)) {
38650Sstevel@tonic-gate 		VN_HOLD(vp);
38660Sstevel@tonic-gate 		mutex_exit(&dpnp->pr_mutex);
38670Sstevel@tonic-gate 		prunlock(dpnp);
38680Sstevel@tonic-gate 		prfreenode(pnp);
38690Sstevel@tonic-gate 		return (vp);
38700Sstevel@tonic-gate 	}
38710Sstevel@tonic-gate 
38720Sstevel@tonic-gate 	/*
38730Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
38740Sstevel@tonic-gate 	 * Finish the job.
38750Sstevel@tonic-gate 	 */
38760Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
38770Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
38780Sstevel@tonic-gate 	pnp->pr_parent = dp;
38790Sstevel@tonic-gate 	VN_HOLD(dp);
38800Sstevel@tonic-gate 	pnp->pr_index = i;
38810Sstevel@tonic-gate 
38820Sstevel@tonic-gate 	dpnp->pr_files[i] = vp = PTOV(pnp);
38830Sstevel@tonic-gate 
38840Sstevel@tonic-gate 	/*
38850Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
38860Sstevel@tonic-gate 	 */
38870Sstevel@tonic-gate 	if (vp->v_type == VPROC) {
38880Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
38890Sstevel@tonic-gate 		p->p_plist = vp;
38900Sstevel@tonic-gate 	}
38910Sstevel@tonic-gate 	mutex_exit(&dpnp->pr_mutex);
38920Sstevel@tonic-gate 	prunlock(dpnp);
38930Sstevel@tonic-gate 	return (vp);
38940Sstevel@tonic-gate }
38950Sstevel@tonic-gate 
38960Sstevel@tonic-gate /*
38970Sstevel@tonic-gate  * Lookup one of the process's open files.
38980Sstevel@tonic-gate  */
38990Sstevel@tonic-gate static vnode_t *
pr_lookup_fddir(vnode_t * dp,char * comp)39000Sstevel@tonic-gate pr_lookup_fddir(vnode_t *dp, char *comp)
39010Sstevel@tonic-gate {
39020Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
39030Sstevel@tonic-gate 	prnode_t *pnp;
39040Sstevel@tonic-gate 	vnode_t *vp = NULL;
39050Sstevel@tonic-gate 	proc_t *p;
39060Sstevel@tonic-gate 	file_t *fp;
39070Sstevel@tonic-gate 	uint_t fd;
39080Sstevel@tonic-gate 	int c;
39090Sstevel@tonic-gate 	uf_entry_t *ufp;
39100Sstevel@tonic-gate 	uf_info_t *fip;
39110Sstevel@tonic-gate 
39120Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_FDDIR);
39130Sstevel@tonic-gate 
39140Sstevel@tonic-gate 	fd = 0;
39150Sstevel@tonic-gate 	while ((c = *comp++) != '\0') {
39160Sstevel@tonic-gate 		int ofd;
39170Sstevel@tonic-gate 		if (c < '0' || c > '9')
39180Sstevel@tonic-gate 			return (NULL);
39190Sstevel@tonic-gate 		ofd = fd;
39200Sstevel@tonic-gate 		fd = 10*fd + c - '0';
39210Sstevel@tonic-gate 		if (fd/10 != ofd)	/* integer overflow */
39220Sstevel@tonic-gate 			return (NULL);
39230Sstevel@tonic-gate 	}
39240Sstevel@tonic-gate 
39250Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_FD);
39260Sstevel@tonic-gate 
39270Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
39280Sstevel@tonic-gate 		prfreenode(pnp);
39290Sstevel@tonic-gate 		return (NULL);
39300Sstevel@tonic-gate 	}
39310Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
39320Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
39330Sstevel@tonic-gate 		prunlock(dpnp);
39340Sstevel@tonic-gate 		prfreenode(pnp);
39350Sstevel@tonic-gate 		return (NULL);
39360Sstevel@tonic-gate 	}
39370Sstevel@tonic-gate 
39380Sstevel@tonic-gate 	fip = P_FINFO(p);
39390Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
39400Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
39410Sstevel@tonic-gate 	if (fd < fip->fi_nfiles) {
39420Sstevel@tonic-gate 		UF_ENTER(ufp, fip, fd);
39430Sstevel@tonic-gate 		if ((fp = ufp->uf_file) != NULL) {
39440Sstevel@tonic-gate 			pnp->pr_mode = 07111;
39450Sstevel@tonic-gate 			if (fp->f_flag & FREAD)
39460Sstevel@tonic-gate 				pnp->pr_mode |= 0444;
39470Sstevel@tonic-gate 			if (fp->f_flag & FWRITE)
39480Sstevel@tonic-gate 				pnp->pr_mode |= 0222;
39490Sstevel@tonic-gate 			vp = fp->f_vnode;
39500Sstevel@tonic-gate 			VN_HOLD(vp);
39510Sstevel@tonic-gate 		}
39520Sstevel@tonic-gate 		UF_EXIT(ufp);
39530Sstevel@tonic-gate 	}
39540Sstevel@tonic-gate 	mutex_exit(&fip->fi_lock);
39550Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
39560Sstevel@tonic-gate 	prunlock(dpnp);
39570Sstevel@tonic-gate 
39580Sstevel@tonic-gate 	if (vp == NULL)
39590Sstevel@tonic-gate 		prfreenode(pnp);
39600Sstevel@tonic-gate 	else {
39610Sstevel@tonic-gate 		/*
39620Sstevel@tonic-gate 		 * Fill in the prnode so future references will
39630Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
39640Sstevel@tonic-gate 		 * Don't link this prnode into the list of all
39650Sstevel@tonic-gate 		 * prnodes for the process; this is a one-use node.
39660Sstevel@tonic-gate 		 */
39670Sstevel@tonic-gate 		pnp->pr_realvp = vp;
39680Sstevel@tonic-gate 		pnp->pr_parent = dp;		/* needed for prlookup */
39690Sstevel@tonic-gate 		VN_HOLD(dp);
39700Sstevel@tonic-gate 		vp = PTOV(pnp);
39710Sstevel@tonic-gate 		if (pnp->pr_realvp->v_type == VDIR)
39720Sstevel@tonic-gate 			vp->v_type = VDIR;
39730Sstevel@tonic-gate 	}
39740Sstevel@tonic-gate 
39750Sstevel@tonic-gate 	return (vp);
39760Sstevel@tonic-gate }
39770Sstevel@tonic-gate 
39780Sstevel@tonic-gate static vnode_t *
pr_lookup_pathdir(vnode_t * dp,char * comp)39790Sstevel@tonic-gate pr_lookup_pathdir(vnode_t *dp, char *comp)
39800Sstevel@tonic-gate {
39810Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
39820Sstevel@tonic-gate 	prnode_t *pnp;
39830Sstevel@tonic-gate 	vnode_t *vp = NULL;
39840Sstevel@tonic-gate 	proc_t *p;
39850Sstevel@tonic-gate 	uint_t fd, flags = 0;
39860Sstevel@tonic-gate 	int c;
39870Sstevel@tonic-gate 	uf_entry_t *ufp;
39880Sstevel@tonic-gate 	uf_info_t *fip;
39890Sstevel@tonic-gate 	enum { NAME_FD, NAME_OBJECT, NAME_ROOT, NAME_CWD, NAME_UNKNOWN } type;
39900Sstevel@tonic-gate 	char *tmp;
39910Sstevel@tonic-gate 	int idx;
39920Sstevel@tonic-gate 	struct seg *seg;
39930Sstevel@tonic-gate 	struct as *as = NULL;
39940Sstevel@tonic-gate 	vattr_t vattr;
39950Sstevel@tonic-gate 
39960Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_PATHDIR);
39970Sstevel@tonic-gate 
39980Sstevel@tonic-gate 	/*
39990Sstevel@tonic-gate 	 * First, check if this is a numeric entry, in which case we have a
40000Sstevel@tonic-gate 	 * file descriptor.
40010Sstevel@tonic-gate 	 */
40020Sstevel@tonic-gate 	fd = 0;
40030Sstevel@tonic-gate 	type = NAME_FD;
40040Sstevel@tonic-gate 	tmp = comp;
40050Sstevel@tonic-gate 	while ((c = *tmp++) != '\0') {
40060Sstevel@tonic-gate 		int ofd;
40070Sstevel@tonic-gate 		if (c < '0' || c > '9') {
40080Sstevel@tonic-gate 			type = NAME_UNKNOWN;
40090Sstevel@tonic-gate 			break;
40100Sstevel@tonic-gate 		}
40110Sstevel@tonic-gate 		ofd = fd;
40120Sstevel@tonic-gate 		fd = 10*fd + c - '0';
40130Sstevel@tonic-gate 		if (fd/10 != ofd) {	/* integer overflow */
40140Sstevel@tonic-gate 			type = NAME_UNKNOWN;
40150Sstevel@tonic-gate 			break;
40160Sstevel@tonic-gate 		}
40170Sstevel@tonic-gate 	}
40180Sstevel@tonic-gate 
40190Sstevel@tonic-gate 	/*
40200Sstevel@tonic-gate 	 * Next, see if it is one of the special values {root, cwd}.
40210Sstevel@tonic-gate 	 */
40220Sstevel@tonic-gate 	if (type == NAME_UNKNOWN) {
40230Sstevel@tonic-gate 		if (strcmp(comp, "root") == 0)
40240Sstevel@tonic-gate 			type = NAME_ROOT;
40250Sstevel@tonic-gate 		else if (strcmp(comp, "cwd") == 0)
40260Sstevel@tonic-gate 			type = NAME_CWD;
40270Sstevel@tonic-gate 	}
40280Sstevel@tonic-gate 
40290Sstevel@tonic-gate 	/*
40300Sstevel@tonic-gate 	 * Grab the necessary data from the process
40310Sstevel@tonic-gate 	 */
40320Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0)
40330Sstevel@tonic-gate 		return (NULL);
40340Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
40350Sstevel@tonic-gate 
40360Sstevel@tonic-gate 	fip = P_FINFO(p);
40370Sstevel@tonic-gate 
40380Sstevel@tonic-gate 	switch (type) {
40390Sstevel@tonic-gate 	case NAME_ROOT:
40400Sstevel@tonic-gate 		if ((vp = PTOU(p)->u_rdir) == NULL)
40410Sstevel@tonic-gate 			vp = p->p_zone->zone_rootvp;
40420Sstevel@tonic-gate 		VN_HOLD(vp);
40430Sstevel@tonic-gate 		break;
40440Sstevel@tonic-gate 	case NAME_CWD:
40450Sstevel@tonic-gate 		vp = PTOU(p)->u_cdir;
40460Sstevel@tonic-gate 		VN_HOLD(vp);
40470Sstevel@tonic-gate 		break;
40480Sstevel@tonic-gate 	default:
40490Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
40500Sstevel@tonic-gate 			prunlock(dpnp);
40510Sstevel@tonic-gate 			return (NULL);
40520Sstevel@tonic-gate 		}
40530Sstevel@tonic-gate 	}
40540Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
40550Sstevel@tonic-gate 
40560Sstevel@tonic-gate 	/*
40570Sstevel@tonic-gate 	 * Determine if this is an object entry
40580Sstevel@tonic-gate 	 */
40590Sstevel@tonic-gate 	if (type == NAME_UNKNOWN) {
40600Sstevel@tonic-gate 		/*
40610Sstevel@tonic-gate 		 * Start with the inode index immediately after the number of
40620Sstevel@tonic-gate 		 * files.
40630Sstevel@tonic-gate 		 */
40640Sstevel@tonic-gate 		mutex_enter(&fip->fi_lock);
40650Sstevel@tonic-gate 		idx = fip->fi_nfiles + 4;
40660Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
40670Sstevel@tonic-gate 
40680Sstevel@tonic-gate 		if (strcmp(comp, "a.out") == 0) {
40690Sstevel@tonic-gate 			if (p->p_execdir != NULL) {
40700Sstevel@tonic-gate 				vp = p->p_execdir;
40710Sstevel@tonic-gate 				VN_HOLD(vp);
40720Sstevel@tonic-gate 				type = NAME_OBJECT;
40730Sstevel@tonic-gate 				flags |= PR_AOUT;
40740Sstevel@tonic-gate 			} else {
40750Sstevel@tonic-gate 				vp = p->p_exec;
40760Sstevel@tonic-gate 				VN_HOLD(vp);
40770Sstevel@tonic-gate 				type = NAME_OBJECT;
40780Sstevel@tonic-gate 			}
40790Sstevel@tonic-gate 		} else {
40800Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
40810Sstevel@tonic-gate 			if ((seg = AS_SEGFIRST(as)) != NULL) {
40820Sstevel@tonic-gate 				do {
40830Sstevel@tonic-gate 					/*
40840Sstevel@tonic-gate 					 * Manufacture a filename for the
40850Sstevel@tonic-gate 					 * "object" directory.
40860Sstevel@tonic-gate 					 */
40870Sstevel@tonic-gate 					vattr.va_mask = AT_FSID|AT_NODEID;
40880Sstevel@tonic-gate 					if (seg->s_ops == &segvn_ops &&
40890Sstevel@tonic-gate 					    SEGOP_GETVP(seg, seg->s_base, &vp)
40900Sstevel@tonic-gate 					    == 0 &&
40910Sstevel@tonic-gate 					    vp != NULL && vp->v_type == VREG &&
40925331Samw 					    VOP_GETATTR(vp, &vattr, 0, CRED(),
40935331Samw 					    NULL) == 0) {
40940Sstevel@tonic-gate 						char name[64];
40950Sstevel@tonic-gate 
40960Sstevel@tonic-gate 						if (vp == p->p_exec)
40970Sstevel@tonic-gate 							continue;
40980Sstevel@tonic-gate 						idx++;
40990Sstevel@tonic-gate 						pr_object_name(name, vp,
41000Sstevel@tonic-gate 						    &vattr);
41010Sstevel@tonic-gate 						if (strcmp(name, comp) == 0)
41020Sstevel@tonic-gate 							break;
41030Sstevel@tonic-gate 					}
41040Sstevel@tonic-gate 				} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
41050Sstevel@tonic-gate 			}
41060Sstevel@tonic-gate 
41070Sstevel@tonic-gate 			if (seg == NULL) {
41080Sstevel@tonic-gate 				vp = NULL;
41090Sstevel@tonic-gate 			} else {
41100Sstevel@tonic-gate 				VN_HOLD(vp);
41110Sstevel@tonic-gate 				type = NAME_OBJECT;
41120Sstevel@tonic-gate 			}
41130Sstevel@tonic-gate 
41140Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
41150Sstevel@tonic-gate 		}
41160Sstevel@tonic-gate 	}
41170Sstevel@tonic-gate 
41180Sstevel@tonic-gate 
41190Sstevel@tonic-gate 	switch (type) {
41200Sstevel@tonic-gate 	case NAME_FD:
41210Sstevel@tonic-gate 		mutex_enter(&fip->fi_lock);
41220Sstevel@tonic-gate 		if (fd < fip->fi_nfiles) {
41230Sstevel@tonic-gate 			UF_ENTER(ufp, fip, fd);
41240Sstevel@tonic-gate 			if (ufp->uf_file != NULL) {
41250Sstevel@tonic-gate 				vp = ufp->uf_file->f_vnode;
41260Sstevel@tonic-gate 				VN_HOLD(vp);
41270Sstevel@tonic-gate 			}
41280Sstevel@tonic-gate 			UF_EXIT(ufp);
41290Sstevel@tonic-gate 		}
41300Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
41310Sstevel@tonic-gate 		idx = fd + 4;
41320Sstevel@tonic-gate 		break;
41330Sstevel@tonic-gate 	case NAME_ROOT:
41340Sstevel@tonic-gate 		idx = 2;
41350Sstevel@tonic-gate 		break;
41360Sstevel@tonic-gate 	case NAME_CWD:
41370Sstevel@tonic-gate 		idx = 3;
41380Sstevel@tonic-gate 		break;
41390Sstevel@tonic-gate 	case NAME_OBJECT:
41400Sstevel@tonic-gate 	case NAME_UNKNOWN:
41410Sstevel@tonic-gate 		/* Nothing to do */
41420Sstevel@tonic-gate 		break;
41430Sstevel@tonic-gate 	}
41440Sstevel@tonic-gate 
41450Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
41460Sstevel@tonic-gate 	prunlock(dpnp);
41470Sstevel@tonic-gate 
41480Sstevel@tonic-gate 	if (vp != NULL) {
41490Sstevel@tonic-gate 		pnp = prgetnode(dp, PR_PATH);
41500Sstevel@tonic-gate 
41510Sstevel@tonic-gate 		pnp->pr_flags |= flags;
41520Sstevel@tonic-gate 		pnp->pr_common = dpnp->pr_common;
41530Sstevel@tonic-gate 		pnp->pr_pcommon = dpnp->pr_pcommon;
41540Sstevel@tonic-gate 		pnp->pr_realvp = vp;
41550Sstevel@tonic-gate 		pnp->pr_parent = dp;		/* needed for prlookup */
41560Sstevel@tonic-gate 		pnp->pr_ino = pmkino(idx, dpnp->pr_common->prc_slot, PR_PATH);
41570Sstevel@tonic-gate 		VN_HOLD(dp);
41580Sstevel@tonic-gate 		vp = PTOV(pnp);
41590Sstevel@tonic-gate 		vp->v_type = VLNK;
41600Sstevel@tonic-gate 	}
41610Sstevel@tonic-gate 
41620Sstevel@tonic-gate 	return (vp);
41630Sstevel@tonic-gate }
41640Sstevel@tonic-gate 
41650Sstevel@tonic-gate /*
41660Sstevel@tonic-gate  * Look up one of the process's active templates.
41670Sstevel@tonic-gate  */
41680Sstevel@tonic-gate static vnode_t *
pr_lookup_tmpldir(vnode_t * dp,char * comp)41690Sstevel@tonic-gate pr_lookup_tmpldir(vnode_t *dp, char *comp)
41700Sstevel@tonic-gate {
41710Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
41720Sstevel@tonic-gate 	prnode_t *pnp;
41730Sstevel@tonic-gate 	vnode_t *vp = NULL;
41740Sstevel@tonic-gate 	proc_t *p;
41750Sstevel@tonic-gate 	int i;
41760Sstevel@tonic-gate 
41770Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_TMPLDIR);
41780Sstevel@tonic-gate 
41790Sstevel@tonic-gate 	for (i = 0; i < ct_ntypes; i++)
41800Sstevel@tonic-gate 		if (strcmp(comp, ct_types[i]->ct_type_name) == 0)
41810Sstevel@tonic-gate 			break;
41820Sstevel@tonic-gate 	if (i == ct_ntypes)
41830Sstevel@tonic-gate 		return (NULL);
41840Sstevel@tonic-gate 
41850Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_TMPL);
41860Sstevel@tonic-gate 
41870Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
41880Sstevel@tonic-gate 		prfreenode(pnp);
41890Sstevel@tonic-gate 		return (NULL);
41900Sstevel@tonic-gate 	}
41910Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
41920Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas ||
41930Sstevel@tonic-gate 	    (dpnp->pr_common->prc_flags & (PRC_DESTROY | PRC_LWP)) != PRC_LWP) {
41940Sstevel@tonic-gate 		prunlock(dpnp);
41950Sstevel@tonic-gate 		prfreenode(pnp);
41960Sstevel@tonic-gate 		return (NULL);
41970Sstevel@tonic-gate 	}
41980Sstevel@tonic-gate 	if (ttolwp(dpnp->pr_common->prc_thread)->lwp_ct_active[i] != NULL) {
41990Sstevel@tonic-gate 		pnp->pr_common = dpnp->pr_common;
42000Sstevel@tonic-gate 		pnp->pr_pcommon = dpnp->pr_pcommon;
42010Sstevel@tonic-gate 		pnp->pr_parent = dp;
42020Sstevel@tonic-gate 		pnp->pr_cttype = i;
42030Sstevel@tonic-gate 		VN_HOLD(dp);
42040Sstevel@tonic-gate 		vp = PTOV(pnp);
42050Sstevel@tonic-gate 	} else {
42060Sstevel@tonic-gate 		prfreenode(pnp);
42070Sstevel@tonic-gate 	}
42080Sstevel@tonic-gate 	prunlock(dpnp);
42090Sstevel@tonic-gate 
42100Sstevel@tonic-gate 	return (vp);
42110Sstevel@tonic-gate }
42120Sstevel@tonic-gate 
42130Sstevel@tonic-gate /*
42140Sstevel@tonic-gate  * Look up one of the contracts owned by the process.
42150Sstevel@tonic-gate  */
42160Sstevel@tonic-gate static vnode_t *
pr_lookup_ctdir(vnode_t * dp,char * comp)42170Sstevel@tonic-gate pr_lookup_ctdir(vnode_t *dp, char *comp)
42180Sstevel@tonic-gate {
42190Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
42200Sstevel@tonic-gate 	prnode_t *pnp;
42210Sstevel@tonic-gate 	vnode_t *vp = NULL;
42220Sstevel@tonic-gate 	proc_t *p;
42230Sstevel@tonic-gate 	id_t id = 0;
42240Sstevel@tonic-gate 	contract_t *ct;
42250Sstevel@tonic-gate 	int c;
42260Sstevel@tonic-gate 
42270Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_CTDIR);
42280Sstevel@tonic-gate 
42290Sstevel@tonic-gate 	while ((c = *comp++) != '\0') {
42300Sstevel@tonic-gate 		id_t oid;
42310Sstevel@tonic-gate 		if (c < '0' || c > '9')
42320Sstevel@tonic-gate 			return (NULL);
42330Sstevel@tonic-gate 		oid = id;
42340Sstevel@tonic-gate 		id = 10 * id + c - '0';
42350Sstevel@tonic-gate 		if (id / 10 != oid)	/* integer overflow */
42360Sstevel@tonic-gate 			return (NULL);
42370Sstevel@tonic-gate 	}
42380Sstevel@tonic-gate 
42390Sstevel@tonic-gate 	/*
42400Sstevel@tonic-gate 	 * Search all contracts; we'll filter below.
42410Sstevel@tonic-gate 	 */
42420Sstevel@tonic-gate 	ct = contract_ptr(id, GLOBAL_ZONEUNIQID);
42430Sstevel@tonic-gate 	if (ct == NULL)
42440Sstevel@tonic-gate 		return (NULL);
42450Sstevel@tonic-gate 
42460Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_CT);
42470Sstevel@tonic-gate 
42480Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
42490Sstevel@tonic-gate 		prfreenode(pnp);
42500Sstevel@tonic-gate 		contract_rele(ct);
42510Sstevel@tonic-gate 		return (NULL);
42520Sstevel@tonic-gate 	}
42530Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
42540Sstevel@tonic-gate 	/*
42550Sstevel@tonic-gate 	 * We only allow lookups of contracts owned by this process, or,
42560Sstevel@tonic-gate 	 * if we are zsched and this is a zone's procfs, contracts on
42570Sstevel@tonic-gate 	 * stuff in the zone which are held by processes or contracts
42580Sstevel@tonic-gate 	 * outside the zone.  (see logic in contract_status_common)
42590Sstevel@tonic-gate 	 */
42600Sstevel@tonic-gate 	if ((ct->ct_owner != p) &&
4261789Sahrens 	    !(p == VTOZONE(dp)->zone_zsched && ct->ct_state < CTS_ORPHAN &&
4262789Sahrens 	    VTOZONE(dp)->zone_uniqid == contract_getzuniqid(ct) &&
4263789Sahrens 	    VTOZONE(dp)->zone_uniqid != GLOBAL_ZONEUNIQID &&
42640Sstevel@tonic-gate 	    ct->ct_czuniqid == GLOBAL_ZONEUNIQID)) {
42650Sstevel@tonic-gate 		prunlock(dpnp);
42660Sstevel@tonic-gate 		prfreenode(pnp);
42670Sstevel@tonic-gate 		contract_rele(ct);
42680Sstevel@tonic-gate 		return (NULL);
42690Sstevel@tonic-gate 	}
42700Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
42710Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
42720Sstevel@tonic-gate 	pnp->pr_contract = ct;
42730Sstevel@tonic-gate 	pnp->pr_parent = dp;
42740Sstevel@tonic-gate 	pnp->pr_ino = pmkino(id, pnp->pr_common->prc_slot, PR_CT);
42750Sstevel@tonic-gate 	VN_HOLD(dp);
42760Sstevel@tonic-gate 	prunlock(dpnp);
42770Sstevel@tonic-gate 	vp = PTOV(pnp);
42780Sstevel@tonic-gate 
42790Sstevel@tonic-gate 	return (vp);
42800Sstevel@tonic-gate }
42810Sstevel@tonic-gate 
42820Sstevel@tonic-gate /*
42830Sstevel@tonic-gate  * Construct an lwp vnode for the old /proc interface.
42840Sstevel@tonic-gate  * We stand on our head to make the /proc plumbing correct.
42850Sstevel@tonic-gate  */
42860Sstevel@tonic-gate vnode_t *
prlwpnode(prnode_t * pnp,uint_t tid)42870Sstevel@tonic-gate prlwpnode(prnode_t *pnp, uint_t tid)
42880Sstevel@tonic-gate {
42890Sstevel@tonic-gate 	char comp[12];
42900Sstevel@tonic-gate 	vnode_t *dp;
42910Sstevel@tonic-gate 	vnode_t *vp;
42920Sstevel@tonic-gate 	prcommon_t *pcp;
42930Sstevel@tonic-gate 	proc_t *p;
42940Sstevel@tonic-gate 
42950Sstevel@tonic-gate 	/*
42960Sstevel@tonic-gate 	 * Lookup the /proc/<pid>/lwp/<lwpid> directory vnode.
42970Sstevel@tonic-gate 	 */
42980Sstevel@tonic-gate 	if (pnp->pr_type == PR_PIDFILE) {
42990Sstevel@tonic-gate 		dp = pnp->pr_parent;		/* /proc/<pid> */
43000Sstevel@tonic-gate 		VN_HOLD(dp);
43010Sstevel@tonic-gate 		vp = pr_lookup_piddir(dp, "lwp");
43020Sstevel@tonic-gate 		VN_RELE(dp);
43030Sstevel@tonic-gate 		if ((dp = vp) == NULL)		/* /proc/<pid>/lwp */
43040Sstevel@tonic-gate 			return (NULL);
43050Sstevel@tonic-gate 	} else if (pnp->pr_type == PR_LWPIDFILE) {
43060Sstevel@tonic-gate 		dp = pnp->pr_parent;		/* /proc/<pid>/lwp/<lwpid> */
43070Sstevel@tonic-gate 		dp = VTOP(dp)->pr_parent;	/* /proc/<pid>/lwp */
43080Sstevel@tonic-gate 		VN_HOLD(dp);
43090Sstevel@tonic-gate 	} else {
43100Sstevel@tonic-gate 		return (NULL);
43110Sstevel@tonic-gate 	}
43120Sstevel@tonic-gate 
43130Sstevel@tonic-gate 	(void) pr_u32tos(tid, comp, sizeof (comp));
43140Sstevel@tonic-gate 	vp = pr_lookup_lwpdir(dp, comp);
43150Sstevel@tonic-gate 	VN_RELE(dp);
43160Sstevel@tonic-gate 	if ((dp = vp) == NULL)
43170Sstevel@tonic-gate 		return (NULL);
43180Sstevel@tonic-gate 
43190Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_LWPIDFILE);
43200Sstevel@tonic-gate 	vp = PTOV(pnp);
43210Sstevel@tonic-gate 
43220Sstevel@tonic-gate 	/*
43230Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
43240Sstevel@tonic-gate 	 * Finish the job.
43250Sstevel@tonic-gate 	 */
43260Sstevel@tonic-gate 	pcp = VTOP(dp)->pr_common;
43270Sstevel@tonic-gate 	pnp->pr_ino = ptoi(pcp->prc_pid);
43280Sstevel@tonic-gate 	pnp->pr_common = pcp;
43290Sstevel@tonic-gate 	pnp->pr_pcommon = VTOP(dp)->pr_pcommon;
43300Sstevel@tonic-gate 	pnp->pr_parent = dp;
43310Sstevel@tonic-gate 	/*
43320Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
43330Sstevel@tonic-gate 	 */
43340Sstevel@tonic-gate 	p = pr_p_lock(pnp);
43350Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
43360Sstevel@tonic-gate 	if (p == NULL) {
43370Sstevel@tonic-gate 		VN_RELE(dp);
43380Sstevel@tonic-gate 		prfreenode(pnp);
43390Sstevel@tonic-gate 		vp = NULL;
43400Sstevel@tonic-gate 	} else if (pcp->prc_thread == NULL) {
43410Sstevel@tonic-gate 		prunlock(pnp);
43420Sstevel@tonic-gate 		VN_RELE(dp);
43430Sstevel@tonic-gate 		prfreenode(pnp);
43440Sstevel@tonic-gate 		vp = NULL;
43450Sstevel@tonic-gate 	} else {
43460Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
43470Sstevel@tonic-gate 		p->p_plist = vp;
43480Sstevel@tonic-gate 		prunlock(pnp);
43490Sstevel@tonic-gate 	}
43500Sstevel@tonic-gate 
43510Sstevel@tonic-gate 	return (vp);
43520Sstevel@tonic-gate }
43530Sstevel@tonic-gate 
43540Sstevel@tonic-gate #if defined(DEBUG)
43550Sstevel@tonic-gate 
43560Sstevel@tonic-gate static	uint32_t nprnode;
43570Sstevel@tonic-gate static	uint32_t nprcommon;
43580Sstevel@tonic-gate 
43590Sstevel@tonic-gate #define	INCREMENT(x)	atomic_add_32(&x, 1);
43600Sstevel@tonic-gate #define	DECREMENT(x)	atomic_add_32(&x, -1);
43610Sstevel@tonic-gate 
43620Sstevel@tonic-gate #else
43630Sstevel@tonic-gate 
43640Sstevel@tonic-gate #define	INCREMENT(x)
43650Sstevel@tonic-gate #define	DECREMENT(x)
43660Sstevel@tonic-gate 
43670Sstevel@tonic-gate #endif	/* DEBUG */
43680Sstevel@tonic-gate 
43690Sstevel@tonic-gate /*
43700Sstevel@tonic-gate  * New /proc vnode required; allocate it and fill in most of the fields.
43710Sstevel@tonic-gate  */
43720Sstevel@tonic-gate prnode_t *
prgetnode(vnode_t * dp,prnodetype_t type)43730Sstevel@tonic-gate prgetnode(vnode_t *dp, prnodetype_t type)
43740Sstevel@tonic-gate {
43750Sstevel@tonic-gate 	prnode_t *pnp;
43760Sstevel@tonic-gate 	prcommon_t *pcp;
43770Sstevel@tonic-gate 	vnode_t *vp;
43780Sstevel@tonic-gate 	ulong_t nfiles;
43790Sstevel@tonic-gate 
43800Sstevel@tonic-gate 	INCREMENT(nprnode);
43810Sstevel@tonic-gate 	pnp = kmem_zalloc(sizeof (prnode_t), KM_SLEEP);
43820Sstevel@tonic-gate 
43830Sstevel@tonic-gate 	mutex_init(&pnp->pr_mutex, NULL, MUTEX_DEFAULT, NULL);
43840Sstevel@tonic-gate 	pnp->pr_type = type;
43850Sstevel@tonic-gate 
43860Sstevel@tonic-gate 	pnp->pr_vnode = vn_alloc(KM_SLEEP);
43870Sstevel@tonic-gate 
43880Sstevel@tonic-gate 	vp = PTOV(pnp);
43890Sstevel@tonic-gate 	vp->v_flag = VNOCACHE|VNOMAP|VNOSWAP|VNOMOUNT;
43900Sstevel@tonic-gate 	vn_setops(vp, prvnodeops);
43910Sstevel@tonic-gate 	vp->v_vfsp = dp->v_vfsp;
43920Sstevel@tonic-gate 	vp->v_type = VPROC;
43930Sstevel@tonic-gate 	vp->v_data = (caddr_t)pnp;
43940Sstevel@tonic-gate 
43950Sstevel@tonic-gate 	switch (type) {
43960Sstevel@tonic-gate 	case PR_PIDDIR:
43970Sstevel@tonic-gate 	case PR_LWPIDDIR:
43980Sstevel@tonic-gate 		/*
43990Sstevel@tonic-gate 		 * We need a prcommon and a files array for each of these.
44000Sstevel@tonic-gate 		 */
44010Sstevel@tonic-gate 		INCREMENT(nprcommon);
44020Sstevel@tonic-gate 
44030Sstevel@tonic-gate 		pcp = kmem_zalloc(sizeof (prcommon_t), KM_SLEEP);
44040Sstevel@tonic-gate 		pcp->prc_refcnt = 1;
44050Sstevel@tonic-gate 		pnp->pr_common = pcp;
44060Sstevel@tonic-gate 		mutex_init(&pcp->prc_mutex, NULL, MUTEX_DEFAULT, NULL);
44070Sstevel@tonic-gate 		cv_init(&pcp->prc_wait, NULL, CV_DEFAULT, NULL);
44080Sstevel@tonic-gate 
44090Sstevel@tonic-gate 		nfiles = (type == PR_PIDDIR)? NPIDDIRFILES : NLWPIDDIRFILES;
44100Sstevel@tonic-gate 		pnp->pr_files =
44110Sstevel@tonic-gate 		    kmem_zalloc(nfiles * sizeof (vnode_t *), KM_SLEEP);
44120Sstevel@tonic-gate 
44130Sstevel@tonic-gate 		vp->v_type = VDIR;
44140Sstevel@tonic-gate 		/*
44150Sstevel@tonic-gate 		 * Mode should be read-search by all, but we cannot so long
44160Sstevel@tonic-gate 		 * as we must support compatibility mode with old /proc.
44170Sstevel@tonic-gate 		 * Make /proc/<pid> be read by owner only, search by all.
44180Sstevel@tonic-gate 		 * Make /proc/<pid>/lwp/<lwpid> read-search by all.  Also,
44190Sstevel@tonic-gate 		 * set VDIROPEN on /proc/<pid> so it can be opened for writing.
44200Sstevel@tonic-gate 		 */
44210Sstevel@tonic-gate 		if (type == PR_PIDDIR) {
44220Sstevel@tonic-gate 			/* kludge for old /proc interface */
44230Sstevel@tonic-gate 			prnode_t *xpnp = prgetnode(dp, PR_PIDFILE);
44240Sstevel@tonic-gate 			pnp->pr_pidfile = PTOV(xpnp);
44250Sstevel@tonic-gate 			pnp->pr_mode = 0511;
44260Sstevel@tonic-gate 			vp->v_flag |= VDIROPEN;
44270Sstevel@tonic-gate 		} else {
44280Sstevel@tonic-gate 			pnp->pr_mode = 0555;
44290Sstevel@tonic-gate 		}
44300Sstevel@tonic-gate 
44310Sstevel@tonic-gate 		break;
44320Sstevel@tonic-gate 
44330Sstevel@tonic-gate 	case PR_CURDIR:
44340Sstevel@tonic-gate 	case PR_ROOTDIR:
44350Sstevel@tonic-gate 	case PR_FDDIR:
44360Sstevel@tonic-gate 	case PR_OBJECTDIR:
44370Sstevel@tonic-gate 	case PR_PATHDIR:
44380Sstevel@tonic-gate 	case PR_CTDIR:
44390Sstevel@tonic-gate 	case PR_TMPLDIR:
44400Sstevel@tonic-gate 		vp->v_type = VDIR;
44410Sstevel@tonic-gate 		pnp->pr_mode = 0500;	/* read-search by owner only */
44420Sstevel@tonic-gate 		break;
44430Sstevel@tonic-gate 
44440Sstevel@tonic-gate 	case PR_CT:
44450Sstevel@tonic-gate 		vp->v_type = VLNK;
44460Sstevel@tonic-gate 		pnp->pr_mode = 0500;	/* read-search by owner only */
44470Sstevel@tonic-gate 		break;
44480Sstevel@tonic-gate 
44490Sstevel@tonic-gate 	case PR_PATH:
44500Sstevel@tonic-gate 	case PR_SELF:
44510Sstevel@tonic-gate 		vp->v_type = VLNK;
44520Sstevel@tonic-gate 		pnp->pr_mode = 0777;
44530Sstevel@tonic-gate 		break;
44540Sstevel@tonic-gate 
44550Sstevel@tonic-gate 	case PR_LWPDIR:
44560Sstevel@tonic-gate 		vp->v_type = VDIR;
44570Sstevel@tonic-gate 		pnp->pr_mode = 0555;	/* read-search by all */
44580Sstevel@tonic-gate 		break;
44590Sstevel@tonic-gate 
44600Sstevel@tonic-gate 	case PR_AS:
44610Sstevel@tonic-gate 	case PR_TMPL:
44620Sstevel@tonic-gate 		pnp->pr_mode = 0600;	/* read-write by owner only */
44630Sstevel@tonic-gate 		break;
44640Sstevel@tonic-gate 
44650Sstevel@tonic-gate 	case PR_CTL:
44660Sstevel@tonic-gate 	case PR_LWPCTL:
44670Sstevel@tonic-gate 		pnp->pr_mode = 0200;	/* write-only by owner only */
44680Sstevel@tonic-gate 		break;
44690Sstevel@tonic-gate 
44700Sstevel@tonic-gate 	case PR_PIDFILE:
44710Sstevel@tonic-gate 	case PR_LWPIDFILE:
44720Sstevel@tonic-gate 		pnp->pr_mode = 0600;	/* read-write by owner only */
44730Sstevel@tonic-gate 		break;
44740Sstevel@tonic-gate 
44750Sstevel@tonic-gate 	case PR_PSINFO:
44760Sstevel@tonic-gate 	case PR_LPSINFO:
44770Sstevel@tonic-gate 	case PR_LWPSINFO:
44780Sstevel@tonic-gate 	case PR_USAGE:
44790Sstevel@tonic-gate 	case PR_LUSAGE:
44800Sstevel@tonic-gate 	case PR_LWPUSAGE:
44810Sstevel@tonic-gate 		pnp->pr_mode = 0444;	/* read-only by all */
44820Sstevel@tonic-gate 		break;
44830Sstevel@tonic-gate 
44840Sstevel@tonic-gate 	default:
44850Sstevel@tonic-gate 		pnp->pr_mode = 0400;	/* read-only by owner only */
44860Sstevel@tonic-gate 		break;
44870Sstevel@tonic-gate 	}
44880Sstevel@tonic-gate 	vn_exists(vp);
44890Sstevel@tonic-gate 	return (pnp);
44900Sstevel@tonic-gate }
44910Sstevel@tonic-gate 
44920Sstevel@tonic-gate /*
44930Sstevel@tonic-gate  * Free the storage obtained from prgetnode().
44940Sstevel@tonic-gate  */
44950Sstevel@tonic-gate void
prfreenode(prnode_t * pnp)44960Sstevel@tonic-gate prfreenode(prnode_t *pnp)
44970Sstevel@tonic-gate {
44980Sstevel@tonic-gate 	vnode_t *vp;
44990Sstevel@tonic-gate 	ulong_t nfiles;
45000Sstevel@tonic-gate 
45010Sstevel@tonic-gate 	vn_invalid(PTOV(pnp));
45020Sstevel@tonic-gate 	vn_free(PTOV(pnp));
45030Sstevel@tonic-gate 	mutex_destroy(&pnp->pr_mutex);
45040Sstevel@tonic-gate 
45050Sstevel@tonic-gate 	switch (pnp->pr_type) {
45060Sstevel@tonic-gate 	case PR_PIDDIR:
45070Sstevel@tonic-gate 		/* kludge for old /proc interface */
45080Sstevel@tonic-gate 		if (pnp->pr_pidfile != NULL) {
45090Sstevel@tonic-gate 			prfreenode(VTOP(pnp->pr_pidfile));
45100Sstevel@tonic-gate 			pnp->pr_pidfile = NULL;
45110Sstevel@tonic-gate 		}
45120Sstevel@tonic-gate 		/* FALLTHROUGH */
45130Sstevel@tonic-gate 	case PR_LWPIDDIR:
45140Sstevel@tonic-gate 		/*
45150Sstevel@tonic-gate 		 * We allocated a prcommon and a files array for each of these.
45160Sstevel@tonic-gate 		 */
45170Sstevel@tonic-gate 		prfreecommon(pnp->pr_common);
45180Sstevel@tonic-gate 		nfiles = (pnp->pr_type == PR_PIDDIR)?
45190Sstevel@tonic-gate 		    NPIDDIRFILES : NLWPIDDIRFILES;
45200Sstevel@tonic-gate 		kmem_free(pnp->pr_files, nfiles * sizeof (vnode_t *));
45210Sstevel@tonic-gate 		break;
45220Sstevel@tonic-gate 	default:
45230Sstevel@tonic-gate 		break;
45240Sstevel@tonic-gate 	}
45250Sstevel@tonic-gate 	/*
45260Sstevel@tonic-gate 	 * If there is an underlying vnode, be sure
45270Sstevel@tonic-gate 	 * to release it after freeing the prnode.
45280Sstevel@tonic-gate 	 */
45290Sstevel@tonic-gate 	vp = pnp->pr_realvp;
45300Sstevel@tonic-gate 	kmem_free(pnp, sizeof (*pnp));
45310Sstevel@tonic-gate 	DECREMENT(nprnode);
45320Sstevel@tonic-gate 	if (vp != NULL) {
45330Sstevel@tonic-gate 		VN_RELE(vp);
45340Sstevel@tonic-gate 	}
45350Sstevel@tonic-gate }
45360Sstevel@tonic-gate 
45370Sstevel@tonic-gate /*
45385331Samw  * Free a prcommon structure, if the reference count reaches zero.
45390Sstevel@tonic-gate  */
45400Sstevel@tonic-gate static void
prfreecommon(prcommon_t * pcp)45410Sstevel@tonic-gate prfreecommon(prcommon_t *pcp)
45420Sstevel@tonic-gate {
45430Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
45440Sstevel@tonic-gate 	ASSERT(pcp->prc_refcnt > 0);
45450Sstevel@tonic-gate 	if (--pcp->prc_refcnt != 0)
45460Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
45470Sstevel@tonic-gate 	else {
45480Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
45490Sstevel@tonic-gate 		ASSERT(pcp->prc_pollhead.ph_list == NULL);
45500Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt == 0);
45510Sstevel@tonic-gate 		ASSERT(pcp->prc_selfopens == 0 && pcp->prc_writers == 0);
45520Sstevel@tonic-gate 		mutex_destroy(&pcp->prc_mutex);
45530Sstevel@tonic-gate 		cv_destroy(&pcp->prc_wait);
45540Sstevel@tonic-gate 		kmem_free(pcp, sizeof (prcommon_t));
45550Sstevel@tonic-gate 		DECREMENT(nprcommon);
45560Sstevel@tonic-gate 	}
45570Sstevel@tonic-gate }
45580Sstevel@tonic-gate 
45590Sstevel@tonic-gate /*
45600Sstevel@tonic-gate  * Array of readdir functions, indexed by /proc file type.
45610Sstevel@tonic-gate  */
45620Sstevel@tonic-gate static int pr_readdir_notdir(), pr_readdir_procdir(), pr_readdir_piddir(),
45630Sstevel@tonic-gate 	pr_readdir_objectdir(), pr_readdir_lwpdir(), pr_readdir_lwpiddir(),
45640Sstevel@tonic-gate 	pr_readdir_fddir(), pr_readdir_pathdir(), pr_readdir_tmpldir(),
45650Sstevel@tonic-gate 	pr_readdir_ctdir();
45660Sstevel@tonic-gate 
45670Sstevel@tonic-gate static int (*pr_readdir_function[PR_NFILES])() = {
45680Sstevel@tonic-gate 	pr_readdir_procdir,	/* /proc				*/
45690Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/self				*/
45700Sstevel@tonic-gate 	pr_readdir_piddir,	/* /proc/<pid>				*/
45710Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/as			*/
45720Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/ctl			*/
45730Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/status			*/
45740Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lstatus			*/
45750Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/psinfo			*/
45760Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lpsinfo			*/
45770Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/map			*/
45780Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/rmap			*/
45790Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/xmap			*/
45800Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/cred			*/
45810Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/sigact			*/
45820Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/auxv			*/
45830Sstevel@tonic-gate #if defined(__x86)
45840Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/ldt			*/
45850Sstevel@tonic-gate #endif
45860Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/usage			*/
45870Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lusage			*/
45880Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/pagedata			*/
45890Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/watch			*/
45900Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/cwd			*/
45910Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/root			*/
45920Sstevel@tonic-gate 	pr_readdir_fddir,	/* /proc/<pid>/fd			*/
45930Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/fd/nn			*/
45940Sstevel@tonic-gate 	pr_readdir_objectdir,	/* /proc/<pid>/object			*/
45950Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/object/xxx		*/
45960Sstevel@tonic-gate 	pr_readdir_lwpdir,	/* /proc/<pid>/lwp			*/
45970Sstevel@tonic-gate 	pr_readdir_lwpiddir,	/* /proc/<pid>/lwp/<lwpid>		*/
45980Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
45990Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
46000Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
46010Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
46020Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
46030Sstevel@tonic-gate 	pr_readdir_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
46040Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
46050Sstevel@tonic-gate #if defined(__sparc)
46060Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
46070Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
46080Sstevel@tonic-gate #endif
46090Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/priv			*/
46100Sstevel@tonic-gate 	pr_readdir_pathdir,	/* /proc/<pid>/path			*/
46110Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/path/xxx			*/
46120Sstevel@tonic-gate 	pr_readdir_ctdir,	/* /proc/<pid>/contracts		*/
46130Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/contracts/<ctid>		*/
46140Sstevel@tonic-gate 	pr_readdir_notdir,	/* old process file			*/
46150Sstevel@tonic-gate 	pr_readdir_notdir,	/* old lwp file				*/
46160Sstevel@tonic-gate 	pr_readdir_notdir,	/* old pagedata file			*/
46170Sstevel@tonic-gate };
46180Sstevel@tonic-gate 
46190Sstevel@tonic-gate /* ARGSUSED */
46200Sstevel@tonic-gate static int
prreaddir(vnode_t * vp,uio_t * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)46215331Samw prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
46225331Samw 	caller_context_t *ct, int flags)
46230Sstevel@tonic-gate {
46240Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
46250Sstevel@tonic-gate 
46260Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
46270Sstevel@tonic-gate 
46285331Samw 	/* XXX - Do we need to pass ct and flags? */
46290Sstevel@tonic-gate 	return (pr_readdir_function[pnp->pr_type](pnp, uiop, eofp));
46300Sstevel@tonic-gate }
46310Sstevel@tonic-gate 
46320Sstevel@tonic-gate /* ARGSUSED */
46330Sstevel@tonic-gate static int
pr_readdir_notdir(prnode_t * pnp,uio_t * uiop,int * eofp)46340Sstevel@tonic-gate pr_readdir_notdir(prnode_t *pnp, uio_t *uiop, int *eofp)
46350Sstevel@tonic-gate {
46360Sstevel@tonic-gate 	return (ENOTDIR);
46370Sstevel@tonic-gate }
46380Sstevel@tonic-gate 
46390Sstevel@tonic-gate /* ARGSUSED */
46400Sstevel@tonic-gate static int
pr_readdir_procdir(prnode_t * pnp,uio_t * uiop,int * eofp)46410Sstevel@tonic-gate pr_readdir_procdir(prnode_t *pnp, uio_t *uiop, int *eofp)
46420Sstevel@tonic-gate {
46430Sstevel@tonic-gate 	zoneid_t zoneid;
46440Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
46450Sstevel@tonic-gate 	int error, eof = 0;
46460Sstevel@tonic-gate 	offset_t n;
46470Sstevel@tonic-gate 
46480Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PROCDIR);
46490Sstevel@tonic-gate 
4650789Sahrens 	zoneid = VTOZONE(PTOV(pnp))->zone_id;
46510Sstevel@tonic-gate 
46520Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PNSIZ, PRSDSIZE, uiop,
46535663Sck153898 	    PRROOTINO, PRROOTINO, 0)) != 0)
46540Sstevel@tonic-gate 		return (error);
46550Sstevel@tonic-gate 
46560Sstevel@tonic-gate 	/*
46570Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until all processes
46580Sstevel@tonic-gate 	 * have been examined.
46590Sstevel@tonic-gate 	 */
46600Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
46610Sstevel@tonic-gate 		uint_t pid;
46620Sstevel@tonic-gate 		int pslot;
46630Sstevel@tonic-gate 		proc_t *p;
46640Sstevel@tonic-gate 
46650Sstevel@tonic-gate 		/*
46660Sstevel@tonic-gate 		 * Find next entry.  Skip processes not visible where
46670Sstevel@tonic-gate 		 * this /proc was mounted.
46680Sstevel@tonic-gate 		 */
46690Sstevel@tonic-gate 		mutex_enter(&pidlock);
46700Sstevel@tonic-gate 		while (n < v.v_proc &&
46710Sstevel@tonic-gate 		    ((p = pid_entry(n)) == NULL || p->p_stat == SIDL ||
46720Sstevel@tonic-gate 		    (zoneid != GLOBAL_ZONEID && p->p_zone->zone_id != zoneid) ||
46730Sstevel@tonic-gate 		    secpolicy_basic_procinfo(CRED(), p, curproc) != 0))
46740Sstevel@tonic-gate 			n++;
46750Sstevel@tonic-gate 
46760Sstevel@tonic-gate 		/*
46770Sstevel@tonic-gate 		 * Stop when entire proc table has been examined.
46780Sstevel@tonic-gate 		 */
46790Sstevel@tonic-gate 		if (n >= v.v_proc) {
46800Sstevel@tonic-gate 			mutex_exit(&pidlock);
46810Sstevel@tonic-gate 			eof = 1;
46820Sstevel@tonic-gate 			break;
46830Sstevel@tonic-gate 		}
46840Sstevel@tonic-gate 
46850Sstevel@tonic-gate 		ASSERT(p->p_stat != 0);
46860Sstevel@tonic-gate 		pid = p->p_pid;
46870Sstevel@tonic-gate 		pslot = p->p_slot;
46880Sstevel@tonic-gate 		mutex_exit(&pidlock);
46890Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, n,
46900Sstevel@tonic-gate 		    pmkino(0, pslot, PR_PIDDIR), pid);
46910Sstevel@tonic-gate 		if (error)
46920Sstevel@tonic-gate 			break;
46930Sstevel@tonic-gate 	}
46940Sstevel@tonic-gate 
46950Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
46960Sstevel@tonic-gate }
46970Sstevel@tonic-gate 
46980Sstevel@tonic-gate /* ARGSUSED */
46990Sstevel@tonic-gate static int
pr_readdir_piddir(prnode_t * pnp,uio_t * uiop,int * eofp)47000Sstevel@tonic-gate pr_readdir_piddir(prnode_t *pnp, uio_t *uiop, int *eofp)
47010Sstevel@tonic-gate {
47020Sstevel@tonic-gate 	int zombie = ((pnp->pr_pcommon->prc_flags & PRC_DESTROY) != 0);
47030Sstevel@tonic-gate 	prdirent_t dirent;
47040Sstevel@tonic-gate 	prdirent_t *dirp;
47050Sstevel@tonic-gate 	offset_t off;
47060Sstevel@tonic-gate 	int error;
47070Sstevel@tonic-gate 
47080Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDDIR);
47090Sstevel@tonic-gate 
47100Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
47110Sstevel@tonic-gate 	    uiop->uio_offset % sizeof (prdirent_t) != 0 ||
47120Sstevel@tonic-gate 	    uiop->uio_resid < sizeof (prdirent_t))
47130Sstevel@tonic-gate 		return (EINVAL);
47140Sstevel@tonic-gate 	if (pnp->pr_pcommon->prc_proc == NULL)
47150Sstevel@tonic-gate 		return (ENOENT);
47160Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (piddir))
47170Sstevel@tonic-gate 		goto out;
47180Sstevel@tonic-gate 
47190Sstevel@tonic-gate 	/*
47200Sstevel@tonic-gate 	 * Loop until user's request is satisfied, omitting some
47210Sstevel@tonic-gate 	 * files along the way if the process is a zombie.
47220Sstevel@tonic-gate 	 */
47230Sstevel@tonic-gate 	for (dirp = &piddir[uiop->uio_offset / sizeof (prdirent_t)];
47240Sstevel@tonic-gate 	    uiop->uio_resid >= sizeof (prdirent_t) &&
47250Sstevel@tonic-gate 	    dirp < &piddir[NPIDDIRFILES+2];
47260Sstevel@tonic-gate 	    uiop->uio_offset = off + sizeof (prdirent_t), dirp++) {
47270Sstevel@tonic-gate 		off = uiop->uio_offset;
47280Sstevel@tonic-gate 		if (zombie) {
47290Sstevel@tonic-gate 			switch (dirp->d_ino) {
47300Sstevel@tonic-gate 			case PR_PIDDIR:
47310Sstevel@tonic-gate 			case PR_PROCDIR:
47320Sstevel@tonic-gate 			case PR_PSINFO:
47330Sstevel@tonic-gate 			case PR_USAGE:
47340Sstevel@tonic-gate 				break;
47350Sstevel@tonic-gate 			default:
47360Sstevel@tonic-gate 				continue;
47370Sstevel@tonic-gate 			}
47380Sstevel@tonic-gate 		}
47390Sstevel@tonic-gate 		bcopy(dirp, &dirent, sizeof (prdirent_t));
47400Sstevel@tonic-gate 		if (dirent.d_ino == PR_PROCDIR)
47410Sstevel@tonic-gate 			dirent.d_ino = PRROOTINO;
47420Sstevel@tonic-gate 		else
47430Sstevel@tonic-gate 			dirent.d_ino = pmkino(0, pnp->pr_pcommon->prc_slot,
47445663Sck153898 			    dirent.d_ino);
47450Sstevel@tonic-gate 		if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
47460Sstevel@tonic-gate 		    UIO_READ, uiop)) != 0)
47470Sstevel@tonic-gate 			return (error);
47480Sstevel@tonic-gate 	}
47490Sstevel@tonic-gate out:
47500Sstevel@tonic-gate 	if (eofp)
47510Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= sizeof (piddir));
47520Sstevel@tonic-gate 	return (0);
47530Sstevel@tonic-gate }
47540Sstevel@tonic-gate 
47550Sstevel@tonic-gate static void
rebuild_objdir(struct as * as)47560Sstevel@tonic-gate rebuild_objdir(struct as *as)
47570Sstevel@tonic-gate {
47580Sstevel@tonic-gate 	struct seg *seg;
47590Sstevel@tonic-gate 	vnode_t *vp;
47600Sstevel@tonic-gate 	vattr_t vattr;
47610Sstevel@tonic-gate 	vnode_t **dir;
47620Sstevel@tonic-gate 	ulong_t nalloc;
47630Sstevel@tonic-gate 	ulong_t nentries;
47640Sstevel@tonic-gate 	int i, j;
47650Sstevel@tonic-gate 	ulong_t nold, nnew;
47660Sstevel@tonic-gate 
47670Sstevel@tonic-gate 	ASSERT(AS_WRITE_HELD(as, &as->a_lock));
47680Sstevel@tonic-gate 
47690Sstevel@tonic-gate 	if (as->a_updatedir == 0 && as->a_objectdir != NULL)
47700Sstevel@tonic-gate 		return;
47710Sstevel@tonic-gate 	as->a_updatedir = 0;
47720Sstevel@tonic-gate 
47730Sstevel@tonic-gate 	if ((nalloc = avl_numnodes(&as->a_segtree)) == 0 ||
47740Sstevel@tonic-gate 	    (seg = AS_SEGFIRST(as)) == NULL)	/* can't happen? */
47750Sstevel@tonic-gate 		return;
47760Sstevel@tonic-gate 
47770Sstevel@tonic-gate 	/*
47780Sstevel@tonic-gate 	 * Allocate space for the new object directory.
47790Sstevel@tonic-gate 	 * (This is usually about two times too many entries.)
47800Sstevel@tonic-gate 	 */
47810Sstevel@tonic-gate 	nalloc = (nalloc + 0xf) & ~0xf;		/* multiple of 16 */
47820Sstevel@tonic-gate 	dir = kmem_zalloc(nalloc * sizeof (vnode_t *), KM_SLEEP);
47830Sstevel@tonic-gate 
47840Sstevel@tonic-gate 	/* fill in the new directory with desired entries */
47850Sstevel@tonic-gate 	nentries = 0;
47860Sstevel@tonic-gate 	do {
47870Sstevel@tonic-gate 		vattr.va_mask = AT_FSID|AT_NODEID;
47880Sstevel@tonic-gate 		if (seg->s_ops == &segvn_ops &&
47890Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
47900Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
47915331Samw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
47920Sstevel@tonic-gate 			for (i = 0; i < nentries; i++)
47930Sstevel@tonic-gate 				if (vp == dir[i])
47940Sstevel@tonic-gate 					break;
47950Sstevel@tonic-gate 			if (i == nentries) {
47960Sstevel@tonic-gate 				ASSERT(nentries < nalloc);
47970Sstevel@tonic-gate 				dir[nentries++] = vp;
47980Sstevel@tonic-gate 			}
47990Sstevel@tonic-gate 		}
48000Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
48010Sstevel@tonic-gate 
48020Sstevel@tonic-gate 	if (as->a_objectdir == NULL) {	/* first time */
48030Sstevel@tonic-gate 		as->a_objectdir = dir;
48040Sstevel@tonic-gate 		as->a_sizedir = nalloc;
48050Sstevel@tonic-gate 		return;
48060Sstevel@tonic-gate 	}
48070Sstevel@tonic-gate 
48080Sstevel@tonic-gate 	/*
48090Sstevel@tonic-gate 	 * Null out all of the defunct entries in the old directory.
48100Sstevel@tonic-gate 	 */
48110Sstevel@tonic-gate 	nold = 0;
48120Sstevel@tonic-gate 	nnew = nentries;
48130Sstevel@tonic-gate 	for (i = 0; i < as->a_sizedir; i++) {
48140Sstevel@tonic-gate 		if ((vp = as->a_objectdir[i]) != NULL) {
48150Sstevel@tonic-gate 			for (j = 0; j < nentries; j++) {
48160Sstevel@tonic-gate 				if (vp == dir[j]) {
48170Sstevel@tonic-gate 					dir[j] = NULL;
48180Sstevel@tonic-gate 					nnew--;
48190Sstevel@tonic-gate 					break;
48200Sstevel@tonic-gate 				}
48210Sstevel@tonic-gate 			}
48220Sstevel@tonic-gate 			if (j == nentries)
48230Sstevel@tonic-gate 				as->a_objectdir[i] = NULL;
48240Sstevel@tonic-gate 			else
48250Sstevel@tonic-gate 				nold++;
48260Sstevel@tonic-gate 		}
48270Sstevel@tonic-gate 	}
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate 	if (nold + nnew > as->a_sizedir) {
48300Sstevel@tonic-gate 		/*
48310Sstevel@tonic-gate 		 * Reallocate the old directory to have enough
48320Sstevel@tonic-gate 		 * space for the old and new entries combined.
48330Sstevel@tonic-gate 		 * Round up to the next multiple of 16.
48340Sstevel@tonic-gate 		 */
48350Sstevel@tonic-gate 		ulong_t newsize = (nold + nnew + 0xf) & ~0xf;
48360Sstevel@tonic-gate 		vnode_t **newdir = kmem_zalloc(newsize * sizeof (vnode_t *),
48375663Sck153898 		    KM_SLEEP);
48380Sstevel@tonic-gate 		bcopy(as->a_objectdir, newdir,
48395663Sck153898 		    as->a_sizedir * sizeof (vnode_t *));
48400Sstevel@tonic-gate 		kmem_free(as->a_objectdir, as->a_sizedir * sizeof (vnode_t *));
48410Sstevel@tonic-gate 		as->a_objectdir = newdir;
48420Sstevel@tonic-gate 		as->a_sizedir = newsize;
48430Sstevel@tonic-gate 	}
48440Sstevel@tonic-gate 
48450Sstevel@tonic-gate 	/*
48460Sstevel@tonic-gate 	 * Move all new entries to the old directory and
48470Sstevel@tonic-gate 	 * deallocate the space used by the new directory.
48480Sstevel@tonic-gate 	 */
48490Sstevel@tonic-gate 	if (nnew) {
48500Sstevel@tonic-gate 		for (i = 0, j = 0; i < nentries; i++) {
48510Sstevel@tonic-gate 			if ((vp = dir[i]) == NULL)
48520Sstevel@tonic-gate 				continue;
48530Sstevel@tonic-gate 			for (; j < as->a_sizedir; j++) {
48540Sstevel@tonic-gate 				if (as->a_objectdir[j] != NULL)
48550Sstevel@tonic-gate 					continue;
48560Sstevel@tonic-gate 				as->a_objectdir[j++] = vp;
48570Sstevel@tonic-gate 				break;
48580Sstevel@tonic-gate 			}
48590Sstevel@tonic-gate 		}
48600Sstevel@tonic-gate 	}
48610Sstevel@tonic-gate 	kmem_free(dir, nalloc * sizeof (vnode_t *));
48620Sstevel@tonic-gate }
48630Sstevel@tonic-gate 
48640Sstevel@tonic-gate /*
48650Sstevel@tonic-gate  * Return the vnode from a slot in the process's object directory.
48660Sstevel@tonic-gate  * The caller must have locked the process's address space.
48670Sstevel@tonic-gate  * The only caller is below, in pr_readdir_objectdir().
48680Sstevel@tonic-gate  */
48690Sstevel@tonic-gate static vnode_t *
obj_entry(struct as * as,int slot)48700Sstevel@tonic-gate obj_entry(struct as *as, int slot)
48710Sstevel@tonic-gate {
48720Sstevel@tonic-gate 	ASSERT(AS_LOCK_HELD(as, &as->a_lock));
48730Sstevel@tonic-gate 	if (as->a_objectdir == NULL)
48740Sstevel@tonic-gate 		return (NULL);
48750Sstevel@tonic-gate 	ASSERT(slot < as->a_sizedir);
48760Sstevel@tonic-gate 	return (as->a_objectdir[slot]);
48770Sstevel@tonic-gate }
48780Sstevel@tonic-gate 
48790Sstevel@tonic-gate /* ARGSUSED */
48800Sstevel@tonic-gate static int
pr_readdir_objectdir(prnode_t * pnp,uio_t * uiop,int * eofp)48810Sstevel@tonic-gate pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
48820Sstevel@tonic-gate {
48830Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
48840Sstevel@tonic-gate 	int error, eof = 0;
48850Sstevel@tonic-gate 	offset_t n;
48860Sstevel@tonic-gate 	int pslot;
48870Sstevel@tonic-gate 	size_t objdirsize;
48880Sstevel@tonic-gate 	proc_t *p;
48890Sstevel@tonic-gate 	struct as *as;
48900Sstevel@tonic-gate 	vnode_t *vp;
48910Sstevel@tonic-gate 
48920Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OBJECTDIR);
48930Sstevel@tonic-gate 
48940Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
48950Sstevel@tonic-gate 		return (error);
48960Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
48970Sstevel@tonic-gate 	pslot = p->p_slot;
48980Sstevel@tonic-gate 
48990Sstevel@tonic-gate 	/*
49000Sstevel@tonic-gate 	 * We drop p_lock before grabbing the address space lock
49010Sstevel@tonic-gate 	 * in order to avoid a deadlock with the clock thread.
49020Sstevel@tonic-gate 	 * The process will not disappear and its address space
49030Sstevel@tonic-gate 	 * will not change because it is marked P_PR_LOCK.
49040Sstevel@tonic-gate 	 */
49050Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
49060Sstevel@tonic-gate 
49070Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, 64, PRSDSIZE, uiop,
49080Sstevel@tonic-gate 	    pmkino(0, pslot, PR_PIDDIR),
49095663Sck153898 	    pmkino(0, pslot, PR_OBJECTDIR), 0)) != 0) {
49100Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
49110Sstevel@tonic-gate 		prunlock(pnp);
49120Sstevel@tonic-gate 		return (error);
49130Sstevel@tonic-gate 	}
49140Sstevel@tonic-gate 
49150Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
49160Sstevel@tonic-gate 		as = NULL;
49170Sstevel@tonic-gate 		objdirsize = 0;
49180Sstevel@tonic-gate 	}
49190Sstevel@tonic-gate 
49200Sstevel@tonic-gate 	/*
49210Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until
4922774Spetede 	 * all mapped objects have been examined. Cannot hold
4923774Spetede 	 * the address space lock for the following call as
4924774Spetede 	 * gfs_readdir_pred() utimately causes a call to uiomove().
49250Sstevel@tonic-gate 	 */
49260Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
49270Sstevel@tonic-gate 		vattr_t vattr;
49280Sstevel@tonic-gate 		char str[64];
49290Sstevel@tonic-gate 
49300Sstevel@tonic-gate 		/*
4931774Spetede 		 * Set the correct size of the directory just
4932774Spetede 		 * in case the process has changed it's address
4933774Spetede 		 * space via mmap/munmap calls.
4934774Spetede 		 */
4935774Spetede 		if (as != NULL) {
4936774Spetede 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
4937774Spetede 			if (as->a_updatedir)
4938774Spetede 				rebuild_objdir(as);
4939774Spetede 			objdirsize = as->a_sizedir;
4940774Spetede 		}
4941774Spetede 
4942774Spetede 		/*
49430Sstevel@tonic-gate 		 * Find next object.
49440Sstevel@tonic-gate 		 */
49450Sstevel@tonic-gate 		vattr.va_mask = AT_FSID | AT_NODEID;
49460Sstevel@tonic-gate 		while (n < objdirsize && (((vp = obj_entry(as, n)) == NULL) ||
49475331Samw 		    (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)
49485331Samw 		    != 0))) {
49490Sstevel@tonic-gate 			vattr.va_mask = AT_FSID | AT_NODEID;
49500Sstevel@tonic-gate 			n++;
49510Sstevel@tonic-gate 		}
49520Sstevel@tonic-gate 
4953774Spetede 		if (as != NULL)
4954774Spetede 			AS_LOCK_EXIT(as, &as->a_lock);
4955774Spetede 
49560Sstevel@tonic-gate 		/*
49570Sstevel@tonic-gate 		 * Stop when all objects have been reported.
49580Sstevel@tonic-gate 		 */
49590Sstevel@tonic-gate 		if (n >= objdirsize) {
49600Sstevel@tonic-gate 			eof = 1;
49610Sstevel@tonic-gate 			break;
49620Sstevel@tonic-gate 		}
49630Sstevel@tonic-gate 
49640Sstevel@tonic-gate 		if (vp == p->p_exec)
49650Sstevel@tonic-gate 			(void) strcpy(str, "a.out");
49660Sstevel@tonic-gate 		else
49670Sstevel@tonic-gate 			pr_object_name(str, vp, &vattr);
49680Sstevel@tonic-gate 
49690Sstevel@tonic-gate 		error = gfs_readdir_emit(&gstate, uiop, n, vattr.va_nodeid,
49705663Sck153898 		    str, 0);
4971774Spetede 
49720Sstevel@tonic-gate 		if (error)
49730Sstevel@tonic-gate 			break;
49740Sstevel@tonic-gate 	}
49750Sstevel@tonic-gate 
49760Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
49770Sstevel@tonic-gate 	prunlock(pnp);
49780Sstevel@tonic-gate 
49790Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
49800Sstevel@tonic-gate }
49810Sstevel@tonic-gate 
49820Sstevel@tonic-gate /* ARGSUSED */
49830Sstevel@tonic-gate static int
pr_readdir_lwpdir(prnode_t * pnp,uio_t * uiop,int * eofp)49840Sstevel@tonic-gate pr_readdir_lwpdir(prnode_t *pnp, uio_t *uiop, int *eofp)
49850Sstevel@tonic-gate {
49860Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
49870Sstevel@tonic-gate 	int error, eof = 0;
49880Sstevel@tonic-gate 	offset_t tslot;
49890Sstevel@tonic-gate 	proc_t *p;
49900Sstevel@tonic-gate 	int pslot;
49910Sstevel@tonic-gate 	lwpdir_t *lwpdir;
49920Sstevel@tonic-gate 	int lwpdirsize;
49930Sstevel@tonic-gate 
49940Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPDIR);
49950Sstevel@tonic-gate 
49960Sstevel@tonic-gate 	p = pr_p_lock(pnp);
49970Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
49980Sstevel@tonic-gate 	if (p == NULL)
49990Sstevel@tonic-gate 		return (ENOENT);
50000Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
50010Sstevel@tonic-gate 	pslot = p->p_slot;
50020Sstevel@tonic-gate 	lwpdir = p->p_lwpdir;
50030Sstevel@tonic-gate 	lwpdirsize = p->p_lwpdir_sz;
50040Sstevel@tonic-gate 
50050Sstevel@tonic-gate 	/*
50060Sstevel@tonic-gate 	 * Drop p->p_lock so we can safely do uiomove().
50070Sstevel@tonic-gate 	 * The lwp directory will not change because
50080Sstevel@tonic-gate 	 * we have the process locked with P_PR_LOCK.
50090Sstevel@tonic-gate 	 */
50100Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
50110Sstevel@tonic-gate 
50120Sstevel@tonic-gate 
50130Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
50145663Sck153898 	    pmkino(0, pslot, PR_PIDDIR),
50155663Sck153898 	    pmkino(0, pslot, PR_LWPDIR), 0)) != 0) {
50160Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
50170Sstevel@tonic-gate 		prunlock(pnp);
50180Sstevel@tonic-gate 		return (error);
50190Sstevel@tonic-gate 	}
50200Sstevel@tonic-gate 
50210Sstevel@tonic-gate 	/*
50220Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until all lwps
50230Sstevel@tonic-gate 	 * have been examined.
50240Sstevel@tonic-gate 	 */
50250Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &tslot)) == 0) {
50260Sstevel@tonic-gate 		lwpent_t *lep;
50270Sstevel@tonic-gate 		uint_t tid;
50280Sstevel@tonic-gate 
50290Sstevel@tonic-gate 		/*
50300Sstevel@tonic-gate 		 * Find next LWP.
50310Sstevel@tonic-gate 		 */
50320Sstevel@tonic-gate 		while (tslot < lwpdirsize &&
50330Sstevel@tonic-gate 		    ((lep = lwpdir[tslot].ld_entry) == NULL))
50340Sstevel@tonic-gate 			tslot++;
50350Sstevel@tonic-gate 		/*
50360Sstevel@tonic-gate 		 * Stop when all lwps have been reported.
50370Sstevel@tonic-gate 		 */
50380Sstevel@tonic-gate 		if (tslot >= lwpdirsize) {
50390Sstevel@tonic-gate 			eof = 1;
50400Sstevel@tonic-gate 			break;
50410Sstevel@tonic-gate 		}
50420Sstevel@tonic-gate 
50430Sstevel@tonic-gate 		tid = lep->le_lwpid;
50440Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, tslot,
50450Sstevel@tonic-gate 		    pmkino(tslot, pslot, PR_LWPIDDIR), tid);
50460Sstevel@tonic-gate 		if (error)
50470Sstevel@tonic-gate 			break;
50480Sstevel@tonic-gate 	}
50490Sstevel@tonic-gate 
50500Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
50510Sstevel@tonic-gate 	prunlock(pnp);
50520Sstevel@tonic-gate 
50530Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
50540Sstevel@tonic-gate }
50550Sstevel@tonic-gate 
50560Sstevel@tonic-gate /* ARGSUSED */
50570Sstevel@tonic-gate static int
pr_readdir_lwpiddir(prnode_t * pnp,uio_t * uiop,int * eofp)50580Sstevel@tonic-gate pr_readdir_lwpiddir(prnode_t *pnp, uio_t *uiop, int *eofp)
50590Sstevel@tonic-gate {
50600Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
50610Sstevel@tonic-gate 	int zombie = ((pcp->prc_flags & PRC_DESTROY) != 0);
50620Sstevel@tonic-gate 	prdirent_t dirent;
50630Sstevel@tonic-gate 	prdirent_t *dirp;
50640Sstevel@tonic-gate 	offset_t off;
50650Sstevel@tonic-gate 	int error;
50660Sstevel@tonic-gate 	int pslot;
50670Sstevel@tonic-gate 	int tslot;
50680Sstevel@tonic-gate 
50690Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPIDDIR);
50700Sstevel@tonic-gate 
50710Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
50720Sstevel@tonic-gate 	    uiop->uio_offset % sizeof (prdirent_t) != 0 ||
50730Sstevel@tonic-gate 	    uiop->uio_resid < sizeof (prdirent_t))
50740Sstevel@tonic-gate 		return (EINVAL);
50750Sstevel@tonic-gate 	if (pcp->prc_proc == NULL || pcp->prc_tslot == -1)
50760Sstevel@tonic-gate 		return (ENOENT);
50770Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpiddir))
50780Sstevel@tonic-gate 		goto out;
50790Sstevel@tonic-gate 
50800Sstevel@tonic-gate 	/*
50810Sstevel@tonic-gate 	 * Loop until user's request is satisfied, omitting some files
50820Sstevel@tonic-gate 	 * along the way if the lwp is a zombie and also depending
50830Sstevel@tonic-gate 	 * on the data model of the process.
50840Sstevel@tonic-gate 	 */
50850Sstevel@tonic-gate 	pslot = pcp->prc_slot;
50860Sstevel@tonic-gate 	tslot = pcp->prc_tslot;
50870Sstevel@tonic-gate 	for (dirp = &lwpiddir[uiop->uio_offset / sizeof (prdirent_t)];
50880Sstevel@tonic-gate 	    uiop->uio_resid >= sizeof (prdirent_t) &&
50890Sstevel@tonic-gate 	    dirp < &lwpiddir[NLWPIDDIRFILES+2];
50900Sstevel@tonic-gate 	    uiop->uio_offset = off + sizeof (prdirent_t), dirp++) {
50910Sstevel@tonic-gate 		off = uiop->uio_offset;
50920Sstevel@tonic-gate 		if (zombie) {
50930Sstevel@tonic-gate 			switch (dirp->d_ino) {
50940Sstevel@tonic-gate 			case PR_LWPIDDIR:
50950Sstevel@tonic-gate 			case PR_LWPDIR:
50960Sstevel@tonic-gate 			case PR_LWPSINFO:
50970Sstevel@tonic-gate 				break;
50980Sstevel@tonic-gate 			default:
50990Sstevel@tonic-gate 				continue;
51000Sstevel@tonic-gate 			}
51010Sstevel@tonic-gate 		}
51020Sstevel@tonic-gate #if defined(__sparc)
51030Sstevel@tonic-gate 		/* the asrs file exists only for sparc v9 _LP64 processes */
51040Sstevel@tonic-gate 		if (dirp->d_ino == PR_ASRS &&
51050Sstevel@tonic-gate 		    pcp->prc_datamodel != DATAMODEL_LP64)
51060Sstevel@tonic-gate 			continue;
51070Sstevel@tonic-gate #endif
51080Sstevel@tonic-gate 		bcopy(dirp, &dirent, sizeof (prdirent_t));
51090Sstevel@tonic-gate 		if (dirent.d_ino == PR_LWPDIR)
51100Sstevel@tonic-gate 			dirent.d_ino = pmkino(0, pslot, dirp->d_ino);
51110Sstevel@tonic-gate 		else
51120Sstevel@tonic-gate 			dirent.d_ino = pmkino(tslot, pslot, dirp->d_ino);
51130Sstevel@tonic-gate 		if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
51140Sstevel@tonic-gate 		    UIO_READ, uiop)) != 0)
51150Sstevel@tonic-gate 			return (error);
51160Sstevel@tonic-gate 	}
51170Sstevel@tonic-gate out:
51180Sstevel@tonic-gate 	if (eofp)
51190Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= sizeof (lwpiddir));
51200Sstevel@tonic-gate 	return (0);
51210Sstevel@tonic-gate }
51220Sstevel@tonic-gate 
51230Sstevel@tonic-gate /* ARGSUSED */
51240Sstevel@tonic-gate static int
pr_readdir_fddir(prnode_t * pnp,uio_t * uiop,int * eofp)51250Sstevel@tonic-gate pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
51260Sstevel@tonic-gate {
51270Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
51280Sstevel@tonic-gate 	int error, eof = 0;
51290Sstevel@tonic-gate 	offset_t n;
51300Sstevel@tonic-gate 	proc_t *p;
51310Sstevel@tonic-gate 	int pslot;
51320Sstevel@tonic-gate 	int fddirsize;
51330Sstevel@tonic-gate 	uf_info_t *fip;
51340Sstevel@tonic-gate 
51350Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_FDDIR);
51360Sstevel@tonic-gate 
51370Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
51380Sstevel@tonic-gate 		return (error);
51390Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
51400Sstevel@tonic-gate 	pslot = p->p_slot;
51410Sstevel@tonic-gate 	fip = P_FINFO(p);
51420Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
51430Sstevel@tonic-gate 
51440Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
51455663Sck153898 	    pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_FDDIR), 0)) != 0) {
51460Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
51470Sstevel@tonic-gate 		prunlock(pnp);
51480Sstevel@tonic-gate 		return (error);
51490Sstevel@tonic-gate 	}
51500Sstevel@tonic-gate 
51510Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
51520Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
51530Sstevel@tonic-gate 		fddirsize = 0;
51540Sstevel@tonic-gate 	else
51550Sstevel@tonic-gate 		fddirsize = fip->fi_nfiles;
51560Sstevel@tonic-gate 
51570Sstevel@tonic-gate 	/*
51580Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until
51590Sstevel@tonic-gate 	 * all file descriptors have been examined.
51600Sstevel@tonic-gate 	 */
51610Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
51620Sstevel@tonic-gate 		/*
51630Sstevel@tonic-gate 		 * Find next fd.
51640Sstevel@tonic-gate 		 */
51650Sstevel@tonic-gate 		while (n < fddirsize && fip->fi_list[n].uf_file == NULL)
51660Sstevel@tonic-gate 			n++;
51670Sstevel@tonic-gate 		/*
51680Sstevel@tonic-gate 		 * Stop when all fds have been reported.
51690Sstevel@tonic-gate 		 */
51700Sstevel@tonic-gate 		if (n >= fddirsize) {
51710Sstevel@tonic-gate 			eof = 1;
51720Sstevel@tonic-gate 			break;
51730Sstevel@tonic-gate 		}
51740Sstevel@tonic-gate 
51750Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, n,
51760Sstevel@tonic-gate 		    pmkino(n, pslot, PR_FD), n);
51770Sstevel@tonic-gate 		if (error)
51780Sstevel@tonic-gate 			break;
51790Sstevel@tonic-gate 	}
51800Sstevel@tonic-gate 
51810Sstevel@tonic-gate 	mutex_exit(&fip->fi_lock);
51820Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
51830Sstevel@tonic-gate 	prunlock(pnp);
51840Sstevel@tonic-gate 
51850Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
51860Sstevel@tonic-gate }
51870Sstevel@tonic-gate 
51880Sstevel@tonic-gate /* ARGSUSED */
51890Sstevel@tonic-gate static int
pr_readdir_pathdir(prnode_t * pnp,uio_t * uiop,int * eofp)51900Sstevel@tonic-gate pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
51910Sstevel@tonic-gate {
51920Sstevel@tonic-gate 	longlong_t bp[DIRENT64_RECLEN(64) / sizeof (longlong_t)];
51930Sstevel@tonic-gate 	dirent64_t *dirent = (dirent64_t *)bp;
51940Sstevel@tonic-gate 	int reclen;
51950Sstevel@tonic-gate 	ssize_t oresid;
51960Sstevel@tonic-gate 	offset_t off, idx;
51970Sstevel@tonic-gate 	int error = 0;
51980Sstevel@tonic-gate 	proc_t *p;
51990Sstevel@tonic-gate 	int fd, obj;
52000Sstevel@tonic-gate 	int pslot;
52010Sstevel@tonic-gate 	int fddirsize;
52020Sstevel@tonic-gate 	uf_info_t *fip;
52030Sstevel@tonic-gate 	struct as *as = NULL;
52040Sstevel@tonic-gate 	size_t objdirsize;
52050Sstevel@tonic-gate 	vattr_t vattr;
52060Sstevel@tonic-gate 	vnode_t *vp;
52070Sstevel@tonic-gate 
52080Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PATHDIR);
52090Sstevel@tonic-gate 
52100Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
52110Sstevel@tonic-gate 	    uiop->uio_resid <= 0 ||
52120Sstevel@tonic-gate 	    (uiop->uio_offset % PRSDSIZE) != 0)
52130Sstevel@tonic-gate 		return (EINVAL);
52140Sstevel@tonic-gate 	oresid = uiop->uio_resid;
52150Sstevel@tonic-gate 	bzero(bp, sizeof (bp));
52160Sstevel@tonic-gate 
52170Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
52180Sstevel@tonic-gate 		return (error);
52190Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
52200Sstevel@tonic-gate 	fip = P_FINFO(p);
52210Sstevel@tonic-gate 	pslot = p->p_slot;
52220Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
52230Sstevel@tonic-gate 
52240Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
52250Sstevel@tonic-gate 		as = NULL;
52260Sstevel@tonic-gate 		objdirsize = 0;
52270Sstevel@tonic-gate 	} else {
52280Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
52290Sstevel@tonic-gate 		if (as->a_updatedir)
52300Sstevel@tonic-gate 			rebuild_objdir(as);
52310Sstevel@tonic-gate 		objdirsize = as->a_sizedir;
52320Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
52330Sstevel@tonic-gate 		as = NULL;
52340Sstevel@tonic-gate 	}
52350Sstevel@tonic-gate 
52360Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
52370Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
52380Sstevel@tonic-gate 		fddirsize = 0;
52390Sstevel@tonic-gate 	else
52400Sstevel@tonic-gate 		fddirsize = fip->fi_nfiles;
52410Sstevel@tonic-gate 
52420Sstevel@tonic-gate 	for (; uiop->uio_resid > 0; uiop->uio_offset = off + PRSDSIZE) {
52430Sstevel@tonic-gate 		/*
52440Sstevel@tonic-gate 		 * There are 4 special files in the path directory: ".", "..",
52450Sstevel@tonic-gate 		 * "root", and "cwd".  We handle those specially here.
52460Sstevel@tonic-gate 		 */
52470Sstevel@tonic-gate 		off = uiop->uio_offset;
52480Sstevel@tonic-gate 		idx = off / PRSDSIZE;
52490Sstevel@tonic-gate 		if (off == 0) {				/* "." */
52500Sstevel@tonic-gate 			dirent->d_ino = pmkino(0, pslot, PR_PATHDIR);
52510Sstevel@tonic-gate 			dirent->d_name[0] = '.';
52520Sstevel@tonic-gate 			dirent->d_name[1] = '\0';
52530Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(1);
52540Sstevel@tonic-gate 		} else if (idx == 1) {			/* ".." */
52550Sstevel@tonic-gate 			dirent->d_ino = pmkino(0, pslot, PR_PIDDIR);
52560Sstevel@tonic-gate 			dirent->d_name[0] = '.';
52570Sstevel@tonic-gate 			dirent->d_name[1] = '.';
52580Sstevel@tonic-gate 			dirent->d_name[2] = '\0';
52590Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(2);
52600Sstevel@tonic-gate 		} else if (idx == 2) {			/* "root" */
52610Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
52620Sstevel@tonic-gate 			(void) strcpy(dirent->d_name, "root");
52630Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(4);
52640Sstevel@tonic-gate 		} else if (idx == 3) {			/* "cwd" */
52650Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
52660Sstevel@tonic-gate 			(void) strcpy(dirent->d_name, "cwd");
52670Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(3);
52680Sstevel@tonic-gate 		} else if (idx < 4 + fddirsize) {
52690Sstevel@tonic-gate 			/*
52700Sstevel@tonic-gate 			 * In this case, we have one of the file descriptors.
52710Sstevel@tonic-gate 			 */
52720Sstevel@tonic-gate 			fd = idx - 4;
52730Sstevel@tonic-gate 			if (fip->fi_list[fd].uf_file == NULL)
52740Sstevel@tonic-gate 				continue;
52750Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
52760Sstevel@tonic-gate 			(void) pr_u32tos(fd, dirent->d_name, PLNSIZ+1);
52770Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(PLNSIZ);
52780Sstevel@tonic-gate 		} else if (idx < 4 + fddirsize + objdirsize) {
52790Sstevel@tonic-gate 			if (fip != NULL) {
52800Sstevel@tonic-gate 				mutex_exit(&fip->fi_lock);
52810Sstevel@tonic-gate 				fip = NULL;
52820Sstevel@tonic-gate 			}
52830Sstevel@tonic-gate 
52840Sstevel@tonic-gate 			/*
52850Sstevel@tonic-gate 			 * We drop p_lock before grabbing the address space lock
52860Sstevel@tonic-gate 			 * in order to avoid a deadlock with the clock thread.
52870Sstevel@tonic-gate 			 * The process will not disappear and its address space
52880Sstevel@tonic-gate 			 * will not change because it is marked P_PR_LOCK.
52890Sstevel@tonic-gate 			 */
52900Sstevel@tonic-gate 			if (as == NULL) {
52910Sstevel@tonic-gate 				as = p->p_as;
52920Sstevel@tonic-gate 				AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
52930Sstevel@tonic-gate 			}
52940Sstevel@tonic-gate 
52950Sstevel@tonic-gate 			if (as->a_updatedir) {
52960Sstevel@tonic-gate 				rebuild_objdir(as);
52970Sstevel@tonic-gate 				objdirsize = as->a_sizedir;
52980Sstevel@tonic-gate 			}
52990Sstevel@tonic-gate 
53000Sstevel@tonic-gate 			obj = idx - 4 - fddirsize;
53010Sstevel@tonic-gate 			if ((vp = obj_entry(as, obj)) == NULL)
53020Sstevel@tonic-gate 				continue;
53030Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
53045331Samw 			if (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) != 0)
53050Sstevel@tonic-gate 				continue;
53060Sstevel@tonic-gate 			if (vp == p->p_exec)
53070Sstevel@tonic-gate 				(void) strcpy(dirent->d_name, "a.out");
53080Sstevel@tonic-gate 			else
53090Sstevel@tonic-gate 				pr_object_name(dirent->d_name, vp, &vattr);
53100Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
53110Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(strlen(dirent->d_name));
53120Sstevel@tonic-gate 		} else {
53130Sstevel@tonic-gate 			break;
53140Sstevel@tonic-gate 		}
53150Sstevel@tonic-gate 
53160Sstevel@tonic-gate 		dirent->d_off = uiop->uio_offset + PRSDSIZE;
53170Sstevel@tonic-gate 		dirent->d_reclen = (ushort_t)reclen;
53180Sstevel@tonic-gate 		if (reclen > uiop->uio_resid) {
53190Sstevel@tonic-gate 			/*
53200Sstevel@tonic-gate 			 * Error if no entries have been returned yet.
53210Sstevel@tonic-gate 			 */
53220Sstevel@tonic-gate 			if (uiop->uio_resid == oresid)
53230Sstevel@tonic-gate 				error = EINVAL;
53240Sstevel@tonic-gate 			break;
53250Sstevel@tonic-gate 		}
53260Sstevel@tonic-gate 		/*
53270Sstevel@tonic-gate 		 * Drop the address space lock to do the uiomove().
53280Sstevel@tonic-gate 		 */
53290Sstevel@tonic-gate 		if (as != NULL)
53300Sstevel@tonic-gate 			AS_LOCK_EXIT(as, &as->a_lock);
53310Sstevel@tonic-gate 
53320Sstevel@tonic-gate 		error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop);
53330Sstevel@tonic-gate 		if (as != NULL)
53340Sstevel@tonic-gate 			AS_LOCK_ENTER(as, &as->a_lock, RW_WRITER);
53350Sstevel@tonic-gate 
53360Sstevel@tonic-gate 		if (error)
53370Sstevel@tonic-gate 			break;
53380Sstevel@tonic-gate 	}
53390Sstevel@tonic-gate 
53400Sstevel@tonic-gate 	if (error == 0 && eofp)
53410Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= (fddirsize + 2) * PRSDSIZE);
53420Sstevel@tonic-gate 
53430Sstevel@tonic-gate 	if (fip != NULL)
53440Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
53450Sstevel@tonic-gate 	if (as != NULL)
53460Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
53470Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
53480Sstevel@tonic-gate 	prunlock(pnp);
53490Sstevel@tonic-gate 	return (error);
53500Sstevel@tonic-gate }
53510Sstevel@tonic-gate 
53520Sstevel@tonic-gate static int
pr_readdir_tmpldir(prnode_t * pnp,uio_t * uiop,int * eofp)53530Sstevel@tonic-gate pr_readdir_tmpldir(prnode_t *pnp, uio_t *uiop, int *eofp)
53540Sstevel@tonic-gate {
53550Sstevel@tonic-gate 	proc_t *p;
53560Sstevel@tonic-gate 	int pslot, tslot;
53570Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
53580Sstevel@tonic-gate 	int error, eof = 0;
53590Sstevel@tonic-gate 	offset_t n;
53600Sstevel@tonic-gate 
53610Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_TMPLDIR);
53620Sstevel@tonic-gate 
53630Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
53640Sstevel@tonic-gate 		return (error);
53650Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
53660Sstevel@tonic-gate 	pslot = pnp->pr_common->prc_slot;
53670Sstevel@tonic-gate 	tslot = pnp->pr_common->prc_tslot;
53680Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
53690Sstevel@tonic-gate 
53700Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
53710Sstevel@tonic-gate 	    pmkino(tslot, pslot, PR_LWPDIR),
53725663Sck153898 	    pmkino(tslot, pslot, PR_TMPLDIR), 0)) != 0) {
53730Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
53740Sstevel@tonic-gate 		prunlock(pnp);
53750Sstevel@tonic-gate 		return (error);
53760Sstevel@tonic-gate 	}
53770Sstevel@tonic-gate 
53780Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
53790Sstevel@tonic-gate 		/*
53800Sstevel@tonic-gate 		 * Check for an active template.  Reading a directory's
53810Sstevel@tonic-gate 		 * contents is already racy, so we don't bother taking
53820Sstevel@tonic-gate 		 * any locks.
53830Sstevel@tonic-gate 		 */
53840Sstevel@tonic-gate 		while (n < ct_ntypes &&
53850Sstevel@tonic-gate 		    pnp->pr_common->prc_thread->t_lwp->lwp_ct_active[n] == NULL)
53860Sstevel@tonic-gate 			n++;
53870Sstevel@tonic-gate 		/*
53880Sstevel@tonic-gate 		 * Stop when all types have been reported.
53890Sstevel@tonic-gate 		 */
53900Sstevel@tonic-gate 		if (n >= ct_ntypes) {
53910Sstevel@tonic-gate 			eof = 1;
53920Sstevel@tonic-gate 			break;
53930Sstevel@tonic-gate 		}
53940Sstevel@tonic-gate 		/*
53950Sstevel@tonic-gate 		 * The pmkino invocation below will need to be updated
53960Sstevel@tonic-gate 		 * when we create our fifth contract type.
53970Sstevel@tonic-gate 		 */
53980Sstevel@tonic-gate 		ASSERT(ct_ntypes <= 4);
53990Sstevel@tonic-gate 		error = gfs_readdir_emit(&gstate, uiop, n,
54000Sstevel@tonic-gate 		    pmkino((tslot << 2) | n, pslot, PR_TMPL),
54015663Sck153898 		    ct_types[n]->ct_type_name, 0);
54020Sstevel@tonic-gate 		if (error)
54030Sstevel@tonic-gate 			break;
54040Sstevel@tonic-gate 	}
54050Sstevel@tonic-gate 
54060Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
54070Sstevel@tonic-gate 	prunlock(pnp);
54080Sstevel@tonic-gate 
54090Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
54100Sstevel@tonic-gate }
54110Sstevel@tonic-gate 
54120Sstevel@tonic-gate static int
pr_readdir_ctdir(prnode_t * pnp,uio_t * uiop,int * eofp)54130Sstevel@tonic-gate pr_readdir_ctdir(prnode_t *pnp, uio_t *uiop, int *eofp)
54140Sstevel@tonic-gate {
54150Sstevel@tonic-gate 	proc_t *p;
54160Sstevel@tonic-gate 	int pslot;
54170Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
54180Sstevel@tonic-gate 	int error, eof = 0;
54190Sstevel@tonic-gate 	offset_t n;
54200Sstevel@tonic-gate 	uint64_t zid;
54210Sstevel@tonic-gate 
54220Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_CTDIR);
54230Sstevel@tonic-gate 
54240Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
54250Sstevel@tonic-gate 		return (error);
54260Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
54270Sstevel@tonic-gate 	pslot = p->p_slot;
54280Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
54290Sstevel@tonic-gate 
54300Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
54315663Sck153898 	    pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_CTDIR), 0)) != 0) {
54320Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
54330Sstevel@tonic-gate 		prunlock(pnp);
54340Sstevel@tonic-gate 		return (error);
54350Sstevel@tonic-gate 	}
54360Sstevel@tonic-gate 
5437789Sahrens 	zid = VTOZONE(pnp->pr_vnode)->zone_uniqid;
54380Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
54390Sstevel@tonic-gate 		id_t next = contract_plookup(p, n, zid);
54400Sstevel@tonic-gate 		if (next == -1) {
54410Sstevel@tonic-gate 			eof = 1;
54420Sstevel@tonic-gate 			break;
54430Sstevel@tonic-gate 		}
54440Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, next,
54450Sstevel@tonic-gate 		    pmkino(next, pslot, PR_CT), next);
54460Sstevel@tonic-gate 		if (error)
54470Sstevel@tonic-gate 			break;
54480Sstevel@tonic-gate 	}
54490Sstevel@tonic-gate 
54500Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
54510Sstevel@tonic-gate 	prunlock(pnp);
54520Sstevel@tonic-gate 
54530Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
54540Sstevel@tonic-gate }
54550Sstevel@tonic-gate 
54560Sstevel@tonic-gate /* ARGSUSED */
54570Sstevel@tonic-gate static int
prfsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)54585331Samw prfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
54590Sstevel@tonic-gate {
54600Sstevel@tonic-gate 	return (0);
54610Sstevel@tonic-gate }
54620Sstevel@tonic-gate 
54630Sstevel@tonic-gate /*
54640Sstevel@tonic-gate  * Utility: remove a /proc vnode from a linked list, threaded through pr_next.
54650Sstevel@tonic-gate  */
54660Sstevel@tonic-gate static void
pr_list_unlink(vnode_t * pvp,vnode_t ** listp)54670Sstevel@tonic-gate pr_list_unlink(vnode_t *pvp, vnode_t **listp)
54680Sstevel@tonic-gate {
54690Sstevel@tonic-gate 	vnode_t *vp;
54700Sstevel@tonic-gate 	prnode_t *pnp;
54710Sstevel@tonic-gate 
54720Sstevel@tonic-gate 	while ((vp = *listp) != NULL) {
54730Sstevel@tonic-gate 		pnp = VTOP(vp);
54740Sstevel@tonic-gate 		if (vp == pvp) {
54750Sstevel@tonic-gate 			*listp = pnp->pr_next;
54760Sstevel@tonic-gate 			pnp->pr_next = NULL;
54770Sstevel@tonic-gate 			break;
54780Sstevel@tonic-gate 		}
54790Sstevel@tonic-gate 		listp = &pnp->pr_next;
54800Sstevel@tonic-gate 	}
54810Sstevel@tonic-gate }
54820Sstevel@tonic-gate 
54830Sstevel@tonic-gate /* ARGSUSED */
54840Sstevel@tonic-gate static void
prinactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)54855331Samw prinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
54860Sstevel@tonic-gate {
54870Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
54880Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
54890Sstevel@tonic-gate 	proc_t *p;
54900Sstevel@tonic-gate 	vnode_t *dp;
54910Sstevel@tonic-gate 	vnode_t *ovp = NULL;
54920Sstevel@tonic-gate 	prnode_t *opnp = NULL;
54930Sstevel@tonic-gate 
54940Sstevel@tonic-gate 	switch (type) {
54950Sstevel@tonic-gate 	case PR_OBJECT:
54960Sstevel@tonic-gate 	case PR_FD:
54970Sstevel@tonic-gate 	case PR_SELF:
54980Sstevel@tonic-gate 	case PR_PATH:
54990Sstevel@tonic-gate 		/* These are not linked into the usual lists */
55000Sstevel@tonic-gate 		ASSERT(vp->v_count == 1);
55010Sstevel@tonic-gate 		if ((dp = pnp->pr_parent) != NULL)
55020Sstevel@tonic-gate 			VN_RELE(dp);
55030Sstevel@tonic-gate 		prfreenode(pnp);
55040Sstevel@tonic-gate 		return;
55050Sstevel@tonic-gate 	default:
55060Sstevel@tonic-gate 		break;
55070Sstevel@tonic-gate 	}
55080Sstevel@tonic-gate 
55090Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);
55100Sstevel@tonic-gate 	if (pnp->pr_pcommon == NULL)
55110Sstevel@tonic-gate 		p = NULL;
55120Sstevel@tonic-gate 	else if ((p = pnp->pr_pcommon->prc_proc) != NULL)
55130Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
55140Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
55150Sstevel@tonic-gate 
55160Sstevel@tonic-gate 	if (type == PR_PROCDIR || vp->v_count > 1) {
55170Sstevel@tonic-gate 		vp->v_count--;
55180Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
55190Sstevel@tonic-gate 		if (p != NULL)
55200Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
55210Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
55220Sstevel@tonic-gate 		return;
55230Sstevel@tonic-gate 	}
55240Sstevel@tonic-gate 
55250Sstevel@tonic-gate 	if ((dp = pnp->pr_parent) != NULL) {
55260Sstevel@tonic-gate 		prnode_t *dpnp;
55270Sstevel@tonic-gate 
55280Sstevel@tonic-gate 		switch (type) {
55290Sstevel@tonic-gate 		case PR_PIDFILE:
55300Sstevel@tonic-gate 		case PR_LWPIDFILE:
55310Sstevel@tonic-gate 		case PR_OPAGEDATA:
55320Sstevel@tonic-gate 			break;
55330Sstevel@tonic-gate 		default:
55340Sstevel@tonic-gate 			dpnp = VTOP(dp);
55350Sstevel@tonic-gate 			mutex_enter(&dpnp->pr_mutex);
55360Sstevel@tonic-gate 			if (dpnp->pr_files != NULL &&
55370Sstevel@tonic-gate 			    dpnp->pr_files[pnp->pr_index] == vp)
55380Sstevel@tonic-gate 				dpnp->pr_files[pnp->pr_index] = NULL;
55390Sstevel@tonic-gate 			mutex_exit(&dpnp->pr_mutex);
55400Sstevel@tonic-gate 			break;
55410Sstevel@tonic-gate 		}
55420Sstevel@tonic-gate 		pnp->pr_parent = NULL;
55430Sstevel@tonic-gate 	}
55440Sstevel@tonic-gate 
55450Sstevel@tonic-gate 	ASSERT(vp->v_count == 1);
55460Sstevel@tonic-gate 
55470Sstevel@tonic-gate 	/*
55480Sstevel@tonic-gate 	 * If we allocated an old /proc/pid node, free it too.
55490Sstevel@tonic-gate 	 */
55500Sstevel@tonic-gate 	if (pnp->pr_pidfile != NULL) {
55510Sstevel@tonic-gate 		ASSERT(type == PR_PIDDIR);
55520Sstevel@tonic-gate 		ovp = pnp->pr_pidfile;
55530Sstevel@tonic-gate 		opnp = VTOP(ovp);
55540Sstevel@tonic-gate 		ASSERT(opnp->pr_type == PR_PIDFILE);
55550Sstevel@tonic-gate 		pnp->pr_pidfile = NULL;
55560Sstevel@tonic-gate 	}
55570Sstevel@tonic-gate 
55580Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
55590Sstevel@tonic-gate 
55600Sstevel@tonic-gate 	if (p != NULL) {
55610Sstevel@tonic-gate 		/*
55620Sstevel@tonic-gate 		 * Remove the vnodes from the lists of
55630Sstevel@tonic-gate 		 * /proc vnodes for the process.
55640Sstevel@tonic-gate 		 */
55650Sstevel@tonic-gate 		int slot;
55660Sstevel@tonic-gate 
55670Sstevel@tonic-gate 		switch (type) {
55680Sstevel@tonic-gate 		case PR_PIDDIR:
55690Sstevel@tonic-gate 			pr_list_unlink(vp, &p->p_trace);
55700Sstevel@tonic-gate 			break;
55710Sstevel@tonic-gate 		case PR_LWPIDDIR:
55720Sstevel@tonic-gate 			if ((slot = pnp->pr_common->prc_tslot) != -1) {
55730Sstevel@tonic-gate 				lwpent_t *lep = p->p_lwpdir[slot].ld_entry;
55740Sstevel@tonic-gate 				pr_list_unlink(vp, &lep->le_trace);
55750Sstevel@tonic-gate 			}
55760Sstevel@tonic-gate 			break;
55770Sstevel@tonic-gate 		default:
55780Sstevel@tonic-gate 			pr_list_unlink(vp, &p->p_plist);
55790Sstevel@tonic-gate 			break;
55800Sstevel@tonic-gate 		}
55810Sstevel@tonic-gate 		if (ovp != NULL)
55820Sstevel@tonic-gate 			pr_list_unlink(ovp, &p->p_plist);
55830Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
55840Sstevel@tonic-gate 	}
55850Sstevel@tonic-gate 
55860Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
55870Sstevel@tonic-gate 
55880Sstevel@tonic-gate 	if (type == PR_CT && pnp->pr_contract != NULL) {
55890Sstevel@tonic-gate 		contract_rele(pnp->pr_contract);
55900Sstevel@tonic-gate 		pnp->pr_contract = NULL;
55910Sstevel@tonic-gate 	}
55920Sstevel@tonic-gate 
55930Sstevel@tonic-gate 	if (opnp != NULL)
55940Sstevel@tonic-gate 		prfreenode(opnp);
55950Sstevel@tonic-gate 	prfreenode(pnp);
55960Sstevel@tonic-gate 	if (dp != NULL) {
55970Sstevel@tonic-gate 		VN_RELE(dp);
55980Sstevel@tonic-gate 	}
55990Sstevel@tonic-gate }
56000Sstevel@tonic-gate 
56010Sstevel@tonic-gate /* ARGSUSED */
56020Sstevel@tonic-gate static int
prseek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)56035331Samw prseek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
56040Sstevel@tonic-gate {
56050Sstevel@tonic-gate 	return (0);
56060Sstevel@tonic-gate }
56070Sstevel@tonic-gate 
56080Sstevel@tonic-gate /*
56090Sstevel@tonic-gate  * We use the p_execdir member of proc_t to expand the %d token in core file
56100Sstevel@tonic-gate  * paths (the directory path for the executable that dumped core; see
56110Sstevel@tonic-gate  * coreadm(1M) for details). We'd like gcore(1) to be able to expand %d in
56120Sstevel@tonic-gate  * the same way as core dumping from the kernel, but there's no convenient
56130Sstevel@tonic-gate  * and comprehensible way to export the path name for p_execdir. To solve
56140Sstevel@tonic-gate  * this, we try to find the actual path to the executable that was used. In
56150Sstevel@tonic-gate  * pr_lookup_pathdir(), we mark the a.out path name vnode with the PR_AOUT
56160Sstevel@tonic-gate  * flag, and use that here to indicate that more work is needed beyond the
56170Sstevel@tonic-gate  * call to vnodetopath().
56180Sstevel@tonic-gate  */
56190Sstevel@tonic-gate static int
prreadlink_lookup(prnode_t * pnp,char * buf,size_t size,cred_t * cr)56200Sstevel@tonic-gate prreadlink_lookup(prnode_t *pnp, char *buf, size_t size, cred_t *cr)
56210Sstevel@tonic-gate {
56220Sstevel@tonic-gate 	proc_t *p;
56230Sstevel@tonic-gate 	vnode_t *vp, *execvp, *vrootp;
56240Sstevel@tonic-gate 	int ret;
56250Sstevel@tonic-gate 	size_t len;
56260Sstevel@tonic-gate 	dirent64_t *dp;
56270Sstevel@tonic-gate 	size_t dlen = DIRENT64_RECLEN(MAXPATHLEN);
56280Sstevel@tonic-gate 	char *dbuf;
56290Sstevel@tonic-gate 
56300Sstevel@tonic-gate 	p = curproc;
56310Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
56320Sstevel@tonic-gate 	if ((vrootp = PTOU(p)->u_rdir) == NULL)
56330Sstevel@tonic-gate 		vrootp = rootdir;
56340Sstevel@tonic-gate 	VN_HOLD(vrootp);
56350Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
56360Sstevel@tonic-gate 
56370Sstevel@tonic-gate 	ret = vnodetopath(vrootp, pnp->pr_realvp, buf, size, cr);
56380Sstevel@tonic-gate 
56390Sstevel@tonic-gate 	/*
56400Sstevel@tonic-gate 	 * If PR_AOUT isn't set, then we looked up the path for the vnode;
56410Sstevel@tonic-gate 	 * otherwise, we looked up the path for (what we believe to be) the
56420Sstevel@tonic-gate 	 * containing directory.
56430Sstevel@tonic-gate 	 */
56440Sstevel@tonic-gate 	if ((pnp->pr_flags & PR_AOUT) == 0) {
56450Sstevel@tonic-gate 		VN_RELE(vrootp);
56460Sstevel@tonic-gate 		return (ret);
56470Sstevel@tonic-gate 	}
56480Sstevel@tonic-gate 
56490Sstevel@tonic-gate 	/*
56500Sstevel@tonic-gate 	 * Fail if there's a problem locking the process. This will only
56510Sstevel@tonic-gate 	 * occur if the process is changing so the information we would
56520Sstevel@tonic-gate 	 * report would already be invalid.
56530Sstevel@tonic-gate 	 */
56540Sstevel@tonic-gate 	if (prlock(pnp, ZNO) != 0) {
56550Sstevel@tonic-gate 		VN_RELE(vrootp);
56560Sstevel@tonic-gate 		return (EIO);
56570Sstevel@tonic-gate 	}
56580Sstevel@tonic-gate 
56590Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
56600Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
56610Sstevel@tonic-gate 
56620Sstevel@tonic-gate 	execvp = p->p_exec;
56630Sstevel@tonic-gate 	VN_HOLD(execvp);
56640Sstevel@tonic-gate 
56650Sstevel@tonic-gate 	/*
56660Sstevel@tonic-gate 	 * If our initial lookup of the directory failed, fall back to
56670Sstevel@tonic-gate 	 * the path name information for p_exec.
56680Sstevel@tonic-gate 	 */
56690Sstevel@tonic-gate 	if (ret != 0) {
56700Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
56710Sstevel@tonic-gate 		prunlock(pnp);
56720Sstevel@tonic-gate 		ret = vnodetopath(vrootp, execvp, buf, size, cr);
56730Sstevel@tonic-gate 		VN_RELE(execvp);
56740Sstevel@tonic-gate 		VN_RELE(vrootp);
56750Sstevel@tonic-gate 		return (ret);
56760Sstevel@tonic-gate 	}
56770Sstevel@tonic-gate 
56780Sstevel@tonic-gate 	len = strlen(buf);
56790Sstevel@tonic-gate 
56800Sstevel@tonic-gate 	/*
56810Sstevel@tonic-gate 	 * We use u_comm as a guess for the last component of the full
56820Sstevel@tonic-gate 	 * executable path name. If there isn't going to be enough space
56830Sstevel@tonic-gate 	 * we fall back to using the p_exec so that we can have _an_
56840Sstevel@tonic-gate 	 * answer even if it's not perfect.
56850Sstevel@tonic-gate 	 */
56860Sstevel@tonic-gate 	if (strlen(PTOU(p)->u_comm) + len + 1 < size) {
56870Sstevel@tonic-gate 		buf[len] = '/';
56880Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, PTOU(p)->u_comm);
56890Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
56900Sstevel@tonic-gate 		prunlock(pnp);
56910Sstevel@tonic-gate 
56920Sstevel@tonic-gate 		/*
56930Sstevel@tonic-gate 		 * Do a forward lookup of our u_comm guess.
56940Sstevel@tonic-gate 		 */
56950Sstevel@tonic-gate 		if (lookupnameat(buf + len + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
56960Sstevel@tonic-gate 		    &vp, pnp->pr_realvp) == 0) {
56970Sstevel@tonic-gate 			if (vn_compare(vp, execvp)) {
56980Sstevel@tonic-gate 				VN_RELE(vp);
56990Sstevel@tonic-gate 				VN_RELE(execvp);
57000Sstevel@tonic-gate 				VN_RELE(vrootp);
57010Sstevel@tonic-gate 				return (0);
57020Sstevel@tonic-gate 			}
57030Sstevel@tonic-gate 
57040Sstevel@tonic-gate 			VN_RELE(vp);
57050Sstevel@tonic-gate 		}
57060Sstevel@tonic-gate 	} else {
57070Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
57080Sstevel@tonic-gate 		prunlock(pnp);
57090Sstevel@tonic-gate 	}
57100Sstevel@tonic-gate 
57110Sstevel@tonic-gate 	dbuf = kmem_alloc(dlen, KM_SLEEP);
57120Sstevel@tonic-gate 
57130Sstevel@tonic-gate 	/*
57140Sstevel@tonic-gate 	 * Try to find a matching vnode by iterating through the directory's
57150Sstevel@tonic-gate 	 * entries. If that fails, fall back to the path information for
57160Sstevel@tonic-gate 	 * p_exec.
57170Sstevel@tonic-gate 	 */
57180Sstevel@tonic-gate 	if ((ret = dirfindvp(vrootp, pnp->pr_realvp, execvp, cr, dbuf,
57190Sstevel@tonic-gate 	    dlen, &dp)) == 0 && strlen(dp->d_name) + len + 1 < size) {
57200Sstevel@tonic-gate 		buf[len] = '/';
57210Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, dp->d_name);
57220Sstevel@tonic-gate 	} else {
57230Sstevel@tonic-gate 		ret = vnodetopath(vrootp, execvp, buf, size, cr);
57240Sstevel@tonic-gate 	}
57250Sstevel@tonic-gate 
57260Sstevel@tonic-gate 	kmem_free(dbuf, dlen);
57270Sstevel@tonic-gate 	VN_RELE(execvp);
57280Sstevel@tonic-gate 	VN_RELE(vrootp);
57290Sstevel@tonic-gate 
57300Sstevel@tonic-gate 	return (ret);
57310Sstevel@tonic-gate }
57320Sstevel@tonic-gate 
57330Sstevel@tonic-gate /* ARGSUSED */
57340Sstevel@tonic-gate static int
prreadlink(vnode_t * vp,uio_t * uiop,cred_t * cr,caller_context_t * ctp)57355331Samw prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ctp)
57360Sstevel@tonic-gate {
57370Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
57380Sstevel@tonic-gate 	char *buf;
57390Sstevel@tonic-gate 	int ret = EINVAL;
57400Sstevel@tonic-gate 	char idbuf[16];
57410Sstevel@tonic-gate 	int length, rlength;
57420Sstevel@tonic-gate 	contract_t *ct;
57430Sstevel@tonic-gate 
57440Sstevel@tonic-gate 	switch (pnp->pr_type) {
57450Sstevel@tonic-gate 	case PR_SELF:
57460Sstevel@tonic-gate 		(void) snprintf(idbuf, sizeof (idbuf), "%d", curproc->p_pid);
57470Sstevel@tonic-gate 		ret = uiomove(idbuf, strlen(idbuf), UIO_READ, uiop);
57480Sstevel@tonic-gate 		break;
57490Sstevel@tonic-gate 	case PR_OBJECT:
57500Sstevel@tonic-gate 	case PR_FD:
57510Sstevel@tonic-gate 	case PR_CURDIR:
57520Sstevel@tonic-gate 	case PR_ROOTDIR:
57530Sstevel@tonic-gate 		if (pnp->pr_realvp->v_type == VDIR)
57540Sstevel@tonic-gate 			ret = 0;
57550Sstevel@tonic-gate 		break;
57560Sstevel@tonic-gate 	case PR_PATH:
57570Sstevel@tonic-gate 		buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
57580Sstevel@tonic-gate 
57590Sstevel@tonic-gate 		if ((ret = prreadlink_lookup(pnp, buf, MAXPATHLEN, cr)) == 0)
57600Sstevel@tonic-gate 			ret = uiomove(buf, strlen(buf), UIO_READ, uiop);
57610Sstevel@tonic-gate 
57620Sstevel@tonic-gate 		kmem_free(buf, MAXPATHLEN);
57630Sstevel@tonic-gate 		break;
57640Sstevel@tonic-gate 	case PR_CT:
57650Sstevel@tonic-gate 		ASSERT(pnp->pr_contract != NULL);
57660Sstevel@tonic-gate 		ct = pnp->pr_contract;
57670Sstevel@tonic-gate 		length = sizeof (CTFS_ROOT "//") + sizeof (idbuf) +
57680Sstevel@tonic-gate 		    strlen(ct->ct_type->ct_type_name);
57690Sstevel@tonic-gate 		buf = kmem_alloc(length, KM_SLEEP);
57700Sstevel@tonic-gate 		rlength = snprintf(buf, length, CTFS_ROOT "/%s/%d",
57710Sstevel@tonic-gate 		    ct->ct_type->ct_type_name, ct->ct_id);
57720Sstevel@tonic-gate 		ASSERT(rlength < length);
57730Sstevel@tonic-gate 		ret = uiomove(buf, rlength, UIO_READ, uiop);
57740Sstevel@tonic-gate 		kmem_free(buf, length);
57750Sstevel@tonic-gate 		break;
57760Sstevel@tonic-gate 	default:
57770Sstevel@tonic-gate 		break;
57780Sstevel@tonic-gate 	}
57790Sstevel@tonic-gate 
57800Sstevel@tonic-gate 	return (ret);
57810Sstevel@tonic-gate }
57820Sstevel@tonic-gate 
57835331Samw /*ARGSUSED2*/
57840Sstevel@tonic-gate static int
prcmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)57855331Samw prcmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
57860Sstevel@tonic-gate {
57870Sstevel@tonic-gate 	prnode_t *pp1, *pp2;
57880Sstevel@tonic-gate 
57890Sstevel@tonic-gate 	if (vp1 == vp2)
57900Sstevel@tonic-gate 		return (1);
57910Sstevel@tonic-gate 
57920Sstevel@tonic-gate 	if (!vn_matchops(vp1, prvnodeops) || !vn_matchops(vp2, prvnodeops))
57930Sstevel@tonic-gate 		return (0);
57940Sstevel@tonic-gate 
57950Sstevel@tonic-gate 	pp1 = VTOP(vp1);
57960Sstevel@tonic-gate 	pp2 = VTOP(vp2);
57970Sstevel@tonic-gate 
57980Sstevel@tonic-gate 	if (pp1->pr_type != pp2->pr_type)
57990Sstevel@tonic-gate 		return (0);
58000Sstevel@tonic-gate 	if (pp1->pr_type == PR_PROCDIR)
58010Sstevel@tonic-gate 		return (1);
58020Sstevel@tonic-gate 	if (pp1->pr_ino || pp2->pr_ino)
58030Sstevel@tonic-gate 		return (pp2->pr_ino == pp1->pr_ino);
58040Sstevel@tonic-gate 
58050Sstevel@tonic-gate 	if (pp1->pr_common == NULL || pp2->pr_common == NULL)
58060Sstevel@tonic-gate 		return (0);
58070Sstevel@tonic-gate 
58080Sstevel@tonic-gate 	return (pp1->pr_common->prc_slot == pp2->pr_common->prc_slot &&
58090Sstevel@tonic-gate 	    pp1->pr_common->prc_tslot == pp2->pr_common->prc_tslot);
58100Sstevel@tonic-gate }
58110Sstevel@tonic-gate 
58120Sstevel@tonic-gate static int
prrealvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)58135331Samw prrealvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
58140Sstevel@tonic-gate {
58150Sstevel@tonic-gate 	vnode_t *rvp;
58160Sstevel@tonic-gate 
58170Sstevel@tonic-gate 	if ((rvp = VTOP(vp)->pr_realvp) != NULL) {
58180Sstevel@tonic-gate 		vp = rvp;
58195331Samw 		if (VOP_REALVP(vp, &rvp, ct) == 0)
58200Sstevel@tonic-gate 			vp = rvp;
58210Sstevel@tonic-gate 	}
58220Sstevel@tonic-gate 
58230Sstevel@tonic-gate 	*vpp = vp;
58240Sstevel@tonic-gate 	return (0);
58250Sstevel@tonic-gate }
58260Sstevel@tonic-gate 
58270Sstevel@tonic-gate /*
58280Sstevel@tonic-gate  * Return the answer requested to poll().
58290Sstevel@tonic-gate  * POLLIN, POLLRDNORM, and POLLOUT are recognized as in fs_poll().
58300Sstevel@tonic-gate  * In addition, these have special meaning for /proc files:
58310Sstevel@tonic-gate  *	POLLPRI		process or lwp stopped on an event of interest
58320Sstevel@tonic-gate  *	POLLERR		/proc file descriptor is invalid
58330Sstevel@tonic-gate  *	POLLHUP		process or lwp has terminated
58340Sstevel@tonic-gate  */
58355331Samw /*ARGSUSED5*/
58360Sstevel@tonic-gate static int
prpoll(vnode_t * vp,short events,int anyyet,short * reventsp,pollhead_t ** phpp,caller_context_t * ct)58370Sstevel@tonic-gate prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
58385331Samw 	pollhead_t **phpp, caller_context_t *ct)
58390Sstevel@tonic-gate {
58400Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
58410Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
58420Sstevel@tonic-gate 	pollhead_t *php = &pcp->prc_pollhead;
58430Sstevel@tonic-gate 	proc_t *p;
58440Sstevel@tonic-gate 	short revents;
58450Sstevel@tonic-gate 	int error;
58460Sstevel@tonic-gate 	int lockstate;
58470Sstevel@tonic-gate 
58480Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
58490Sstevel@tonic-gate 
58500Sstevel@tonic-gate 	/*
58510Sstevel@tonic-gate 	 * Support for old /proc interface.
58520Sstevel@tonic-gate 	 */
58530Sstevel@tonic-gate 	if (pnp->pr_pidfile != NULL) {
58540Sstevel@tonic-gate 		vp = pnp->pr_pidfile;
58550Sstevel@tonic-gate 		pnp = VTOP(vp);
58560Sstevel@tonic-gate 		ASSERT(pnp->pr_type == PR_PIDFILE);
58570Sstevel@tonic-gate 		ASSERT(pnp->pr_common == pcp);
58580Sstevel@tonic-gate 	}
58590Sstevel@tonic-gate 
58600Sstevel@tonic-gate 	*reventsp = revents = 0;
58610Sstevel@tonic-gate 	*phpp = (pollhead_t *)NULL;
58620Sstevel@tonic-gate 
58630Sstevel@tonic-gate 	if (vp->v_type == VDIR) {
58640Sstevel@tonic-gate 		*reventsp |= POLLNVAL;
58650Sstevel@tonic-gate 		return (0);
58660Sstevel@tonic-gate 	}
58670Sstevel@tonic-gate 
58680Sstevel@tonic-gate 	lockstate = pollunlock();	/* avoid deadlock with prnotify() */
58690Sstevel@tonic-gate 
58700Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0) {
58710Sstevel@tonic-gate 		pollrelock(lockstate);
58720Sstevel@tonic-gate 		switch (error) {
58730Sstevel@tonic-gate 		case ENOENT:		/* process or lwp died */
58740Sstevel@tonic-gate 			*reventsp = POLLHUP;
58750Sstevel@tonic-gate 			error = 0;
58760Sstevel@tonic-gate 			break;
58770Sstevel@tonic-gate 		case EAGAIN:		/* invalidated */
58780Sstevel@tonic-gate 			*reventsp = POLLERR;
58790Sstevel@tonic-gate 			error = 0;
58800Sstevel@tonic-gate 			break;
58810Sstevel@tonic-gate 		}
58820Sstevel@tonic-gate 		return (error);
58830Sstevel@tonic-gate 	}
58840Sstevel@tonic-gate 
58850Sstevel@tonic-gate 	/*
58860Sstevel@tonic-gate 	 * We have the process marked locked (P_PR_LOCK) and we are holding
58870Sstevel@tonic-gate 	 * its p->p_lock.  We want to unmark the process but retain
58880Sstevel@tonic-gate 	 * exclusive control w.r.t. other /proc controlling processes
58890Sstevel@tonic-gate 	 * before reacquiring the polling locks.
58900Sstevel@tonic-gate 	 *
58910Sstevel@tonic-gate 	 * prunmark() does this for us.  It unmarks the process
58920Sstevel@tonic-gate 	 * but retains p->p_lock so we still have exclusive control.
58930Sstevel@tonic-gate 	 * We will drop p->p_lock at the end to relinquish control.
58940Sstevel@tonic-gate 	 *
58950Sstevel@tonic-gate 	 * We cannot call prunlock() at the end to relinquish control
58960Sstevel@tonic-gate 	 * because prunlock(), like prunmark(), may drop and reacquire
58970Sstevel@tonic-gate 	 * p->p_lock and that would lead to a lock order violation
58980Sstevel@tonic-gate 	 * w.r.t. the polling locks we are about to reacquire.
58990Sstevel@tonic-gate 	 */
59000Sstevel@tonic-gate 	p = pcp->prc_proc;
59010Sstevel@tonic-gate 	ASSERT(p != NULL);
59020Sstevel@tonic-gate 	prunmark(p);
59030Sstevel@tonic-gate 
59040Sstevel@tonic-gate 	pollrelock(lockstate);		/* reacquire dropped poll locks */
59050Sstevel@tonic-gate 
59060Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
59070Sstevel@tonic-gate 		revents = POLLNVAL;
59080Sstevel@tonic-gate 	else {
59090Sstevel@tonic-gate 		short ev;
59100Sstevel@tonic-gate 
59110Sstevel@tonic-gate 		if ((ev = (events & (POLLIN|POLLRDNORM))) != 0)
59120Sstevel@tonic-gate 			revents |= ev;
59130Sstevel@tonic-gate 		/*
59140Sstevel@tonic-gate 		 * POLLWRNORM (same as POLLOUT) really should not be
59150Sstevel@tonic-gate 		 * used to indicate that the process or lwp stopped.
59160Sstevel@tonic-gate 		 * However, USL chose to use POLLWRNORM rather than
59170Sstevel@tonic-gate 		 * POLLPRI to indicate this, so we just accept either
59180Sstevel@tonic-gate 		 * requested event to indicate stopped.  (grr...)
59190Sstevel@tonic-gate 		 */
59200Sstevel@tonic-gate 		if ((ev = (events & (POLLPRI|POLLOUT|POLLWRNORM))) != 0) {
59210Sstevel@tonic-gate 			kthread_t *t;
59220Sstevel@tonic-gate 
59230Sstevel@tonic-gate 			if (pcp->prc_flags & PRC_LWP) {
59240Sstevel@tonic-gate 				t = pcp->prc_thread;
59250Sstevel@tonic-gate 				ASSERT(t != NULL);
59260Sstevel@tonic-gate 				thread_lock(t);
59270Sstevel@tonic-gate 			} else {
59280Sstevel@tonic-gate 				t = prchoose(p);	/* returns locked t */
59290Sstevel@tonic-gate 				ASSERT(t != NULL);
59300Sstevel@tonic-gate 			}
59310Sstevel@tonic-gate 
59320Sstevel@tonic-gate 			if (ISTOPPED(t) || VSTOPPED(t))
59330Sstevel@tonic-gate 				revents |= ev;
59340Sstevel@tonic-gate 			thread_unlock(t);
59350Sstevel@tonic-gate 		}
59360Sstevel@tonic-gate 	}
59370Sstevel@tonic-gate 
59380Sstevel@tonic-gate 	*reventsp = revents;
59390Sstevel@tonic-gate 	if (!anyyet && revents == 0) {
59400Sstevel@tonic-gate 		/*
59410Sstevel@tonic-gate 		 * Arrange to wake up the polling lwp when
59420Sstevel@tonic-gate 		 * the target process/lwp stops or terminates
59430Sstevel@tonic-gate 		 * or when the file descriptor becomes invalid.
59440Sstevel@tonic-gate 		 */
59450Sstevel@tonic-gate 		pcp->prc_flags |= PRC_POLL;
59460Sstevel@tonic-gate 		*phpp = php;
59470Sstevel@tonic-gate 	}
59480Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
59490Sstevel@tonic-gate 	return (0);
59500Sstevel@tonic-gate }
59510Sstevel@tonic-gate 
59520Sstevel@tonic-gate /* in prioctl.c */
59535331Samw extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
59545331Samw 	caller_context_t *);
59550Sstevel@tonic-gate 
59560Sstevel@tonic-gate /*
59570Sstevel@tonic-gate  * /proc vnode operations vector
59580Sstevel@tonic-gate  */
59590Sstevel@tonic-gate const fs_operation_def_t pr_vnodeops_template[] = {
59603898Srsb 	VOPNAME_OPEN,		{ .vop_open = propen },
59613898Srsb 	VOPNAME_CLOSE,		{ .vop_close = prclose },
59623898Srsb 	VOPNAME_READ,		{ .vop_read = prread },
59633898Srsb 	VOPNAME_WRITE,		{ .vop_write = prwrite },
59643898Srsb 	VOPNAME_IOCTL,		{ .vop_ioctl = prioctl },
59653898Srsb 	VOPNAME_GETATTR,	{ .vop_getattr = prgetattr },
59663898Srsb 	VOPNAME_ACCESS,		{ .vop_access = praccess },
59673898Srsb 	VOPNAME_LOOKUP,		{ .vop_lookup = prlookup },
59683898Srsb 	VOPNAME_CREATE,		{ .vop_create = prcreate },
59693898Srsb 	VOPNAME_READDIR,	{ .vop_readdir = prreaddir },
59703898Srsb 	VOPNAME_READLINK,	{ .vop_readlink = prreadlink },
59713898Srsb 	VOPNAME_FSYNC,		{ .vop_fsync = prfsync },
59723898Srsb 	VOPNAME_INACTIVE,	{ .vop_inactive = prinactive },
59733898Srsb 	VOPNAME_SEEK,		{ .vop_seek = prseek },
59743898Srsb 	VOPNAME_CMP,		{ .vop_cmp = prcmp },
59753898Srsb 	VOPNAME_FRLOCK,		{ .error = fs_error },
59763898Srsb 	VOPNAME_REALVP,		{ .vop_realvp = prrealvp },
59773898Srsb 	VOPNAME_POLL,		{ .vop_poll = prpoll },
59783898Srsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
59793898Srsb 	VOPNAME_SHRLOCK,	{ .error = fs_error },
59803898Srsb 	NULL,			NULL
59810Sstevel@tonic-gate };
5982