xref: /titanic_52/usr/src/uts/common/fs/proc/prvnops.c (revision dc32d872cbeb56532bcea030255db9cd79bac7da)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5870619e9Sfrankho  * Common Development and Distribution License (the "License").
6870619e9Sfrankho  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21eb9dbf0cSRoger A. Faulkner 
227c478bd9Sstevel@tonic-gate /*
23e24ad047SChristopher Baumbauer - Oracle America - San Diego United States  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24a5eb7107SBryan Cantrill  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984,	 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <sys/types.h>
317c478bd9Sstevel@tonic-gate #include <sys/param.h>
327c478bd9Sstevel@tonic-gate #include <sys/time.h>
337c478bd9Sstevel@tonic-gate #include <sys/cred.h>
347c478bd9Sstevel@tonic-gate #include <sys/policy.h>
357c478bd9Sstevel@tonic-gate #include <sys/debug.h>
367c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
377c478bd9Sstevel@tonic-gate #include <sys/errno.h>
387c478bd9Sstevel@tonic-gate #include <sys/file.h>
397c478bd9Sstevel@tonic-gate #include <sys/inline.h>
407c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
417c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
427c478bd9Sstevel@tonic-gate #include <sys/proc.h>
43eb9dbf0cSRoger A. Faulkner #include <sys/brand.h>
447c478bd9Sstevel@tonic-gate #include <sys/signal.h>
457c478bd9Sstevel@tonic-gate #include <sys/stat.h>
467c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
477c478bd9Sstevel@tonic-gate #include <sys/systm.h>
487c478bd9Sstevel@tonic-gate #include <sys/zone.h>
497c478bd9Sstevel@tonic-gate #include <sys/uio.h>
507c478bd9Sstevel@tonic-gate #include <sys/var.h>
517c478bd9Sstevel@tonic-gate #include <sys/mode.h>
527c478bd9Sstevel@tonic-gate #include <sys/poll.h>
537c478bd9Sstevel@tonic-gate #include <sys/user.h>
547c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
55aa59c4cbSrsb #include <sys/vfs_opreg.h>
567c478bd9Sstevel@tonic-gate #include <sys/gfs.h>
577c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
587c478bd9Sstevel@tonic-gate #include <sys/fault.h>
597c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
607c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
617c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
627c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
637c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h>
647c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
657c478bd9Sstevel@tonic-gate #include <sys/avl.h>
667c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
677c478bd9Sstevel@tonic-gate #include <vm/rm.h>
687c478bd9Sstevel@tonic-gate #include <vm/as.h>
697c478bd9Sstevel@tonic-gate #include <vm/seg.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
717c478bd9Sstevel@tonic-gate #include <vm/hat.h>
727c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
737c478bd9Sstevel@tonic-gate #if defined(__sparc)
747c478bd9Sstevel@tonic-gate #include <sys/regset.h>
757c478bd9Sstevel@tonic-gate #endif
767c478bd9Sstevel@tonic-gate #if defined(__x86)
777c478bd9Sstevel@tonic-gate #include <sys/sysi86.h>
787c478bd9Sstevel@tonic-gate #endif
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * Created by prinit.
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate vnodeops_t *prvnodeops;
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Directory characteristics (patterned after the s5 file system).
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate #define	PRROOTINO	2
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate #define	PRDIRSIZE	14
917c478bd9Sstevel@tonic-gate struct prdirect {
927c478bd9Sstevel@tonic-gate 	ushort_t	d_ino;
937c478bd9Sstevel@tonic-gate 	char		d_name[PRDIRSIZE];
947c478bd9Sstevel@tonic-gate };
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate #define	PRSDSIZE	(sizeof (struct prdirect))
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /*
997c478bd9Sstevel@tonic-gate  * Directory characteristics.
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate typedef struct prdirent {
1027c478bd9Sstevel@tonic-gate 	ino64_t		d_ino;		/* "inode number" of entry */
1037c478bd9Sstevel@tonic-gate 	off64_t		d_off;		/* offset of disk directory entry */
1047c478bd9Sstevel@tonic-gate 	unsigned short	d_reclen;	/* length of this record */
1057c478bd9Sstevel@tonic-gate 	char		d_name[14];	/* name of file */
1067c478bd9Sstevel@tonic-gate } prdirent_t;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /*
1097c478bd9Sstevel@tonic-gate  * Contents of a /proc/<pid> directory.
1107c478bd9Sstevel@tonic-gate  * Reuse d_ino field for the /proc file type.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate static prdirent_t piddir[] = {
1137c478bd9Sstevel@tonic-gate 	{ PR_PIDDIR,	 1 * sizeof (prdirent_t), sizeof (prdirent_t),
1147c478bd9Sstevel@tonic-gate 		"." },
1157c478bd9Sstevel@tonic-gate 	{ PR_PROCDIR,	 2 * sizeof (prdirent_t), sizeof (prdirent_t),
1167c478bd9Sstevel@tonic-gate 		".." },
1177c478bd9Sstevel@tonic-gate 	{ PR_AS,	 3 * sizeof (prdirent_t), sizeof (prdirent_t),
1187c478bd9Sstevel@tonic-gate 		"as" },
1197c478bd9Sstevel@tonic-gate 	{ PR_CTL,	 4 * sizeof (prdirent_t), sizeof (prdirent_t),
1207c478bd9Sstevel@tonic-gate 		"ctl" },
1217c478bd9Sstevel@tonic-gate 	{ PR_STATUS,	 5 * sizeof (prdirent_t), sizeof (prdirent_t),
1227c478bd9Sstevel@tonic-gate 		"status" },
1237c478bd9Sstevel@tonic-gate 	{ PR_LSTATUS,	 6 * sizeof (prdirent_t), sizeof (prdirent_t),
1247c478bd9Sstevel@tonic-gate 		"lstatus" },
1257c478bd9Sstevel@tonic-gate 	{ PR_PSINFO,	 7 * sizeof (prdirent_t), sizeof (prdirent_t),
1267c478bd9Sstevel@tonic-gate 		"psinfo" },
1277c478bd9Sstevel@tonic-gate 	{ PR_LPSINFO,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
1287c478bd9Sstevel@tonic-gate 		"lpsinfo" },
1297c478bd9Sstevel@tonic-gate 	{ PR_MAP,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
1307c478bd9Sstevel@tonic-gate 		"map" },
1317c478bd9Sstevel@tonic-gate 	{ PR_RMAP,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
1327c478bd9Sstevel@tonic-gate 		"rmap" },
1337c478bd9Sstevel@tonic-gate 	{ PR_XMAP,	11 * sizeof (prdirent_t), sizeof (prdirent_t),
1347c478bd9Sstevel@tonic-gate 		"xmap" },
1357c478bd9Sstevel@tonic-gate 	{ PR_CRED,	12 * sizeof (prdirent_t), sizeof (prdirent_t),
1367c478bd9Sstevel@tonic-gate 		"cred" },
1377c478bd9Sstevel@tonic-gate 	{ PR_SIGACT,	13 * sizeof (prdirent_t), sizeof (prdirent_t),
1387c478bd9Sstevel@tonic-gate 		"sigact" },
1397c478bd9Sstevel@tonic-gate 	{ PR_AUXV,	14 * sizeof (prdirent_t), sizeof (prdirent_t),
1407c478bd9Sstevel@tonic-gate 		"auxv" },
1417c478bd9Sstevel@tonic-gate 	{ PR_USAGE,	15 * sizeof (prdirent_t), sizeof (prdirent_t),
1427c478bd9Sstevel@tonic-gate 		"usage" },
1437c478bd9Sstevel@tonic-gate 	{ PR_LUSAGE,	16 * sizeof (prdirent_t), sizeof (prdirent_t),
1447c478bd9Sstevel@tonic-gate 		"lusage" },
1457c478bd9Sstevel@tonic-gate 	{ PR_PAGEDATA,	17 * sizeof (prdirent_t), sizeof (prdirent_t),
1467c478bd9Sstevel@tonic-gate 		"pagedata" },
1477c478bd9Sstevel@tonic-gate 	{ PR_WATCH,	18 * sizeof (prdirent_t), sizeof (prdirent_t),
1487c478bd9Sstevel@tonic-gate 		"watch" },
1497c478bd9Sstevel@tonic-gate 	{ PR_CURDIR,	19 * sizeof (prdirent_t), sizeof (prdirent_t),
1507c478bd9Sstevel@tonic-gate 		"cwd" },
1517c478bd9Sstevel@tonic-gate 	{ PR_ROOTDIR,	20 * sizeof (prdirent_t), sizeof (prdirent_t),
1527c478bd9Sstevel@tonic-gate 		"root" },
1537c478bd9Sstevel@tonic-gate 	{ PR_FDDIR,	21 * sizeof (prdirent_t), sizeof (prdirent_t),
1547c478bd9Sstevel@tonic-gate 		"fd" },
1557c478bd9Sstevel@tonic-gate 	{ PR_OBJECTDIR,	22 * sizeof (prdirent_t), sizeof (prdirent_t),
1567c478bd9Sstevel@tonic-gate 		"object" },
1577c478bd9Sstevel@tonic-gate 	{ PR_LWPDIR,	23 * sizeof (prdirent_t), sizeof (prdirent_t),
1587c478bd9Sstevel@tonic-gate 		"lwp" },
1597c478bd9Sstevel@tonic-gate 	{ PR_PRIV,	24 * sizeof (prdirent_t), sizeof (prdirent_t),
1607c478bd9Sstevel@tonic-gate 		"priv" },
1617c478bd9Sstevel@tonic-gate 	{ PR_PATHDIR,	25 * sizeof (prdirent_t), sizeof (prdirent_t),
1627c478bd9Sstevel@tonic-gate 		"path" },
1637c478bd9Sstevel@tonic-gate 	{ PR_CTDIR,	26 * sizeof (prdirent_t), sizeof (prdirent_t),
1647c478bd9Sstevel@tonic-gate 		"contracts" },
1657c478bd9Sstevel@tonic-gate #if defined(__x86)
1667c478bd9Sstevel@tonic-gate 	{ PR_LDT,	27 * sizeof (prdirent_t), sizeof (prdirent_t),
1677c478bd9Sstevel@tonic-gate 		"ldt" },
1687c478bd9Sstevel@tonic-gate #endif
1697c478bd9Sstevel@tonic-gate };
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate #define	NPIDDIRFILES	(sizeof (piddir) / sizeof (piddir[0]) - 2)
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate  * Contents of a /proc/<pid>/lwp/<lwpid> directory.
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate static prdirent_t lwpiddir[] = {
1777c478bd9Sstevel@tonic-gate 	{ PR_LWPIDDIR,	 1 * sizeof (prdirent_t), sizeof (prdirent_t),
1787c478bd9Sstevel@tonic-gate 		"." },
1797c478bd9Sstevel@tonic-gate 	{ PR_LWPDIR,	 2 * sizeof (prdirent_t), sizeof (prdirent_t),
1807c478bd9Sstevel@tonic-gate 		".." },
1817c478bd9Sstevel@tonic-gate 	{ PR_LWPCTL,	 3 * sizeof (prdirent_t), sizeof (prdirent_t),
1827c478bd9Sstevel@tonic-gate 		"lwpctl" },
1837c478bd9Sstevel@tonic-gate 	{ PR_LWPSTATUS,	 4 * sizeof (prdirent_t), sizeof (prdirent_t),
1847c478bd9Sstevel@tonic-gate 		"lwpstatus" },
1857c478bd9Sstevel@tonic-gate 	{ PR_LWPSINFO,	 5 * sizeof (prdirent_t), sizeof (prdirent_t),
1867c478bd9Sstevel@tonic-gate 		"lwpsinfo" },
1877c478bd9Sstevel@tonic-gate 	{ PR_LWPUSAGE,	 6 * sizeof (prdirent_t), sizeof (prdirent_t),
1887c478bd9Sstevel@tonic-gate 		"lwpusage" },
1897c478bd9Sstevel@tonic-gate 	{ PR_XREGS,	 7 * sizeof (prdirent_t), sizeof (prdirent_t),
1907c478bd9Sstevel@tonic-gate 		"xregs" },
1917c478bd9Sstevel@tonic-gate 	{ PR_TMPLDIR,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
1927c478bd9Sstevel@tonic-gate 		"templates" },
193f971a346SBryan Cantrill 	{ PR_SPYMASTER,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
194f971a346SBryan Cantrill 		"spymaster" },
1957c478bd9Sstevel@tonic-gate #if defined(__sparc)
196f971a346SBryan Cantrill 	{ PR_GWINDOWS,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
1977c478bd9Sstevel@tonic-gate 		"gwindows" },
198f971a346SBryan Cantrill 	{ PR_ASRS,	11 * sizeof (prdirent_t), sizeof (prdirent_t),
1997c478bd9Sstevel@tonic-gate 		"asrs" },
2007c478bd9Sstevel@tonic-gate #endif
2017c478bd9Sstevel@tonic-gate };
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate #define	NLWPIDDIRFILES	(sizeof (lwpiddir) / sizeof (lwpiddir[0]) - 2)
2047c478bd9Sstevel@tonic-gate 
2057c478bd9Sstevel@tonic-gate /*
2067c478bd9Sstevel@tonic-gate  * Span of entries in the array files (lstatus, lpsinfo, lusage).
2077c478bd9Sstevel@tonic-gate  * We make the span larger than the size of the structure on purpose,
2087c478bd9Sstevel@tonic-gate  * to make sure that programs cannot use the structure size by mistake.
2097c478bd9Sstevel@tonic-gate  * Align _ILP32 structures at 8 bytes, _LP64 structures at 16 bytes.
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate #ifdef _LP64
2127c478bd9Sstevel@tonic-gate #define	LSPAN(type)	(round16(sizeof (type)) + 16)
2137c478bd9Sstevel@tonic-gate #define	LSPAN32(type)	(round8(sizeof (type)) + 8)
2147c478bd9Sstevel@tonic-gate #else
2157c478bd9Sstevel@tonic-gate #define	LSPAN(type)	(round8(sizeof (type)) + 8)
2167c478bd9Sstevel@tonic-gate #endif
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate static void rebuild_objdir(struct as *);
2197c478bd9Sstevel@tonic-gate static void prfreecommon(prcommon_t *);
220da6c28aaSamw static int praccess(vnode_t *, int, int, cred_t *, caller_context_t *);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate static int
223da6c28aaSamw propen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
2247c478bd9Sstevel@tonic-gate {
2257c478bd9Sstevel@tonic-gate 	vnode_t *vp = *vpp;
2267c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
2277c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_pcommon;
2287c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
2297c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
2307c478bd9Sstevel@tonic-gate 	vtype_t vtype;
2317c478bd9Sstevel@tonic-gate 	proc_t *p;
2327c478bd9Sstevel@tonic-gate 	int error = 0;
2337c478bd9Sstevel@tonic-gate 	prnode_t *npnp = NULL;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * Nothing to do for the /proc directory itself.
2377c478bd9Sstevel@tonic-gate 	 */
2387c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR)
2397c478bd9Sstevel@tonic-gate 		return (0);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	/*
2427c478bd9Sstevel@tonic-gate 	 * If we are opening an underlying mapped object, reject opens
2437c478bd9Sstevel@tonic-gate 	 * for writing regardless of the objects's access modes.
2447c478bd9Sstevel@tonic-gate 	 * If we are opening a file in the /proc/pid/fd directory,
2457c478bd9Sstevel@tonic-gate 	 * reject the open for any but a regular file or directory.
2467c478bd9Sstevel@tonic-gate 	 * Just do it if we are opening the current or root directory.
2477c478bd9Sstevel@tonic-gate 	 */
2487c478bd9Sstevel@tonic-gate 	switch (type) {
2497c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
2507c478bd9Sstevel@tonic-gate 	case PR_FD:
2517c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
2527c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
2537c478bd9Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
2547c478bd9Sstevel@tonic-gate 		vtype = rvp->v_type;
2557c478bd9Sstevel@tonic-gate 		if ((type == PR_OBJECT && (flag & FWRITE)) ||
2567c478bd9Sstevel@tonic-gate 		    (type == PR_FD && vtype != VREG && vtype != VDIR))
2577c478bd9Sstevel@tonic-gate 			error = EACCES;
2587c478bd9Sstevel@tonic-gate 		else {
2597c478bd9Sstevel@tonic-gate 			/*
2607c478bd9Sstevel@tonic-gate 			 * Need to hold rvp since VOP_OPEN() may release it.
2617c478bd9Sstevel@tonic-gate 			 */
2627c478bd9Sstevel@tonic-gate 			VN_HOLD(rvp);
263da6c28aaSamw 			error = VOP_OPEN(&rvp, flag, cr, ct);
2647c478bd9Sstevel@tonic-gate 			if (error) {
2657c478bd9Sstevel@tonic-gate 				VN_RELE(rvp);
2667c478bd9Sstevel@tonic-gate 			} else {
2677c478bd9Sstevel@tonic-gate 				*vpp = rvp;
2687c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
2697c478bd9Sstevel@tonic-gate 			}
2707c478bd9Sstevel@tonic-gate 		}
2717c478bd9Sstevel@tonic-gate 		return (error);
2727c478bd9Sstevel@tonic-gate 	default:
2737c478bd9Sstevel@tonic-gate 		break;
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	/*
2777c478bd9Sstevel@tonic-gate 	 * If we are opening the pagedata file, allocate a prnode now
2787c478bd9Sstevel@tonic-gate 	 * to avoid calling kmem_alloc() while holding p->p_lock.
2797c478bd9Sstevel@tonic-gate 	 */
2807c478bd9Sstevel@tonic-gate 	if (type == PR_PAGEDATA || type == PR_OPAGEDATA)
2817c478bd9Sstevel@tonic-gate 		npnp = prgetnode(vp, type);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/*
2847c478bd9Sstevel@tonic-gate 	 * If the process exists, lock it now.
2857c478bd9Sstevel@tonic-gate 	 * Otherwise we have a race condition with prclose().
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
2887c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
2897c478bd9Sstevel@tonic-gate 	if (p == NULL) {
2907c478bd9Sstevel@tonic-gate 		if (npnp != NULL)
2917c478bd9Sstevel@tonic-gate 			prfreenode(npnp);
2927c478bd9Sstevel@tonic-gate 		return (ENOENT);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc);
2957c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/*
2987c478bd9Sstevel@tonic-gate 	 * Maintain a count of opens for write.  Allow exactly one
2997c478bd9Sstevel@tonic-gate 	 * O_WRITE|O_EXCL request and fail subsequent ones.
3007c478bd9Sstevel@tonic-gate 	 * Don't fail opens of old (bletch!) /proc lwp files.
3017c478bd9Sstevel@tonic-gate 	 * Special case for open by the process itself:
3027c478bd9Sstevel@tonic-gate 	 * Always allow the open by self and discount this
3037c478bd9Sstevel@tonic-gate 	 * open for other opens for writing.
3047c478bd9Sstevel@tonic-gate 	 */
3057c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
3067c478bd9Sstevel@tonic-gate 		if (p == curproc) {
3077c478bd9Sstevel@tonic-gate 			pcp->prc_selfopens++;
3087c478bd9Sstevel@tonic-gate 			pnp->pr_flags |= PR_ISSELF;
3097c478bd9Sstevel@tonic-gate 		} else if (type == PR_LWPIDFILE) {
3107c478bd9Sstevel@tonic-gate 			/* EMPTY */;
3117c478bd9Sstevel@tonic-gate 		} else if (flag & FEXCL) {
3127c478bd9Sstevel@tonic-gate 			if (pcp->prc_writers > pcp->prc_selfopens) {
3137c478bd9Sstevel@tonic-gate 				error = EBUSY;
3147c478bd9Sstevel@tonic-gate 				goto out;
3157c478bd9Sstevel@tonic-gate 			}
3167c478bd9Sstevel@tonic-gate 			/* semantic for old /proc interface */
3177c478bd9Sstevel@tonic-gate 			if (type == PR_PIDDIR)
3187c478bd9Sstevel@tonic-gate 				pcp->prc_flags |= PRC_EXCL;
3197c478bd9Sstevel@tonic-gate 		} else if (pcp->prc_flags & PRC_EXCL) {
3207c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_writers > pcp->prc_selfopens);
3217c478bd9Sstevel@tonic-gate 			error = secpolicy_proc_excl_open(cr);
3227c478bd9Sstevel@tonic-gate 			if (error)
3237c478bd9Sstevel@tonic-gate 				goto out;
3247c478bd9Sstevel@tonic-gate 		}
3257c478bd9Sstevel@tonic-gate 		pcp->prc_writers++;
3267c478bd9Sstevel@tonic-gate 		/*
3277c478bd9Sstevel@tonic-gate 		 * The vnode may have become invalid between the
3287c478bd9Sstevel@tonic-gate 		 * VOP_LOOKUP() of the /proc vnode and the VOP_OPEN().
3297c478bd9Sstevel@tonic-gate 		 * If so, do now what prinvalidate() should have done.
3307c478bd9Sstevel@tonic-gate 		 */
3317c478bd9Sstevel@tonic-gate 		if ((pnp->pr_flags & PR_INVAL) ||
3327c478bd9Sstevel@tonic-gate 		    (type == PR_PIDDIR &&
3337c478bd9Sstevel@tonic-gate 		    (VTOP(pnp->pr_pidfile)->pr_flags & PR_INVAL))) {
3347c478bd9Sstevel@tonic-gate 			if (p != curproc)
3357c478bd9Sstevel@tonic-gate 				pcp->prc_selfopens++;
3367c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens <= pcp->prc_writers);
3377c478bd9Sstevel@tonic-gate 			if (pcp->prc_selfopens == pcp->prc_writers)
3387c478bd9Sstevel@tonic-gate 				pcp->prc_flags &= ~PRC_EXCL;
3397c478bd9Sstevel@tonic-gate 		}
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	/*
343d1b18d1aSBryan Cantrill 	 * If this is a large file open, indicate that in our flags -- some
344d1b18d1aSBryan Cantrill 	 * procfs structures are not off_t-neutral (e.g., priovec_t), and
345d1b18d1aSBryan Cantrill 	 * the open will need to be differentiated where 32-bit processes
346d1b18d1aSBryan Cantrill 	 * pass these structures across the user/kernel boundary.
347d1b18d1aSBryan Cantrill 	 */
348d1b18d1aSBryan Cantrill 	if (flag & FOFFMAX)
349d1b18d1aSBryan Cantrill 		pnp->pr_flags |= PR_OFFMAX;
350d1b18d1aSBryan Cantrill 
351d1b18d1aSBryan Cantrill 	/*
3527c478bd9Sstevel@tonic-gate 	 * Do file-specific things.
3537c478bd9Sstevel@tonic-gate 	 */
3547c478bd9Sstevel@tonic-gate 	switch (type) {
3557c478bd9Sstevel@tonic-gate 	default:
3567c478bd9Sstevel@tonic-gate 		break;
3577c478bd9Sstevel@tonic-gate 	case PR_PAGEDATA:
3587c478bd9Sstevel@tonic-gate 	case PR_OPAGEDATA:
3597c478bd9Sstevel@tonic-gate 		/*
3607c478bd9Sstevel@tonic-gate 		 * Enable data collection for page data file;
3617c478bd9Sstevel@tonic-gate 		 * get unique id from the hat layer.
3627c478bd9Sstevel@tonic-gate 		 */
3637c478bd9Sstevel@tonic-gate 		{
3647c478bd9Sstevel@tonic-gate 			int id;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 			/*
3677c478bd9Sstevel@tonic-gate 			 * Drop p->p_lock to call hat_startstat()
3687c478bd9Sstevel@tonic-gate 			 */
3697c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3707c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SSYS) || p->p_as == &kas ||
3717c478bd9Sstevel@tonic-gate 			    (id = hat_startstat(p->p_as)) == -1) {
3727c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3737c478bd9Sstevel@tonic-gate 				error = ENOMEM;
3747c478bd9Sstevel@tonic-gate 			} else if (pnp->pr_hatid == 0) {
3757c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3767c478bd9Sstevel@tonic-gate 				pnp->pr_hatid = (uint_t)id;
3777c478bd9Sstevel@tonic-gate 			} else {
3787c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3797c478bd9Sstevel@tonic-gate 				/*
3807c478bd9Sstevel@tonic-gate 				 * Use our newly allocated prnode.
3817c478bd9Sstevel@tonic-gate 				 */
3827c478bd9Sstevel@tonic-gate 				npnp->pr_hatid = (uint_t)id;
3837c478bd9Sstevel@tonic-gate 				/*
3847c478bd9Sstevel@tonic-gate 				 * prgetnode() initialized most of the prnode.
3857c478bd9Sstevel@tonic-gate 				 * Duplicate the remainder.
3867c478bd9Sstevel@tonic-gate 				 */
3877c478bd9Sstevel@tonic-gate 				npnp->pr_ino = pnp->pr_ino;
3887c478bd9Sstevel@tonic-gate 				npnp->pr_common = pnp->pr_common;
3897c478bd9Sstevel@tonic-gate 				npnp->pr_pcommon = pnp->pr_pcommon;
3907c478bd9Sstevel@tonic-gate 				npnp->pr_parent = pnp->pr_parent;
3917c478bd9Sstevel@tonic-gate 				VN_HOLD(npnp->pr_parent);
3927c478bd9Sstevel@tonic-gate 				npnp->pr_index = pnp->pr_index;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 				npnp->pr_next = p->p_plist;
3957c478bd9Sstevel@tonic-gate 				p->p_plist = PTOV(npnp);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 				VN_RELE(PTOV(pnp));
3987c478bd9Sstevel@tonic-gate 				pnp = npnp;
3997c478bd9Sstevel@tonic-gate 				npnp = NULL;
4007c478bd9Sstevel@tonic-gate 				*vpp = PTOV(pnp);
4017c478bd9Sstevel@tonic-gate 			}
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 		break;
4047c478bd9Sstevel@tonic-gate 	}
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate out:
4077c478bd9Sstevel@tonic-gate 	prunlock(pnp);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (npnp != NULL)
4107c478bd9Sstevel@tonic-gate 		prfreenode(npnp);
4117c478bd9Sstevel@tonic-gate 	return (error);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /* ARGSUSED */
4157c478bd9Sstevel@tonic-gate static int
416da6c28aaSamw prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
417da6c28aaSamw 	caller_context_t *ct)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
4207c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_pcommon;
4217c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
4227c478bd9Sstevel@tonic-gate 	proc_t *p;
4237c478bd9Sstevel@tonic-gate 	kthread_t *t;
4247c478bd9Sstevel@tonic-gate 	user_t *up;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/*
4277c478bd9Sstevel@tonic-gate 	 * Nothing to do for the /proc directory itself.
4287c478bd9Sstevel@tonic-gate 	 */
4297c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR)
4307c478bd9Sstevel@tonic-gate 		return (0);
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	ASSERT(type != PR_OBJECT && type != PR_FD &&
4337c478bd9Sstevel@tonic-gate 	    type != PR_CURDIR && type != PR_ROOTDIR);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	/*
4367c478bd9Sstevel@tonic-gate 	 * If the process exists, lock it now.
4377c478bd9Sstevel@tonic-gate 	 * Otherwise we have a race condition with propen().
4387c478bd9Sstevel@tonic-gate 	 * Hold pr_pidlock across the reference to prc_selfopens,
4397c478bd9Sstevel@tonic-gate 	 * and prc_writers in case there is no process anymore,
4407c478bd9Sstevel@tonic-gate 	 * to cover the case of concurrent calls to prclose()
4417c478bd9Sstevel@tonic-gate 	 * after the process has been reaped by freeproc().
4427c478bd9Sstevel@tonic-gate 	 */
4437c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/*
4467c478bd9Sstevel@tonic-gate 	 * There is nothing more to do until the last close of
4477c478bd9Sstevel@tonic-gate 	 * the file table entry except to clear the pr_owner
4487c478bd9Sstevel@tonic-gate 	 * field of the prnode and notify any waiters
4497c478bd9Sstevel@tonic-gate 	 * (their file descriptor may have just been closed).
4507c478bd9Sstevel@tonic-gate 	 */
4517c478bd9Sstevel@tonic-gate 	if (count > 1) {
4527c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
4537c478bd9Sstevel@tonic-gate 		if (pnp->pr_owner == curproc && !fisopen(vp))
4547c478bd9Sstevel@tonic-gate 			pnp->pr_owner = NULL;
4557c478bd9Sstevel@tonic-gate 		if (p != NULL) {
4567c478bd9Sstevel@tonic-gate 			prnotify(vp);
4577c478bd9Sstevel@tonic-gate 			prunlock(pnp);
4587c478bd9Sstevel@tonic-gate 		}
4597c478bd9Sstevel@tonic-gate 		return (0);
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	/*
4637c478bd9Sstevel@tonic-gate 	 * Decrement the count of self-opens for writing.
4647c478bd9Sstevel@tonic-gate 	 * Decrement the total count of opens for writing.
4657c478bd9Sstevel@tonic-gate 	 * Cancel exclusive opens when only self-opens remain.
4667c478bd9Sstevel@tonic-gate 	 */
4677c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
4687c478bd9Sstevel@tonic-gate 		/*
4697c478bd9Sstevel@tonic-gate 		 * prc_selfopens also contains the count of
4707c478bd9Sstevel@tonic-gate 		 * invalid writers.  See prinvalidate().
4717c478bd9Sstevel@tonic-gate 		 */
4727c478bd9Sstevel@tonic-gate 		if ((pnp->pr_flags & (PR_ISSELF|PR_INVAL)) ||
4737c478bd9Sstevel@tonic-gate 		    (type == PR_PIDDIR &&
4747c478bd9Sstevel@tonic-gate 		    (VTOP(pnp->pr_pidfile)->pr_flags & PR_INVAL))) {
4757c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens != 0);
4767c478bd9Sstevel@tonic-gate 			--pcp->prc_selfopens;
4777c478bd9Sstevel@tonic-gate 		}
4787c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_writers != 0);
4797c478bd9Sstevel@tonic-gate 		if (--pcp->prc_writers == pcp->prc_selfopens)
4807c478bd9Sstevel@tonic-gate 			pcp->prc_flags &= ~PRC_EXCL;
4817c478bd9Sstevel@tonic-gate 	}
4827c478bd9Sstevel@tonic-gate 	ASSERT(pcp->prc_writers >= pcp->prc_selfopens);
4837c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
4847c478bd9Sstevel@tonic-gate 	if (pnp->pr_owner == curproc && !fisopen(vp))
4857c478bd9Sstevel@tonic-gate 		pnp->pr_owner = NULL;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 	/*
4887c478bd9Sstevel@tonic-gate 	 * If there is no process, there is nothing more to do.
4897c478bd9Sstevel@tonic-gate 	 */
4907c478bd9Sstevel@tonic-gate 	if (p == NULL)
4917c478bd9Sstevel@tonic-gate 		return (0);
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc);
4947c478bd9Sstevel@tonic-gate 	prnotify(vp);	/* notify waiters */
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	/*
4977c478bd9Sstevel@tonic-gate 	 * Do file-specific things.
4987c478bd9Sstevel@tonic-gate 	 */
4997c478bd9Sstevel@tonic-gate 	switch (type) {
5007c478bd9Sstevel@tonic-gate 	default:
5017c478bd9Sstevel@tonic-gate 		break;
5027c478bd9Sstevel@tonic-gate 	case PR_PAGEDATA:
5037c478bd9Sstevel@tonic-gate 	case PR_OPAGEDATA:
5047c478bd9Sstevel@tonic-gate 		/*
5057c478bd9Sstevel@tonic-gate 		 * This is a page data file.
5067c478bd9Sstevel@tonic-gate 		 * Free the hat level statistics.
5077c478bd9Sstevel@tonic-gate 		 * Drop p->p_lock before calling hat_freestat().
5087c478bd9Sstevel@tonic-gate 		 */
5097c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
5107c478bd9Sstevel@tonic-gate 		if (p->p_as != &kas && pnp->pr_hatid != 0)
5117c478bd9Sstevel@tonic-gate 			hat_freestat(p->p_as, pnp->pr_hatid);
5127c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
5137c478bd9Sstevel@tonic-gate 		pnp->pr_hatid = 0;
5147c478bd9Sstevel@tonic-gate 		break;
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	/*
5187c478bd9Sstevel@tonic-gate 	 * On last close of all writable file descriptors,
5197c478bd9Sstevel@tonic-gate 	 * perform run-on-last-close and/or kill-on-last-close logic.
5207c478bd9Sstevel@tonic-gate 	 * Can't do this is the /proc agent lwp still exists.
5217c478bd9Sstevel@tonic-gate 	 */
5227c478bd9Sstevel@tonic-gate 	if (pcp->prc_writers == 0 &&
5237c478bd9Sstevel@tonic-gate 	    p->p_agenttp == NULL &&
5247c478bd9Sstevel@tonic-gate 	    !(pcp->prc_flags & PRC_DESTROY) &&
5257c478bd9Sstevel@tonic-gate 	    p->p_stat != SZOMB &&
5267c478bd9Sstevel@tonic-gate 	    (p->p_proc_flag & (P_PR_RUNLCL|P_PR_KILLCL))) {
5277c478bd9Sstevel@tonic-gate 		int killproc;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 		/*
5307c478bd9Sstevel@tonic-gate 		 * Cancel any watchpoints currently in effect.
5317c478bd9Sstevel@tonic-gate 		 * The process might disappear during this operation.
5327c478bd9Sstevel@tonic-gate 		 */
5337c478bd9Sstevel@tonic-gate 		if (pr_cancel_watch(pnp) == NULL)
5347c478bd9Sstevel@tonic-gate 			return (0);
5357c478bd9Sstevel@tonic-gate 		/*
5367c478bd9Sstevel@tonic-gate 		 * If any tracing flags are set, clear them.
5377c478bd9Sstevel@tonic-gate 		 */
5387c478bd9Sstevel@tonic-gate 		if (p->p_proc_flag & P_PR_TRACE) {
5397c478bd9Sstevel@tonic-gate 			up = PTOU(p);
5407c478bd9Sstevel@tonic-gate 			premptyset(&up->u_entrymask);
5417c478bd9Sstevel@tonic-gate 			premptyset(&up->u_exitmask);
5427c478bd9Sstevel@tonic-gate 			up->u_systrap = 0;
5437c478bd9Sstevel@tonic-gate 		}
5447c478bd9Sstevel@tonic-gate 		premptyset(&p->p_sigmask);
5457c478bd9Sstevel@tonic-gate 		premptyset(&p->p_fltmask);
5467c478bd9Sstevel@tonic-gate 		killproc = (p->p_proc_flag & P_PR_KILLCL);
5477c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~(P_PR_RUNLCL|P_PR_KILLCL|P_PR_TRACE);
5487c478bd9Sstevel@tonic-gate 		/*
5497c478bd9Sstevel@tonic-gate 		 * Cancel any outstanding single-step requests.
5507c478bd9Sstevel@tonic-gate 		 */
5517c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
5527c478bd9Sstevel@tonic-gate 			/*
5537c478bd9Sstevel@tonic-gate 			 * Drop p_lock because prnostep() touches the stack.
5547c478bd9Sstevel@tonic-gate 			 * The loop is safe because the process is P_PR_LOCK'd.
5557c478bd9Sstevel@tonic-gate 			 */
5567c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
5577c478bd9Sstevel@tonic-gate 			do {
5587c478bd9Sstevel@tonic-gate 				prnostep(ttolwp(t));
5597c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
5607c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 		/*
5637c478bd9Sstevel@tonic-gate 		 * Set runnable all lwps stopped by /proc.
5647c478bd9Sstevel@tonic-gate 		 */
5657c478bd9Sstevel@tonic-gate 		if (killproc)
5667c478bd9Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGKILL);
5677c478bd9Sstevel@tonic-gate 		else
5687c478bd9Sstevel@tonic-gate 			allsetrun(p);
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	prunlock(pnp);
5727c478bd9Sstevel@tonic-gate 	return (0);
5737c478bd9Sstevel@tonic-gate }
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate /*
5767c478bd9Sstevel@tonic-gate  * Array of read functions, indexed by /proc file type.
5777c478bd9Sstevel@tonic-gate  */
5787c478bd9Sstevel@tonic-gate static int pr_read_inval(), pr_read_as(), pr_read_status(),
5797c478bd9Sstevel@tonic-gate 	pr_read_lstatus(), pr_read_psinfo(), pr_read_lpsinfo(),
5807c478bd9Sstevel@tonic-gate 	pr_read_map(), pr_read_rmap(), pr_read_xmap(),
5817c478bd9Sstevel@tonic-gate 	pr_read_cred(), pr_read_sigact(), pr_read_auxv(),
5827c478bd9Sstevel@tonic-gate #if defined(__x86)
5837c478bd9Sstevel@tonic-gate 	pr_read_ldt(),
5847c478bd9Sstevel@tonic-gate #endif
5857c478bd9Sstevel@tonic-gate 	pr_read_usage(), pr_read_lusage(), pr_read_pagedata(),
5867c478bd9Sstevel@tonic-gate 	pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(),
5877c478bd9Sstevel@tonic-gate 	pr_read_lwpusage(), pr_read_xregs(), pr_read_priv(),
588f971a346SBryan Cantrill 	pr_read_spymaster(),
5897c478bd9Sstevel@tonic-gate #if defined(__sparc)
5907c478bd9Sstevel@tonic-gate 	pr_read_gwindows(), pr_read_asrs(),
5917c478bd9Sstevel@tonic-gate #endif
5927c478bd9Sstevel@tonic-gate 	pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata();
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate static int (*pr_read_function[PR_NFILES])() = {
5957c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc				*/
5967c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/self				*/
5977c478bd9Sstevel@tonic-gate 	pr_read_piddir,		/* /proc/<pid> (old /proc read())	*/
5987c478bd9Sstevel@tonic-gate 	pr_read_as,		/* /proc/<pid>/as			*/
5997c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/ctl			*/
6007c478bd9Sstevel@tonic-gate 	pr_read_status,		/* /proc/<pid>/status			*/
6017c478bd9Sstevel@tonic-gate 	pr_read_lstatus,	/* /proc/<pid>/lstatus			*/
6027c478bd9Sstevel@tonic-gate 	pr_read_psinfo,		/* /proc/<pid>/psinfo			*/
6037c478bd9Sstevel@tonic-gate 	pr_read_lpsinfo,	/* /proc/<pid>/lpsinfo			*/
6047c478bd9Sstevel@tonic-gate 	pr_read_map,		/* /proc/<pid>/map			*/
6057c478bd9Sstevel@tonic-gate 	pr_read_rmap,		/* /proc/<pid>/rmap			*/
6067c478bd9Sstevel@tonic-gate 	pr_read_xmap,		/* /proc/<pid>/xmap			*/
6077c478bd9Sstevel@tonic-gate 	pr_read_cred,		/* /proc/<pid>/cred			*/
6087c478bd9Sstevel@tonic-gate 	pr_read_sigact,		/* /proc/<pid>/sigact			*/
6097c478bd9Sstevel@tonic-gate 	pr_read_auxv,		/* /proc/<pid>/auxv			*/
6107c478bd9Sstevel@tonic-gate #if defined(__x86)
6117c478bd9Sstevel@tonic-gate 	pr_read_ldt,		/* /proc/<pid>/ldt			*/
6127c478bd9Sstevel@tonic-gate #endif
6137c478bd9Sstevel@tonic-gate 	pr_read_usage,		/* /proc/<pid>/usage			*/
6147c478bd9Sstevel@tonic-gate 	pr_read_lusage,		/* /proc/<pid>/lusage			*/
6157c478bd9Sstevel@tonic-gate 	pr_read_pagedata,	/* /proc/<pid>/pagedata			*/
6167c478bd9Sstevel@tonic-gate 	pr_read_watch,		/* /proc/<pid>/watch			*/
6177c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/cwd			*/
6187c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/root			*/
6197c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd			*/
6207c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd/nn			*/
6217c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object			*/
6227c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object/xxx		*/
6237c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp			*/
6247c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>		*/
6257c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
6267c478bd9Sstevel@tonic-gate 	pr_read_lwpstatus,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
6277c478bd9Sstevel@tonic-gate 	pr_read_lwpsinfo,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
6287c478bd9Sstevel@tonic-gate 	pr_read_lwpusage,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
6297c478bd9Sstevel@tonic-gate 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
6307c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
6317c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
632f971a346SBryan Cantrill 	pr_read_spymaster,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
6337c478bd9Sstevel@tonic-gate #if defined(__sparc)
6347c478bd9Sstevel@tonic-gate 	pr_read_gwindows,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
6357c478bd9Sstevel@tonic-gate 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
6367c478bd9Sstevel@tonic-gate #endif
6377c478bd9Sstevel@tonic-gate 	pr_read_priv,		/* /proc/<pid>/priv			*/
6387c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path			*/
6397c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path/xxx			*/
6407c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts		*/
6417c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts/<ctid>		*/
6427c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old process file			*/
6437c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old lwp file				*/
6447c478bd9Sstevel@tonic-gate 	pr_read_opagedata,	/* old pagedata file			*/
6457c478bd9Sstevel@tonic-gate };
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate /* ARGSUSED */
6487c478bd9Sstevel@tonic-gate static int
6497c478bd9Sstevel@tonic-gate pr_read_inval(prnode_t *pnp, uio_t *uiop)
6507c478bd9Sstevel@tonic-gate {
6517c478bd9Sstevel@tonic-gate 	/*
6527c478bd9Sstevel@tonic-gate 	 * No read() on any /proc directory, use getdents(2) instead.
6537c478bd9Sstevel@tonic-gate 	 * Cannot read a control file either.
6547c478bd9Sstevel@tonic-gate 	 * An underlying mapped object file cannot get here.
6557c478bd9Sstevel@tonic-gate 	 */
6567c478bd9Sstevel@tonic-gate 	return (EINVAL);
6577c478bd9Sstevel@tonic-gate }
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate static int
6607c478bd9Sstevel@tonic-gate pr_uioread(void *base, long count, uio_t *uiop)
6617c478bd9Sstevel@tonic-gate {
6627c478bd9Sstevel@tonic-gate 	int error = 0;
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	ASSERT(count >= 0);
6657c478bd9Sstevel@tonic-gate 	count -= uiop->uio_offset;
6667c478bd9Sstevel@tonic-gate 	if (count > 0 && uiop->uio_offset >= 0) {
6677c478bd9Sstevel@tonic-gate 		error = uiomove((char *)base + uiop->uio_offset,
6687c478bd9Sstevel@tonic-gate 		    count, UIO_READ, uiop);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	return (error);
6727c478bd9Sstevel@tonic-gate }
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate static int
6757c478bd9Sstevel@tonic-gate pr_read_as(prnode_t *pnp, uio_t *uiop)
6767c478bd9Sstevel@tonic-gate {
6777c478bd9Sstevel@tonic-gate 	int error;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AS);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
6827c478bd9Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
6837c478bd9Sstevel@tonic-gate 		struct as *as = p->p_as;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 		/*
6867c478bd9Sstevel@tonic-gate 		 * /proc I/O cannot be done to a system process.
6877c478bd9Sstevel@tonic-gate 		 * A 32-bit process cannot read a 64-bit process.
6887c478bd9Sstevel@tonic-gate 		 */
6897c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || as == &kas) {
6907c478bd9Sstevel@tonic-gate 			error = 0;
6917c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
6927c478bd9Sstevel@tonic-gate 		} else if (curproc->p_model == DATAMODEL_ILP32 &&
6937c478bd9Sstevel@tonic-gate 		    PROCESS_NOT_32BIT(p)) {
6947c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
6957c478bd9Sstevel@tonic-gate #endif
6967c478bd9Sstevel@tonic-gate 		} else {
6977c478bd9Sstevel@tonic-gate 			/*
6987c478bd9Sstevel@tonic-gate 			 * We don't hold p_lock over an i/o operation because
6997c478bd9Sstevel@tonic-gate 			 * that could lead to deadlock with the clock thread.
7007c478bd9Sstevel@tonic-gate 			 */
7017c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
7027c478bd9Sstevel@tonic-gate 			error = prusrio(p, UIO_READ, uiop, 0);
7037c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7067c478bd9Sstevel@tonic-gate 	}
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	return (error);
7097c478bd9Sstevel@tonic-gate }
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate static int
7127c478bd9Sstevel@tonic-gate pr_read_status(prnode_t *pnp, uio_t *uiop)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	pstatus_t *sp;
7157c478bd9Sstevel@tonic-gate 	int error;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_STATUS);
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	/*
7207c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the pstatus structure because
7217c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
7227c478bd9Sstevel@tonic-gate 	 */
7237c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
7247c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
725fa9e4066Sahrens 		prgetstatus(pnp->pr_common->prc_proc, sp, VTOZONE(PTOV(pnp)));
7267c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7277c478bd9Sstevel@tonic-gate 		error = pr_uioread(sp, sizeof (*sp), uiop);
7287c478bd9Sstevel@tonic-gate 	}
7297c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
7307c478bd9Sstevel@tonic-gate 	return (error);
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate static int
7347c478bd9Sstevel@tonic-gate pr_read_lstatus(prnode_t *pnp, uio_t *uiop)
7357c478bd9Sstevel@tonic-gate {
7367c478bd9Sstevel@tonic-gate 	proc_t *p;
7377c478bd9Sstevel@tonic-gate 	kthread_t *t;
7387c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
7397c478bd9Sstevel@tonic-gate 	size_t size;
7407c478bd9Sstevel@tonic-gate 	prheader_t *php;
7417c478bd9Sstevel@tonic-gate 	lwpstatus_t *sp;
7427c478bd9Sstevel@tonic-gate 	int error;
7437c478bd9Sstevel@tonic-gate 	int nlwp;
7447c478bd9Sstevel@tonic-gate 	int i;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LSTATUS);
7477c478bd9Sstevel@tonic-gate 
7487c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
7497c478bd9Sstevel@tonic-gate 		return (error);
7507c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
7517c478bd9Sstevel@tonic-gate 	nlwp = p->p_lwpcnt;
7527c478bd9Sstevel@tonic-gate 	size = sizeof (prheader_t) + nlwp * LSPAN(lwpstatus_t);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
7557c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
7567c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
7577c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
7587c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
7597c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
7627c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN(lwpstatus_t);
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 	sp = (lwpstatus_t *)(php + 1);
7657c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
7667c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
7677c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
7687c478bd9Sstevel@tonic-gate 			continue;
769fa9e4066Sahrens 		prgetlwpstatus(t, sp, VTOZONE(PTOV(pnp)));
7707c478bd9Sstevel@tonic-gate 		sp = (lwpstatus_t *)((caddr_t)sp + LSPAN(lwpstatus_t));
7717c478bd9Sstevel@tonic-gate 	}
7727c478bd9Sstevel@tonic-gate 	prunlock(pnp);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
7757c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
7767c478bd9Sstevel@tonic-gate 	return (error);
7777c478bd9Sstevel@tonic-gate }
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate static int
7807c478bd9Sstevel@tonic-gate pr_read_psinfo(prnode_t *pnp, uio_t *uiop)
7817c478bd9Sstevel@tonic-gate {
7827c478bd9Sstevel@tonic-gate 	psinfo_t psinfo;
7837c478bd9Sstevel@tonic-gate 	proc_t *p;
7847c478bd9Sstevel@tonic-gate 	int error = 0;
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PSINFO);
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
7907c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
7917c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
7927c478bd9Sstevel@tonic-gate 	 */
7937c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
7947c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
7957c478bd9Sstevel@tonic-gate 	if (p == NULL)
7967c478bd9Sstevel@tonic-gate 		error = ENOENT;
7977c478bd9Sstevel@tonic-gate 	else {
7987c478bd9Sstevel@tonic-gate 		ASSERT(p == pnp->pr_common->prc_proc);
7997c478bd9Sstevel@tonic-gate 		prgetpsinfo(p, &psinfo);
8007c478bd9Sstevel@tonic-gate 		prunlock(pnp);
8017c478bd9Sstevel@tonic-gate 		error = pr_uioread(&psinfo, sizeof (psinfo), uiop);
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate 	return (error);
8047c478bd9Sstevel@tonic-gate }
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate static int
8077c478bd9Sstevel@tonic-gate pr_read_lpsinfo(prnode_t *pnp, uio_t *uiop)
8087c478bd9Sstevel@tonic-gate {
8097c478bd9Sstevel@tonic-gate 	proc_t *p;
8107c478bd9Sstevel@tonic-gate 	kthread_t *t;
8117c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
8127c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
8137c478bd9Sstevel@tonic-gate 	size_t size;
8147c478bd9Sstevel@tonic-gate 	prheader_t *php;
8157c478bd9Sstevel@tonic-gate 	lwpsinfo_t *sp;
8167c478bd9Sstevel@tonic-gate 	int error;
8177c478bd9Sstevel@tonic-gate 	int nlwp;
8187c478bd9Sstevel@tonic-gate 	int i;
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LPSINFO);
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	/*
8237c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
8247c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
8257c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
8267c478bd9Sstevel@tonic-gate 	 */
8277c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
8287c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
8297c478bd9Sstevel@tonic-gate 	if (p == NULL)
8307c478bd9Sstevel@tonic-gate 		return (ENOENT);
8317c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
8327c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt + p->p_zombcnt) == 0) {
8337c478bd9Sstevel@tonic-gate 		prunlock(pnp);
8347c478bd9Sstevel@tonic-gate 		return (ENOENT);
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate 	size = sizeof (prheader_t) + nlwp * LSPAN(lwpsinfo_t);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
8397c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
8407c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
8417c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
8427c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
8437c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt + p->p_zombcnt);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
8467c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN(lwpsinfo_t);
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 	sp = (lwpsinfo_t *)(php + 1);
8497c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
8507c478bd9Sstevel@tonic-gate 		if ((lep = ldp->ld_entry) == NULL)
8517c478bd9Sstevel@tonic-gate 			continue;
8527c478bd9Sstevel@tonic-gate 		if ((t = lep->le_thread) != NULL)
8537c478bd9Sstevel@tonic-gate 			prgetlwpsinfo(t, sp);
8547c478bd9Sstevel@tonic-gate 		else {
8557c478bd9Sstevel@tonic-gate 			bzero(sp, sizeof (*sp));
8567c478bd9Sstevel@tonic-gate 			sp->pr_lwpid = lep->le_lwpid;
8577c478bd9Sstevel@tonic-gate 			sp->pr_state = SZOMB;
8587c478bd9Sstevel@tonic-gate 			sp->pr_sname = 'Z';
8597c478bd9Sstevel@tonic-gate 			sp->pr_start.tv_sec = lep->le_start;
8607c478bd9Sstevel@tonic-gate 			sp->pr_bindpro = PBIND_NONE;
8617c478bd9Sstevel@tonic-gate 			sp->pr_bindpset = PS_NONE;
8627c478bd9Sstevel@tonic-gate 		}
8637c478bd9Sstevel@tonic-gate 		sp = (lwpsinfo_t *)((caddr_t)sp + LSPAN(lwpsinfo_t));
8647c478bd9Sstevel@tonic-gate 	}
8657c478bd9Sstevel@tonic-gate 	prunlock(pnp);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
8687c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
8697c478bd9Sstevel@tonic-gate 	return (error);
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate static int
873870619e9Sfrankho pr_read_map_common(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	proc_t *p;
8767c478bd9Sstevel@tonic-gate 	struct as *as;
877870619e9Sfrankho 	list_t iolhead;
8787c478bd9Sstevel@tonic-gate 	int error;
8797c478bd9Sstevel@tonic-gate 
880e24ad047SChristopher Baumbauer - Oracle America - San Diego United States readmap_common:
8817c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
8827c478bd9Sstevel@tonic-gate 		return (error);
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
8857c478bd9Sstevel@tonic-gate 	as = p->p_as;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
8887c478bd9Sstevel@tonic-gate 		prunlock(pnp);
8897c478bd9Sstevel@tonic-gate 		return (0);
8907c478bd9Sstevel@tonic-gate 	}
8917c478bd9Sstevel@tonic-gate 
892*dc32d872SJosef 'Jeff' Sipek 	if (!AS_LOCK_TRYENTER(as, RW_WRITER)) {
893e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		prunlock(pnp);
894e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		delay(1);
895e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		goto readmap_common;
896e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 	}
8977c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
898e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 
899870619e9Sfrankho 	switch (type) {
900870619e9Sfrankho 	case PR_XMAP:
901870619e9Sfrankho 		error = prgetxmap(p, &iolhead);
902870619e9Sfrankho 		break;
903870619e9Sfrankho 	case PR_RMAP:
904870619e9Sfrankho 		error = prgetmap(p, 1, &iolhead);
905870619e9Sfrankho 		break;
906870619e9Sfrankho 	case PR_MAP:
907870619e9Sfrankho 		error = prgetmap(p, 0, &iolhead);
908870619e9Sfrankho 		break;
909870619e9Sfrankho 	}
910e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 
911*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
9127c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
9137c478bd9Sstevel@tonic-gate 	prunlock(pnp);
9147c478bd9Sstevel@tonic-gate 
915870619e9Sfrankho 	error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
916870619e9Sfrankho 
9177c478bd9Sstevel@tonic-gate 	return (error);
9187c478bd9Sstevel@tonic-gate }
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate static int
9217c478bd9Sstevel@tonic-gate pr_read_map(prnode_t *pnp, uio_t *uiop)
9227c478bd9Sstevel@tonic-gate {
9237c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_MAP);
924870619e9Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
9257c478bd9Sstevel@tonic-gate }
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate static int
9287c478bd9Sstevel@tonic-gate pr_read_rmap(prnode_t *pnp, uio_t *uiop)
9297c478bd9Sstevel@tonic-gate {
9307c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_RMAP);
931870619e9Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
9327c478bd9Sstevel@tonic-gate }
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate static int
9357c478bd9Sstevel@tonic-gate pr_read_xmap(prnode_t *pnp, uio_t *uiop)
9367c478bd9Sstevel@tonic-gate {
9377c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XMAP);
938870619e9Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate static int
9427c478bd9Sstevel@tonic-gate pr_read_cred(prnode_t *pnp, uio_t *uiop)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate 	proc_t *p;
9457c478bd9Sstevel@tonic-gate 	prcred_t *pcrp;
9467c478bd9Sstevel@tonic-gate 	int error;
9477c478bd9Sstevel@tonic-gate 	size_t count;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_CRED);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	/*
9527c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the prcred_t structure because
9537c478bd9Sstevel@tonic-gate 	 * the number of supplementary groups is variable.
9547c478bd9Sstevel@tonic-gate 	 */
9557c478bd9Sstevel@tonic-gate 	pcrp =
9567c478bd9Sstevel@tonic-gate 	    kmem_alloc(sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1),
9577c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
9607c478bd9Sstevel@tonic-gate 		goto out;
9617c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
9627c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	prgetcred(p, pcrp);
9657c478bd9Sstevel@tonic-gate 	prunlock(pnp);
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	count = sizeof (prcred_t);
9687c478bd9Sstevel@tonic-gate 	if (pcrp->pr_ngroups > 1)
9697c478bd9Sstevel@tonic-gate 		count += sizeof (gid_t) * (pcrp->pr_ngroups - 1);
9707c478bd9Sstevel@tonic-gate 	error = pr_uioread(pcrp, count, uiop);
9717c478bd9Sstevel@tonic-gate out:
9727c478bd9Sstevel@tonic-gate 	kmem_free(pcrp, sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1));
9737c478bd9Sstevel@tonic-gate 	return (error);
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate static int
9777c478bd9Sstevel@tonic-gate pr_read_priv(prnode_t *pnp, uio_t *uiop)
9787c478bd9Sstevel@tonic-gate {
9797c478bd9Sstevel@tonic-gate 	proc_t *p;
9807c478bd9Sstevel@tonic-gate 	size_t psize = prgetprivsize();
9817c478bd9Sstevel@tonic-gate 	prpriv_t *ppriv = kmem_alloc(psize, KM_SLEEP);
9827c478bd9Sstevel@tonic-gate 	int error;
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PRIV);
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
9877c478bd9Sstevel@tonic-gate 		goto out;
9887c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
9897c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	prgetpriv(p, ppriv);
9927c478bd9Sstevel@tonic-gate 	prunlock(pnp);
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	error = pr_uioread(ppriv, psize, uiop);
9957c478bd9Sstevel@tonic-gate out:
9967c478bd9Sstevel@tonic-gate 	kmem_free(ppriv, psize);
9977c478bd9Sstevel@tonic-gate 	return (error);
9987c478bd9Sstevel@tonic-gate }
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate static int
10017c478bd9Sstevel@tonic-gate pr_read_sigact(prnode_t *pnp, uio_t *uiop)
10027c478bd9Sstevel@tonic-gate {
1003eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
10047c478bd9Sstevel@tonic-gate 	proc_t *p;
10057c478bd9Sstevel@tonic-gate 	struct sigaction *sap;
10067c478bd9Sstevel@tonic-gate 	int sig;
10077c478bd9Sstevel@tonic-gate 	int error;
10087c478bd9Sstevel@tonic-gate 	user_t *up;
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_SIGACT);
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	/*
10137c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the sigaction array because
10147c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
10157c478bd9Sstevel@tonic-gate 	 */
1016eb9dbf0cSRoger A. Faulkner 	sap = kmem_alloc((nsig-1) * sizeof (struct sigaction), KM_SLEEP);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10197c478bd9Sstevel@tonic-gate 		goto out;
10207c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10217c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
10227c478bd9Sstevel@tonic-gate 
1023eb9dbf0cSRoger A. Faulkner 	if (uiop->uio_offset >= (nsig-1)*sizeof (struct sigaction)) {
10247c478bd9Sstevel@tonic-gate 		prunlock(pnp);
10257c478bd9Sstevel@tonic-gate 		goto out;
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	up = PTOU(p);
1029eb9dbf0cSRoger A. Faulkner 	for (sig = 1; sig < nsig; sig++)
10307c478bd9Sstevel@tonic-gate 		prgetaction(p, up, sig, &sap[sig-1]);
10317c478bd9Sstevel@tonic-gate 	prunlock(pnp);
10327c478bd9Sstevel@tonic-gate 
1033eb9dbf0cSRoger A. Faulkner 	error = pr_uioread(sap, (nsig - 1) * sizeof (struct sigaction), uiop);
10347c478bd9Sstevel@tonic-gate out:
1035eb9dbf0cSRoger A. Faulkner 	kmem_free(sap, (nsig-1) * sizeof (struct sigaction));
10367c478bd9Sstevel@tonic-gate 	return (error);
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate static int
10407c478bd9Sstevel@tonic-gate pr_read_auxv(prnode_t *pnp, uio_t *uiop)
10417c478bd9Sstevel@tonic-gate {
10427c478bd9Sstevel@tonic-gate 	auxv_t auxv[__KERN_NAUXV_IMPL];
10437c478bd9Sstevel@tonic-gate 	proc_t *p;
10447c478bd9Sstevel@tonic-gate 	user_t *up;
10457c478bd9Sstevel@tonic-gate 	int error;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AUXV);
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10507c478bd9Sstevel@tonic-gate 		return (error);
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (auxv)) {
10537c478bd9Sstevel@tonic-gate 		prunlock(pnp);
10547c478bd9Sstevel@tonic-gate 		return (0);
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10587c478bd9Sstevel@tonic-gate 	up = PTOU(p);
10597c478bd9Sstevel@tonic-gate 	bcopy(up->u_auxv, auxv, sizeof (auxv));
10607c478bd9Sstevel@tonic-gate 	prunlock(pnp);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	return (pr_uioread(auxv, sizeof (auxv), uiop));
10637c478bd9Sstevel@tonic-gate }
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate #if defined(__x86)
10667c478bd9Sstevel@tonic-gate /*
10677c478bd9Sstevel@tonic-gate  * XX64
10687c478bd9Sstevel@tonic-gate  *	This is almost certainly broken for the amd64 kernel, because
10697c478bd9Sstevel@tonic-gate  *	we have two kinds of LDT structures to export -- one for compatibility
10707c478bd9Sstevel@tonic-gate  *	mode, and one for long mode, sigh.
10717c478bd9Sstevel@tonic-gate  *
10727c478bd9Sstevel@tonic-gate  * 	For now lets just have a ldt of size 0 for 64-bit processes.
10737c478bd9Sstevel@tonic-gate  */
10747c478bd9Sstevel@tonic-gate static int
10757c478bd9Sstevel@tonic-gate pr_read_ldt(prnode_t *pnp, uio_t *uiop)
10767c478bd9Sstevel@tonic-gate {
10777c478bd9Sstevel@tonic-gate 	proc_t *p;
10787c478bd9Sstevel@tonic-gate 	struct ssd *ssd;
10797c478bd9Sstevel@tonic-gate 	size_t size;
10807c478bd9Sstevel@tonic-gate 	int error;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LDT);
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10857c478bd9Sstevel@tonic-gate 		return (error);
10867c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10877c478bd9Sstevel@tonic-gate 
10887c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
10897c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_ldtlock);
10907c478bd9Sstevel@tonic-gate 	size = prnldt(p) * sizeof (struct ssd);
10917c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
10927c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_ldtlock);
10937c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
10947c478bd9Sstevel@tonic-gate 		prunlock(pnp);
10957c478bd9Sstevel@tonic-gate 		return (0);
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	ssd = kmem_alloc(size, KM_SLEEP);
10997c478bd9Sstevel@tonic-gate 	prgetldt(p, ssd);
11007c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_ldtlock);
11017c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11027c478bd9Sstevel@tonic-gate 	prunlock(pnp);
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	error = pr_uioread(ssd, size, uiop);
11057c478bd9Sstevel@tonic-gate 	kmem_free(ssd, size);
11067c478bd9Sstevel@tonic-gate 	return (error);
11077c478bd9Sstevel@tonic-gate }
11087c478bd9Sstevel@tonic-gate #endif	/* __x86 */
11097c478bd9Sstevel@tonic-gate 
11107c478bd9Sstevel@tonic-gate static int
11117c478bd9Sstevel@tonic-gate pr_read_usage(prnode_t *pnp, uio_t *uiop)
11127c478bd9Sstevel@tonic-gate {
11137c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
11147c478bd9Sstevel@tonic-gate 	prusage_t *upup;
11157c478bd9Sstevel@tonic-gate 	proc_t *p;
11167c478bd9Sstevel@tonic-gate 	kthread_t *t;
11177c478bd9Sstevel@tonic-gate 	int error;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_USAGE);
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
11227c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
11237c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	/*
11267c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
11277c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
11287c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
11297c478bd9Sstevel@tonic-gate 	 */
11307c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
11317c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
11327c478bd9Sstevel@tonic-gate 	if (p == NULL) {
11337c478bd9Sstevel@tonic-gate 		error = ENOENT;
11347c478bd9Sstevel@tonic-gate 		goto out;
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage_t)) {
11397c478bd9Sstevel@tonic-gate 		prunlock(pnp);
11407c478bd9Sstevel@tonic-gate 		error = 0;
11417c478bd9Sstevel@tonic-gate 		goto out;
11427c478bd9Sstevel@tonic-gate 	}
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
11477c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
11487c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
11517c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
11527c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
11537c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
11547c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
11557c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
11567c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
11577c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
11587c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
11597c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
11607c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
11637c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
11647c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
11657c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
11667c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
11677c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
11687c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
11697c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
11707c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
11717c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
11727c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
11737c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 	/*
11767c478bd9Sstevel@tonic-gate 	 * Add the usage information for each active lwp.
11777c478bd9Sstevel@tonic-gate 	 */
11787c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL &&
11797c478bd9Sstevel@tonic-gate 	    !(pnp->pr_pcommon->prc_flags & PRC_DESTROY)) {
11807c478bd9Sstevel@tonic-gate 		do {
11817c478bd9Sstevel@tonic-gate 			if (t->t_proc_flag & TP_LWPEXIT)
11827c478bd9Sstevel@tonic-gate 				continue;
11837c478bd9Sstevel@tonic-gate 			pup->pr_count++;
11847c478bd9Sstevel@tonic-gate 			praddusage(t, pup);
11857c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
11867c478bd9Sstevel@tonic-gate 	}
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	prunlock(pnp);
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	prcvtusage(pup, upup);
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage_t), uiop);
11937c478bd9Sstevel@tonic-gate out:
11947c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
11957c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
11967c478bd9Sstevel@tonic-gate 	return (error);
11977c478bd9Sstevel@tonic-gate }
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate static int
12007c478bd9Sstevel@tonic-gate pr_read_lusage(prnode_t *pnp, uio_t *uiop)
12017c478bd9Sstevel@tonic-gate {
12027c478bd9Sstevel@tonic-gate 	int nlwp;
12037c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
12047c478bd9Sstevel@tonic-gate 	prheader_t *php;
12057c478bd9Sstevel@tonic-gate 	prusage_t *upup;
12067c478bd9Sstevel@tonic-gate 	size_t size;
12077c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
12087c478bd9Sstevel@tonic-gate 	proc_t *p;
12097c478bd9Sstevel@tonic-gate 	kthread_t *t;
12107c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
12117c478bd9Sstevel@tonic-gate 	int error;
12127c478bd9Sstevel@tonic-gate 	int i;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LUSAGE);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	/*
12177c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
12187c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
12197c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
12207c478bd9Sstevel@tonic-gate 	 */
12217c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
12227c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
12237c478bd9Sstevel@tonic-gate 	if (p == NULL)
12247c478bd9Sstevel@tonic-gate 		return (ENOENT);
12257c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
12267c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt) == 0) {
12277c478bd9Sstevel@tonic-gate 		prunlock(pnp);
12287c478bd9Sstevel@tonic-gate 		return (ENOENT);
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	size = sizeof (prheader_t) + (nlwp + 1) * LSPAN(prusage_t);
12327c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
12337c478bd9Sstevel@tonic-gate 		prunlock(pnp);
12347c478bd9Sstevel@tonic-gate 		return (0);
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate 
12377c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
12387c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
12397c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(size + sizeof (prhusage_t), KM_SLEEP);
12407c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
12417c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
12427c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	php = (prheader_t *)(pup + 1);
12457c478bd9Sstevel@tonic-gate 	upup = (prusage_t *)(php + 1);
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp + 1;
12487c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN(prusage_t);
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	curtime = gethrtime();
12517c478bd9Sstevel@tonic-gate 
12527c478bd9Sstevel@tonic-gate 	/*
12537c478bd9Sstevel@tonic-gate 	 * First the summation over defunct lwps.
12547c478bd9Sstevel@tonic-gate 	 */
12557c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
12567c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
12577c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
12587c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
12617c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
12627c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
12637c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
12647c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
12657c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
12667c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
12677c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
12687c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
12697c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
12707c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
12737c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
12747c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
12757c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
12767c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
12777c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
12787c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
12797c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
12807c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
12817c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
12827c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
12837c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	prcvtusage(pup, upup);
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	/*
12887c478bd9Sstevel@tonic-gate 	 * Fill one prusage struct for each active lwp.
12897c478bd9Sstevel@tonic-gate 	 */
12907c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
12917c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
12927c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
12937c478bd9Sstevel@tonic-gate 			continue;
12947c478bd9Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
12957c478bd9Sstevel@tonic-gate 		ASSERT(nlwp > 0);
12967c478bd9Sstevel@tonic-gate 		--nlwp;
12977c478bd9Sstevel@tonic-gate 		upup = (prusage_t *)((caddr_t)upup + LSPAN(prusage_t));
12987c478bd9Sstevel@tonic-gate 		prgetusage(t, pup);
12997c478bd9Sstevel@tonic-gate 		prcvtusage(pup, upup);
13007c478bd9Sstevel@tonic-gate 	}
13017c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == 0);
13027c478bd9Sstevel@tonic-gate 
13037c478bd9Sstevel@tonic-gate 	prunlock(pnp);
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
13067c478bd9Sstevel@tonic-gate 	kmem_free(pup, size + sizeof (prhusage_t));
13077c478bd9Sstevel@tonic-gate 	return (error);
13087c478bd9Sstevel@tonic-gate }
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate static int
13117c478bd9Sstevel@tonic-gate pr_read_pagedata(prnode_t *pnp, uio_t *uiop)
13127c478bd9Sstevel@tonic-gate {
13137c478bd9Sstevel@tonic-gate 	proc_t *p;
13147c478bd9Sstevel@tonic-gate 	int error;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PAGEDATA);
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
13197c478bd9Sstevel@tonic-gate 		return (error);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
13227c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
13237c478bd9Sstevel@tonic-gate 		prunlock(pnp);
13247c478bd9Sstevel@tonic-gate 		return (0);
13257c478bd9Sstevel@tonic-gate 	}
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13287c478bd9Sstevel@tonic-gate 	error = prpdread(p, pnp->pr_hatid, uiop);
13297c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	prunlock(pnp);
13327c478bd9Sstevel@tonic-gate 	return (error);
13337c478bd9Sstevel@tonic-gate }
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate static int
13367c478bd9Sstevel@tonic-gate pr_read_opagedata(prnode_t *pnp, uio_t *uiop)
13377c478bd9Sstevel@tonic-gate {
13387c478bd9Sstevel@tonic-gate 	proc_t *p;
13397c478bd9Sstevel@tonic-gate 	struct as *as;
13407c478bd9Sstevel@tonic-gate 	int error;
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OPAGEDATA);
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
13457c478bd9Sstevel@tonic-gate 		return (error);
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
13487c478bd9Sstevel@tonic-gate 	as = p->p_as;
13497c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
13507c478bd9Sstevel@tonic-gate 		prunlock(pnp);
13517c478bd9Sstevel@tonic-gate 		return (0);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13557c478bd9Sstevel@tonic-gate 	error = oprpdread(as, pnp->pr_hatid, uiop);
13567c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	prunlock(pnp);
13597c478bd9Sstevel@tonic-gate 	return (error);
13607c478bd9Sstevel@tonic-gate }
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate static int
13637c478bd9Sstevel@tonic-gate pr_read_watch(prnode_t *pnp, uio_t *uiop)
13647c478bd9Sstevel@tonic-gate {
13657c478bd9Sstevel@tonic-gate 	proc_t *p;
13667c478bd9Sstevel@tonic-gate 	int error;
13677c478bd9Sstevel@tonic-gate 	prwatch_t *Bpwp;
13687c478bd9Sstevel@tonic-gate 	size_t size;
13697c478bd9Sstevel@tonic-gate 	prwatch_t *pwp;
13707c478bd9Sstevel@tonic-gate 	int nwarea;
13717c478bd9Sstevel@tonic-gate 	struct watched_area *pwarea;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_WATCH);
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
13767c478bd9Sstevel@tonic-gate 		return (error);
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
13797c478bd9Sstevel@tonic-gate 	nwarea = avl_numnodes(&p->p_warea);
13807c478bd9Sstevel@tonic-gate 	size = nwarea * sizeof (prwatch_t);
13817c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
13827c478bd9Sstevel@tonic-gate 		prunlock(pnp);
13837c478bd9Sstevel@tonic-gate 		return (0);
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
13877c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13887c478bd9Sstevel@tonic-gate 	Bpwp = pwp = kmem_zalloc(size, KM_SLEEP);
13897c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13907c478bd9Sstevel@tonic-gate 	/* p->p_nwarea can't change while process is locked */
13917c478bd9Sstevel@tonic-gate 	ASSERT(nwarea == avl_numnodes(&p->p_warea));
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 	/* gather the watched areas */
13947c478bd9Sstevel@tonic-gate 	for (pwarea = avl_first(&p->p_warea); pwarea != NULL;
13957c478bd9Sstevel@tonic-gate 	    pwarea = AVL_NEXT(&p->p_warea, pwarea), pwp++) {
13967c478bd9Sstevel@tonic-gate 		pwp->pr_vaddr = (uintptr_t)pwarea->wa_vaddr;
13977c478bd9Sstevel@tonic-gate 		pwp->pr_size = pwarea->wa_eaddr - pwarea->wa_vaddr;
13987c478bd9Sstevel@tonic-gate 		pwp->pr_wflags = (int)pwarea->wa_flags;
13997c478bd9Sstevel@tonic-gate 	}
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	prunlock(pnp);
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	error = pr_uioread(Bpwp, size, uiop);
14047c478bd9Sstevel@tonic-gate 	kmem_free(Bpwp, size);
14057c478bd9Sstevel@tonic-gate 	return (error);
14067c478bd9Sstevel@tonic-gate }
14077c478bd9Sstevel@tonic-gate 
14087c478bd9Sstevel@tonic-gate static int
14097c478bd9Sstevel@tonic-gate pr_read_lwpstatus(prnode_t *pnp, uio_t *uiop)
14107c478bd9Sstevel@tonic-gate {
14117c478bd9Sstevel@tonic-gate 	lwpstatus_t *sp;
14127c478bd9Sstevel@tonic-gate 	int error;
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSTATUS);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	/*
14177c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the lwpstatus structure because
14187c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
14197c478bd9Sstevel@tonic-gate 	 */
14207c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
14237c478bd9Sstevel@tonic-gate 		goto out;
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (*sp)) {
14267c478bd9Sstevel@tonic-gate 		prunlock(pnp);
14277c478bd9Sstevel@tonic-gate 		goto out;
14287c478bd9Sstevel@tonic-gate 	}
14297c478bd9Sstevel@tonic-gate 
1430fa9e4066Sahrens 	prgetlwpstatus(pnp->pr_common->prc_thread, sp, VTOZONE(PTOV(pnp)));
14317c478bd9Sstevel@tonic-gate 	prunlock(pnp);
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	error = pr_uioread(sp, sizeof (*sp), uiop);
14347c478bd9Sstevel@tonic-gate out:
14357c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
14367c478bd9Sstevel@tonic-gate 	return (error);
14377c478bd9Sstevel@tonic-gate }
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate static int
14407c478bd9Sstevel@tonic-gate pr_read_lwpsinfo(prnode_t *pnp, uio_t *uiop)
14417c478bd9Sstevel@tonic-gate {
14427c478bd9Sstevel@tonic-gate 	lwpsinfo_t lwpsinfo;
14437c478bd9Sstevel@tonic-gate 	proc_t *p;
14447c478bd9Sstevel@tonic-gate 	kthread_t *t;
14457c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSINFO);
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	/*
14507c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
14517c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
14527c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
14537c478bd9Sstevel@tonic-gate 	 */
14547c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
14557c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
14567c478bd9Sstevel@tonic-gate 	if (p == NULL)
14577c478bd9Sstevel@tonic-gate 		return (ENOENT);
14587c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
14597c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_tslot == -1) {
14607c478bd9Sstevel@tonic-gate 		prunlock(pnp);
14617c478bd9Sstevel@tonic-gate 		return (ENOENT);
14627c478bd9Sstevel@tonic-gate 	}
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpsinfo)) {
14657c478bd9Sstevel@tonic-gate 		prunlock(pnp);
14667c478bd9Sstevel@tonic-gate 		return (0);
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	if ((t = pnp->pr_common->prc_thread) != NULL)
14707c478bd9Sstevel@tonic-gate 		prgetlwpsinfo(t, &lwpsinfo);
14717c478bd9Sstevel@tonic-gate 	else {
14727c478bd9Sstevel@tonic-gate 		lep = p->p_lwpdir[pnp->pr_common->prc_tslot].ld_entry;
14737c478bd9Sstevel@tonic-gate 		bzero(&lwpsinfo, sizeof (lwpsinfo));
14747c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_lwpid = lep->le_lwpid;
14757c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_state = SZOMB;
14767c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_sname = 'Z';
14777c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_start.tv_sec = lep->le_start;
14787c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_bindpro = PBIND_NONE;
14797c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_bindpset = PS_NONE;
14807c478bd9Sstevel@tonic-gate 	}
14817c478bd9Sstevel@tonic-gate 	prunlock(pnp);
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	return (pr_uioread(&lwpsinfo, sizeof (lwpsinfo), uiop));
14847c478bd9Sstevel@tonic-gate }
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate static int
14877c478bd9Sstevel@tonic-gate pr_read_lwpusage(prnode_t *pnp, uio_t *uiop)
14887c478bd9Sstevel@tonic-gate {
14897c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
14907c478bd9Sstevel@tonic-gate 	prusage_t *upup;
14917c478bd9Sstevel@tonic-gate 	proc_t *p;
14927c478bd9Sstevel@tonic-gate 	int error;
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPUSAGE);
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
14977c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
14987c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	/*
15017c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
15027c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
15037c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
15047c478bd9Sstevel@tonic-gate 	 */
15057c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
15067c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
15077c478bd9Sstevel@tonic-gate 	if (p == NULL) {
15087c478bd9Sstevel@tonic-gate 		error = ENOENT;
15097c478bd9Sstevel@tonic-gate 		goto out;
15107c478bd9Sstevel@tonic-gate 	}
15117c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
15127c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_thread == NULL) {
15137c478bd9Sstevel@tonic-gate 		prunlock(pnp);
15147c478bd9Sstevel@tonic-gate 		error = ENOENT;
15157c478bd9Sstevel@tonic-gate 		goto out;
15167c478bd9Sstevel@tonic-gate 	}
15177c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage_t)) {
15187c478bd9Sstevel@tonic-gate 		prunlock(pnp);
15197c478bd9Sstevel@tonic-gate 		error = 0;
15207c478bd9Sstevel@tonic-gate 		goto out;
15217c478bd9Sstevel@tonic-gate 	}
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
15247c478bd9Sstevel@tonic-gate 	prgetusage(pnp->pr_common->prc_thread, pup);
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	prunlock(pnp);
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	prcvtusage(pup, upup);
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage_t), uiop);
15317c478bd9Sstevel@tonic-gate out:
15327c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
15337c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
15347c478bd9Sstevel@tonic-gate 	return (error);
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate /* ARGSUSED */
15387c478bd9Sstevel@tonic-gate static int
15397c478bd9Sstevel@tonic-gate pr_read_xregs(prnode_t *pnp, uio_t *uiop)
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate #if defined(__sparc)
15427c478bd9Sstevel@tonic-gate 	proc_t *p;
15437c478bd9Sstevel@tonic-gate 	kthread_t *t;
15447c478bd9Sstevel@tonic-gate 	int error;
15457c478bd9Sstevel@tonic-gate 	char *xreg;
15467c478bd9Sstevel@tonic-gate 	size_t size;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XREGS);
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	xreg = kmem_zalloc(sizeof (prxregset_t), KM_SLEEP);
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
15537c478bd9Sstevel@tonic-gate 		goto out;
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
15567c478bd9Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	size = prhasx(p)? prgetprxregsize(p) : 0;
15597c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
15607c478bd9Sstevel@tonic-gate 		prunlock(pnp);
15617c478bd9Sstevel@tonic-gate 		goto out;
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	/* drop p->p_lock while (possibly) touching the stack */
15657c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
15667c478bd9Sstevel@tonic-gate 	prgetprxregs(ttolwp(t), xreg);
15677c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
15687c478bd9Sstevel@tonic-gate 	prunlock(pnp);
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	error = pr_uioread(xreg, size, uiop);
15717c478bd9Sstevel@tonic-gate out:
15727c478bd9Sstevel@tonic-gate 	kmem_free(xreg, sizeof (prxregset_t));
15737c478bd9Sstevel@tonic-gate 	return (error);
15747c478bd9Sstevel@tonic-gate #else
15757c478bd9Sstevel@tonic-gate 	return (0);
15767c478bd9Sstevel@tonic-gate #endif
15777c478bd9Sstevel@tonic-gate }
15787c478bd9Sstevel@tonic-gate 
1579f971a346SBryan Cantrill static int
1580f971a346SBryan Cantrill pr_read_spymaster(prnode_t *pnp, uio_t *uiop)
1581f971a346SBryan Cantrill {
1582f971a346SBryan Cantrill 	psinfo_t psinfo;
1583f971a346SBryan Cantrill 	int error;
1584f971a346SBryan Cantrill 	klwp_t *lwp;
1585f971a346SBryan Cantrill 
1586f971a346SBryan Cantrill 	ASSERT(pnp->pr_type == PR_SPYMASTER);
1587f971a346SBryan Cantrill 
1588f971a346SBryan Cantrill 	if ((error = prlock(pnp, ZNO)) != 0)
1589f971a346SBryan Cantrill 		return (error);
1590f971a346SBryan Cantrill 
1591f971a346SBryan Cantrill 	lwp = pnp->pr_common->prc_thread->t_lwp;
1592f971a346SBryan Cantrill 
1593f971a346SBryan Cantrill 	if (lwp->lwp_spymaster == NULL) {
1594f971a346SBryan Cantrill 		prunlock(pnp);
1595f971a346SBryan Cantrill 		return (0);
1596f971a346SBryan Cantrill 	}
1597f971a346SBryan Cantrill 
1598f971a346SBryan Cantrill 	bcopy(lwp->lwp_spymaster, &psinfo, sizeof (psinfo_t));
1599f971a346SBryan Cantrill 	prunlock(pnp);
1600f971a346SBryan Cantrill 
1601f971a346SBryan Cantrill 	return (pr_uioread(&psinfo, sizeof (psinfo), uiop));
1602f971a346SBryan Cantrill }
1603f971a346SBryan Cantrill 
16047c478bd9Sstevel@tonic-gate #if defined(__sparc)
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate static int
16077c478bd9Sstevel@tonic-gate pr_read_gwindows(prnode_t *pnp, uio_t *uiop)
16087c478bd9Sstevel@tonic-gate {
16097c478bd9Sstevel@tonic-gate 	proc_t *p;
16107c478bd9Sstevel@tonic-gate 	kthread_t *t;
16117c478bd9Sstevel@tonic-gate 	gwindows_t *gwp;
16127c478bd9Sstevel@tonic-gate 	int error;
16137c478bd9Sstevel@tonic-gate 	size_t size;
16147c478bd9Sstevel@tonic-gate 
16157c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_GWINDOWS);
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	gwp = kmem_zalloc(sizeof (gwindows_t), KM_SLEEP);
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
16207c478bd9Sstevel@tonic-gate 		goto out;
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
16237c478bd9Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 	/*
16267c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock while touching the stack.
16277c478bd9Sstevel@tonic-gate 	 * The P_PR_LOCK flag prevents the lwp from
16287c478bd9Sstevel@tonic-gate 	 * disappearing while we do this.
16297c478bd9Sstevel@tonic-gate 	 */
16307c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
16317c478bd9Sstevel@tonic-gate 	if ((size = prnwindows(ttolwp(t))) != 0)
16327c478bd9Sstevel@tonic-gate 		size = sizeof (gwindows_t) -
16337c478bd9Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW - size) * sizeof (struct rwindow);
16347c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
16357c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
16367c478bd9Sstevel@tonic-gate 		prunlock(pnp);
16377c478bd9Sstevel@tonic-gate 		goto out;
16387c478bd9Sstevel@tonic-gate 	}
16397c478bd9Sstevel@tonic-gate 	prgetwindows(ttolwp(t), gwp);
16407c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
16417c478bd9Sstevel@tonic-gate 	prunlock(pnp);
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	error = pr_uioread(gwp, size, uiop);
16447c478bd9Sstevel@tonic-gate out:
16457c478bd9Sstevel@tonic-gate 	kmem_free(gwp, sizeof (gwindows_t));
16467c478bd9Sstevel@tonic-gate 	return (error);
16477c478bd9Sstevel@tonic-gate }
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate /* ARGSUSED */
16507c478bd9Sstevel@tonic-gate static int
16517c478bd9Sstevel@tonic-gate pr_read_asrs(prnode_t *pnp, uio_t *uiop)
16527c478bd9Sstevel@tonic-gate {
16537c478bd9Sstevel@tonic-gate 	int error;
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_ASRS);
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 	/* the asrs file exists only for sparc v9 _LP64 processes */
16587c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
16597c478bd9Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
16607c478bd9Sstevel@tonic-gate 		kthread_t *t = pnp->pr_common->prc_thread;
16617c478bd9Sstevel@tonic-gate 		asrset_t asrset;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 		if (p->p_model != DATAMODEL_LP64 ||
16647c478bd9Sstevel@tonic-gate 		    uiop->uio_offset >= sizeof (asrset_t)) {
16657c478bd9Sstevel@tonic-gate 			prunlock(pnp);
16667c478bd9Sstevel@tonic-gate 			return (0);
16677c478bd9Sstevel@tonic-gate 		}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 		/*
16707c478bd9Sstevel@tonic-gate 		 * Drop p->p_lock while touching the stack.
16717c478bd9Sstevel@tonic-gate 		 * The P_PR_LOCK flag prevents the lwp from
16727c478bd9Sstevel@tonic-gate 		 * disappearing while we do this.
16737c478bd9Sstevel@tonic-gate 		 */
16747c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
16757c478bd9Sstevel@tonic-gate 		prgetasregs(ttolwp(t), asrset);
16767c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
16777c478bd9Sstevel@tonic-gate 		prunlock(pnp);
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 		error = pr_uioread(&asrset[0], sizeof (asrset_t), uiop);
16807c478bd9Sstevel@tonic-gate 	}
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	return (error);
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate #endif	/* __sparc */
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate static int
16887c478bd9Sstevel@tonic-gate pr_read_piddir(prnode_t *pnp, uio_t *uiop)
16897c478bd9Sstevel@tonic-gate {
16907c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDDIR);
16917c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_pidfile != NULL);
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 	/* use the underlying PR_PIDFILE to read the process */
16947c478bd9Sstevel@tonic-gate 	pnp = VTOP(pnp->pr_pidfile);
16957c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDFILE);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 	return (pr_read_pidfile(pnp, uiop));
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate static int
17017c478bd9Sstevel@tonic-gate pr_read_pidfile(prnode_t *pnp, uio_t *uiop)
17027c478bd9Sstevel@tonic-gate {
17037c478bd9Sstevel@tonic-gate 	int error;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDFILE || pnp->pr_type == PR_LWPIDFILE);
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
17087c478bd9Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
17097c478bd9Sstevel@tonic-gate 		struct as *as = p->p_as;
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || as == &kas) {
17127c478bd9Sstevel@tonic-gate 			/*
17137c478bd9Sstevel@tonic-gate 			 * /proc I/O cannot be done to a system process.
17147c478bd9Sstevel@tonic-gate 			 */
17157c478bd9Sstevel@tonic-gate 			error = EIO;	/* old /proc semantics */
17167c478bd9Sstevel@tonic-gate 		} else {
17177c478bd9Sstevel@tonic-gate 			/*
17187c478bd9Sstevel@tonic-gate 			 * We drop p_lock because we don't want to hold
17197c478bd9Sstevel@tonic-gate 			 * it over an I/O operation because that could
17207c478bd9Sstevel@tonic-gate 			 * lead to deadlock with the clock thread.
17217c478bd9Sstevel@tonic-gate 			 * The process will not disappear and its address
17227c478bd9Sstevel@tonic-gate 			 * space will not change because it is marked P_PR_LOCK.
17237c478bd9Sstevel@tonic-gate 			 */
17247c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
17257c478bd9Sstevel@tonic-gate 			error = prusrio(p, UIO_READ, uiop, 1);
17267c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
17277c478bd9Sstevel@tonic-gate 		}
17287c478bd9Sstevel@tonic-gate 		prunlock(pnp);
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	return (error);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate /*
17377c478bd9Sstevel@tonic-gate  * Array of ILP32 read functions, indexed by /proc file type.
17387c478bd9Sstevel@tonic-gate  */
17397c478bd9Sstevel@tonic-gate static int pr_read_status_32(),
17407c478bd9Sstevel@tonic-gate 	pr_read_lstatus_32(), pr_read_psinfo_32(), pr_read_lpsinfo_32(),
17417c478bd9Sstevel@tonic-gate 	pr_read_map_32(), pr_read_rmap_32(), pr_read_xmap_32(),
17427c478bd9Sstevel@tonic-gate 	pr_read_sigact_32(), pr_read_auxv_32(),
17437c478bd9Sstevel@tonic-gate 	pr_read_usage_32(), pr_read_lusage_32(), pr_read_pagedata_32(),
17447c478bd9Sstevel@tonic-gate 	pr_read_watch_32(), pr_read_lwpstatus_32(), pr_read_lwpsinfo_32(),
1745f971a346SBryan Cantrill 	pr_read_lwpusage_32(), pr_read_spymaster_32(),
17467c478bd9Sstevel@tonic-gate #if defined(__sparc)
17477c478bd9Sstevel@tonic-gate 	pr_read_gwindows_32(),
17487c478bd9Sstevel@tonic-gate #endif
17497c478bd9Sstevel@tonic-gate 	pr_read_opagedata_32();
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate static int (*pr_read_function_32[PR_NFILES])() = {
17527c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc				*/
17537c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/self				*/
17547c478bd9Sstevel@tonic-gate 	pr_read_piddir,		/* /proc/<pid> (old /proc read())	*/
17557c478bd9Sstevel@tonic-gate 	pr_read_as,		/* /proc/<pid>/as			*/
17567c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/ctl			*/
17577c478bd9Sstevel@tonic-gate 	pr_read_status_32,	/* /proc/<pid>/status			*/
17587c478bd9Sstevel@tonic-gate 	pr_read_lstatus_32,	/* /proc/<pid>/lstatus			*/
17597c478bd9Sstevel@tonic-gate 	pr_read_psinfo_32,	/* /proc/<pid>/psinfo			*/
17607c478bd9Sstevel@tonic-gate 	pr_read_lpsinfo_32,	/* /proc/<pid>/lpsinfo			*/
17617c478bd9Sstevel@tonic-gate 	pr_read_map_32,		/* /proc/<pid>/map			*/
17627c478bd9Sstevel@tonic-gate 	pr_read_rmap_32,	/* /proc/<pid>/rmap			*/
17637c478bd9Sstevel@tonic-gate 	pr_read_xmap_32,	/* /proc/<pid>/xmap			*/
17647c478bd9Sstevel@tonic-gate 	pr_read_cred,		/* /proc/<pid>/cred			*/
17657c478bd9Sstevel@tonic-gate 	pr_read_sigact_32,	/* /proc/<pid>/sigact			*/
17667c478bd9Sstevel@tonic-gate 	pr_read_auxv_32,	/* /proc/<pid>/auxv			*/
17677c478bd9Sstevel@tonic-gate #if defined(__x86)
17687c478bd9Sstevel@tonic-gate 	pr_read_ldt,		/* /proc/<pid>/ldt			*/
17697c478bd9Sstevel@tonic-gate #endif
17707c478bd9Sstevel@tonic-gate 	pr_read_usage_32,	/* /proc/<pid>/usage			*/
17717c478bd9Sstevel@tonic-gate 	pr_read_lusage_32,	/* /proc/<pid>/lusage			*/
17727c478bd9Sstevel@tonic-gate 	pr_read_pagedata_32,	/* /proc/<pid>/pagedata			*/
17737c478bd9Sstevel@tonic-gate 	pr_read_watch_32,	/* /proc/<pid>/watch			*/
17747c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/cwd			*/
17757c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/root			*/
17767c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd			*/
17777c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd/nn			*/
17787c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object			*/
17797c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object/xxx		*/
17807c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp			*/
17817c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>		*/
17827c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
17837c478bd9Sstevel@tonic-gate 	pr_read_lwpstatus_32,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
17847c478bd9Sstevel@tonic-gate 	pr_read_lwpsinfo_32,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
17857c478bd9Sstevel@tonic-gate 	pr_read_lwpusage_32,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
17867c478bd9Sstevel@tonic-gate 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
17877c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
17887c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
1789f971a346SBryan Cantrill 	pr_read_spymaster_32,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
17907c478bd9Sstevel@tonic-gate #if defined(__sparc)
17917c478bd9Sstevel@tonic-gate 	pr_read_gwindows_32,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
17927c478bd9Sstevel@tonic-gate 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
17937c478bd9Sstevel@tonic-gate #endif
17947c478bd9Sstevel@tonic-gate 	pr_read_priv,		/* /proc/<pid>/priv			*/
17957c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path			*/
17967c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path/xxx			*/
17977c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts		*/
17987c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts/<ctid>		*/
17997c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old process file			*/
18007c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old lwp file				*/
18017c478bd9Sstevel@tonic-gate 	pr_read_opagedata_32,	/* old pagedata file			*/
18027c478bd9Sstevel@tonic-gate };
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate static int
18057c478bd9Sstevel@tonic-gate pr_read_status_32(prnode_t *pnp, uio_t *uiop)
18067c478bd9Sstevel@tonic-gate {
18077c478bd9Sstevel@tonic-gate 	pstatus32_t *sp;
18087c478bd9Sstevel@tonic-gate 	proc_t *p;
18097c478bd9Sstevel@tonic-gate 	int error;
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_STATUS);
18127c478bd9Sstevel@tonic-gate 
18137c478bd9Sstevel@tonic-gate 	/*
18147c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the pstatus structure because
18157c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
18167c478bd9Sstevel@tonic-gate 	 */
18177c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
18187c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
18197c478bd9Sstevel@tonic-gate 		/*
18207c478bd9Sstevel@tonic-gate 		 * A 32-bit process cannot get the status of a 64-bit process.
18217c478bd9Sstevel@tonic-gate 		 * The fields for the 64-bit quantities are not large enough.
18227c478bd9Sstevel@tonic-gate 		 */
18237c478bd9Sstevel@tonic-gate 		p = pnp->pr_common->prc_proc;
18247c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p)) {
18257c478bd9Sstevel@tonic-gate 			prunlock(pnp);
18267c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
18277c478bd9Sstevel@tonic-gate 		} else {
18287c478bd9Sstevel@tonic-gate 			prgetstatus32(pnp->pr_common->prc_proc, sp,
1829fa9e4066Sahrens 			    VTOZONE(PTOV(pnp)));
18307c478bd9Sstevel@tonic-gate 			prunlock(pnp);
18317c478bd9Sstevel@tonic-gate 			error = pr_uioread(sp, sizeof (*sp), uiop);
18327c478bd9Sstevel@tonic-gate 		}
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)sp, sizeof (*sp));
18357c478bd9Sstevel@tonic-gate 	return (error);
18367c478bd9Sstevel@tonic-gate }
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate static int
18397c478bd9Sstevel@tonic-gate pr_read_lstatus_32(prnode_t *pnp, uio_t *uiop)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate 	proc_t *p;
18427c478bd9Sstevel@tonic-gate 	kthread_t *t;
18437c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
18447c478bd9Sstevel@tonic-gate 	size_t size;
18457c478bd9Sstevel@tonic-gate 	prheader32_t *php;
18467c478bd9Sstevel@tonic-gate 	lwpstatus32_t *sp;
18477c478bd9Sstevel@tonic-gate 	int error;
18487c478bd9Sstevel@tonic-gate 	int nlwp;
18497c478bd9Sstevel@tonic-gate 	int i;
18507c478bd9Sstevel@tonic-gate 
18517c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LSTATUS);
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
18547c478bd9Sstevel@tonic-gate 		return (error);
18557c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
18567c478bd9Sstevel@tonic-gate 	/*
18577c478bd9Sstevel@tonic-gate 	 * A 32-bit process cannot get the status of a 64-bit process.
18587c478bd9Sstevel@tonic-gate 	 * The fields for the 64-bit quantities are not large enough.
18597c478bd9Sstevel@tonic-gate 	 */
18607c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
18617c478bd9Sstevel@tonic-gate 		prunlock(pnp);
18627c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 	nlwp = p->p_lwpcnt;
18657c478bd9Sstevel@tonic-gate 	size = sizeof (prheader32_t) + nlwp * LSPAN32(lwpstatus32_t);
18667c478bd9Sstevel@tonic-gate 
18677c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
18687c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
18697c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
18707c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18717c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
18727c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
18757c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(lwpstatus32_t);
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	sp = (lwpstatus32_t *)(php + 1);
18787c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
18797c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
18807c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
18817c478bd9Sstevel@tonic-gate 			continue;
1882fa9e4066Sahrens 		prgetlwpstatus32(t, sp, VTOZONE(PTOV(pnp)));
18837c478bd9Sstevel@tonic-gate 		sp = (lwpstatus32_t *)((caddr_t)sp + LSPAN32(lwpstatus32_t));
18847c478bd9Sstevel@tonic-gate 	}
18857c478bd9Sstevel@tonic-gate 	prunlock(pnp);
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
18887c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
18897c478bd9Sstevel@tonic-gate 	return (error);
18907c478bd9Sstevel@tonic-gate }
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate static int
18937c478bd9Sstevel@tonic-gate pr_read_psinfo_32(prnode_t *pnp, uio_t *uiop)
18947c478bd9Sstevel@tonic-gate {
18957c478bd9Sstevel@tonic-gate 	psinfo32_t psinfo;
18967c478bd9Sstevel@tonic-gate 	proc_t *p;
18977c478bd9Sstevel@tonic-gate 	int error = 0;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PSINFO);
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	/*
19027c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
19037c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
19047c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
19057c478bd9Sstevel@tonic-gate 	 */
19067c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
19077c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
19087c478bd9Sstevel@tonic-gate 	if (p == NULL)
19097c478bd9Sstevel@tonic-gate 		error = ENOENT;
19107c478bd9Sstevel@tonic-gate 	else {
19117c478bd9Sstevel@tonic-gate 		ASSERT(p == pnp->pr_common->prc_proc);
19127c478bd9Sstevel@tonic-gate 		prgetpsinfo32(p, &psinfo);
19137c478bd9Sstevel@tonic-gate 		prunlock(pnp);
19147c478bd9Sstevel@tonic-gate 		error = pr_uioread(&psinfo, sizeof (psinfo), uiop);
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 	return (error);
19177c478bd9Sstevel@tonic-gate }
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate static int
19207c478bd9Sstevel@tonic-gate pr_read_lpsinfo_32(prnode_t *pnp, uio_t *uiop)
19217c478bd9Sstevel@tonic-gate {
19227c478bd9Sstevel@tonic-gate 	proc_t *p;
19237c478bd9Sstevel@tonic-gate 	kthread_t *t;
19247c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
19257c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
19267c478bd9Sstevel@tonic-gate 	size_t size;
19277c478bd9Sstevel@tonic-gate 	prheader32_t *php;
19287c478bd9Sstevel@tonic-gate 	lwpsinfo32_t *sp;
19297c478bd9Sstevel@tonic-gate 	int error;
19307c478bd9Sstevel@tonic-gate 	int nlwp;
19317c478bd9Sstevel@tonic-gate 	int i;
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LPSINFO);
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	/*
19367c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
19377c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
19387c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
19397c478bd9Sstevel@tonic-gate 	 */
19407c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
19417c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
19427c478bd9Sstevel@tonic-gate 	if (p == NULL)
19437c478bd9Sstevel@tonic-gate 		return (ENOENT);
19447c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
19457c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt + p->p_zombcnt) == 0) {
19467c478bd9Sstevel@tonic-gate 		prunlock(pnp);
19477c478bd9Sstevel@tonic-gate 		return (ENOENT);
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate 	size = sizeof (prheader32_t) + nlwp * LSPAN32(lwpsinfo32_t);
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
19527c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
19537c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
19547c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
19557c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
19567c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt + p->p_zombcnt);
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
19597c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(lwpsinfo32_t);
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate 	sp = (lwpsinfo32_t *)(php + 1);
19627c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
19637c478bd9Sstevel@tonic-gate 		if ((lep = ldp->ld_entry) == NULL)
19647c478bd9Sstevel@tonic-gate 			continue;
19657c478bd9Sstevel@tonic-gate 		if ((t = lep->le_thread) != NULL)
19667c478bd9Sstevel@tonic-gate 			prgetlwpsinfo32(t, sp);
19677c478bd9Sstevel@tonic-gate 		else {
19687c478bd9Sstevel@tonic-gate 			bzero(sp, sizeof (*sp));
19697c478bd9Sstevel@tonic-gate 			sp->pr_lwpid = lep->le_lwpid;
19707c478bd9Sstevel@tonic-gate 			sp->pr_state = SZOMB;
19717c478bd9Sstevel@tonic-gate 			sp->pr_sname = 'Z';
19727c478bd9Sstevel@tonic-gate 			sp->pr_start.tv_sec = (time32_t)lep->le_start;
19737c478bd9Sstevel@tonic-gate 		}
19747c478bd9Sstevel@tonic-gate 		sp = (lwpsinfo32_t *)((caddr_t)sp + LSPAN32(lwpsinfo32_t));
19757c478bd9Sstevel@tonic-gate 	}
19767c478bd9Sstevel@tonic-gate 	prunlock(pnp);
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
19797c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
19807c478bd9Sstevel@tonic-gate 	return (error);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate static int
1984870619e9Sfrankho pr_read_map_common_32(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
19857c478bd9Sstevel@tonic-gate {
19867c478bd9Sstevel@tonic-gate 	proc_t *p;
19877c478bd9Sstevel@tonic-gate 	struct as *as;
1988870619e9Sfrankho 	list_t	iolhead;
19897c478bd9Sstevel@tonic-gate 	int error;
19907c478bd9Sstevel@tonic-gate 
1991e24ad047SChristopher Baumbauer - Oracle America - San Diego United States readmap32_common:
19927c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
19937c478bd9Sstevel@tonic-gate 		return (error);
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
19967c478bd9Sstevel@tonic-gate 	as = p->p_as;
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
19997c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20007c478bd9Sstevel@tonic-gate 		return (0);
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
20047c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20057c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
20067c478bd9Sstevel@tonic-gate 	}
20077c478bd9Sstevel@tonic-gate 
2008*dc32d872SJosef 'Jeff' Sipek 	if (!AS_LOCK_TRYENTER(as, RW_WRITER)) {
2009e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		prunlock(pnp);
2010e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		delay(1);
2011e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		goto readmap32_common;
2012e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 	}
20137c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
2014e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 
2015870619e9Sfrankho 	switch (type) {
2016870619e9Sfrankho 	case PR_XMAP:
2017870619e9Sfrankho 		error = prgetxmap32(p, &iolhead);
2018870619e9Sfrankho 		break;
2019870619e9Sfrankho 	case PR_RMAP:
2020870619e9Sfrankho 		error = prgetmap32(p, 1, &iolhead);
2021870619e9Sfrankho 		break;
2022870619e9Sfrankho 	case PR_MAP:
2023870619e9Sfrankho 		error = prgetmap32(p, 0, &iolhead);
2024870619e9Sfrankho 		break;
2025870619e9Sfrankho 	}
2026*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
20277c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
20287c478bd9Sstevel@tonic-gate 	prunlock(pnp);
20297c478bd9Sstevel@tonic-gate 
2030870619e9Sfrankho 	error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
2031870619e9Sfrankho 
20327c478bd9Sstevel@tonic-gate 	return (error);
20337c478bd9Sstevel@tonic-gate }
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate static int
20367c478bd9Sstevel@tonic-gate pr_read_map_32(prnode_t *pnp, uio_t *uiop)
20377c478bd9Sstevel@tonic-gate {
20387c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_MAP);
2039870619e9Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
20407c478bd9Sstevel@tonic-gate }
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate static int
20437c478bd9Sstevel@tonic-gate pr_read_rmap_32(prnode_t *pnp, uio_t *uiop)
20447c478bd9Sstevel@tonic-gate {
20457c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_RMAP);
2046870619e9Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
20477c478bd9Sstevel@tonic-gate }
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate static int
20507c478bd9Sstevel@tonic-gate pr_read_xmap_32(prnode_t *pnp, uio_t *uiop)
20517c478bd9Sstevel@tonic-gate {
20527c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XMAP);
2053870619e9Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
20547c478bd9Sstevel@tonic-gate }
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate static int
20577c478bd9Sstevel@tonic-gate pr_read_sigact_32(prnode_t *pnp, uio_t *uiop)
20587c478bd9Sstevel@tonic-gate {
2059eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
20607c478bd9Sstevel@tonic-gate 	proc_t *p;
20617c478bd9Sstevel@tonic-gate 	struct sigaction32 *sap;
20627c478bd9Sstevel@tonic-gate 	int sig;
20637c478bd9Sstevel@tonic-gate 	int error;
20647c478bd9Sstevel@tonic-gate 	user_t *up;
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_SIGACT);
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	/*
20697c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the sigaction32 array because
20707c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
20717c478bd9Sstevel@tonic-gate 	 */
2072eb9dbf0cSRoger A. Faulkner 	sap = kmem_alloc((nsig-1) * sizeof (struct sigaction32), KM_SLEEP);
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
20757c478bd9Sstevel@tonic-gate 		goto out;
20767c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
20777c478bd9Sstevel@tonic-gate 
20787c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
20797c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20807c478bd9Sstevel@tonic-gate 		error = EOVERFLOW;
20817c478bd9Sstevel@tonic-gate 		goto out;
20827c478bd9Sstevel@tonic-gate 	}
20837c478bd9Sstevel@tonic-gate 
2084eb9dbf0cSRoger A. Faulkner 	if (uiop->uio_offset >= (nsig-1) * sizeof (struct sigaction32)) {
20857c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20867c478bd9Sstevel@tonic-gate 		goto out;
20877c478bd9Sstevel@tonic-gate 	}
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	up = PTOU(p);
2090eb9dbf0cSRoger A. Faulkner 	for (sig = 1; sig < nsig; sig++)
20917c478bd9Sstevel@tonic-gate 		prgetaction32(p, up, sig, &sap[sig-1]);
20927c478bd9Sstevel@tonic-gate 	prunlock(pnp);
20937c478bd9Sstevel@tonic-gate 
2094eb9dbf0cSRoger A. Faulkner 	error = pr_uioread(sap, (nsig - 1) * sizeof (struct sigaction32), uiop);
20957c478bd9Sstevel@tonic-gate out:
2096eb9dbf0cSRoger A. Faulkner 	kmem_free(sap, (nsig-1) * sizeof (struct sigaction32));
20977c478bd9Sstevel@tonic-gate 	return (error);
20987c478bd9Sstevel@tonic-gate }
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate static int
21017c478bd9Sstevel@tonic-gate pr_read_auxv_32(prnode_t *pnp, uio_t *uiop)
21027c478bd9Sstevel@tonic-gate {
21037c478bd9Sstevel@tonic-gate 	auxv32_t auxv[__KERN_NAUXV_IMPL];
21047c478bd9Sstevel@tonic-gate 	proc_t *p;
21057c478bd9Sstevel@tonic-gate 	user_t *up;
21067c478bd9Sstevel@tonic-gate 	int error;
21077c478bd9Sstevel@tonic-gate 	int i;
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AUXV);
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
21127c478bd9Sstevel@tonic-gate 		return (error);
21137c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
21167c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21177c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
21187c478bd9Sstevel@tonic-gate 	}
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (auxv)) {
21217c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21227c478bd9Sstevel@tonic-gate 		return (0);
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate 
21257c478bd9Sstevel@tonic-gate 	up = PTOU(p);
21267c478bd9Sstevel@tonic-gate 	for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
21277c478bd9Sstevel@tonic-gate 		auxv[i].a_type = (int32_t)up->u_auxv[i].a_type;
21287c478bd9Sstevel@tonic-gate 		auxv[i].a_un.a_val = (int32_t)up->u_auxv[i].a_un.a_val;
21297c478bd9Sstevel@tonic-gate 	}
21307c478bd9Sstevel@tonic-gate 	prunlock(pnp);
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	return (pr_uioread(auxv, sizeof (auxv), uiop));
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate static int
21367c478bd9Sstevel@tonic-gate pr_read_usage_32(prnode_t *pnp, uio_t *uiop)
21377c478bd9Sstevel@tonic-gate {
21387c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
21397c478bd9Sstevel@tonic-gate 	prusage32_t *upup;
21407c478bd9Sstevel@tonic-gate 	proc_t *p;
21417c478bd9Sstevel@tonic-gate 	kthread_t *t;
21427c478bd9Sstevel@tonic-gate 	int error;
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_USAGE);
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
21477c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
21487c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 	/*
21517c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
21527c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
21537c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
21547c478bd9Sstevel@tonic-gate 	 */
21557c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
21567c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
21577c478bd9Sstevel@tonic-gate 	if (p == NULL) {
21587c478bd9Sstevel@tonic-gate 		error = ENOENT;
21597c478bd9Sstevel@tonic-gate 		goto out;
21607c478bd9Sstevel@tonic-gate 	}
21617c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage32_t)) {
21647c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21657c478bd9Sstevel@tonic-gate 		error = 0;
21667c478bd9Sstevel@tonic-gate 		goto out;
21677c478bd9Sstevel@tonic-gate 	}
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
21707c478bd9Sstevel@tonic-gate 
21717c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
21727c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
21737c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
21767c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
21777c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
21787c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
21797c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
21807c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
21817c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
21827c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
21837c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
21847c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
21857c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
21887c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
21897c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
21907c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
21917c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
21927c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
21937c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
21947c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
21957c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
21967c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
21977c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
21987c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 	/*
22017c478bd9Sstevel@tonic-gate 	 * Add the usage information for each active lwp.
22027c478bd9Sstevel@tonic-gate 	 */
22037c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL &&
22047c478bd9Sstevel@tonic-gate 	    !(pnp->pr_pcommon->prc_flags & PRC_DESTROY)) {
22057c478bd9Sstevel@tonic-gate 		do {
22067c478bd9Sstevel@tonic-gate 			if (t->t_proc_flag & TP_LWPEXIT)
22077c478bd9Sstevel@tonic-gate 				continue;
22087c478bd9Sstevel@tonic-gate 			pup->pr_count++;
22097c478bd9Sstevel@tonic-gate 			praddusage(t, pup);
22107c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
22117c478bd9Sstevel@tonic-gate 	}
22127c478bd9Sstevel@tonic-gate 
22137c478bd9Sstevel@tonic-gate 	prunlock(pnp);
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	prcvtusage32(pup, upup);
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage32_t), uiop);
22187c478bd9Sstevel@tonic-gate out:
22197c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
22207c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
22217c478bd9Sstevel@tonic-gate 	return (error);
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate static int
22257c478bd9Sstevel@tonic-gate pr_read_lusage_32(prnode_t *pnp, uio_t *uiop)
22267c478bd9Sstevel@tonic-gate {
22277c478bd9Sstevel@tonic-gate 	int nlwp;
22287c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
22297c478bd9Sstevel@tonic-gate 	prheader32_t *php;
22307c478bd9Sstevel@tonic-gate 	prusage32_t *upup;
22317c478bd9Sstevel@tonic-gate 	size_t size;
22327c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
22337c478bd9Sstevel@tonic-gate 	proc_t *p;
22347c478bd9Sstevel@tonic-gate 	kthread_t *t;
22357c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
22367c478bd9Sstevel@tonic-gate 	int error;
22377c478bd9Sstevel@tonic-gate 	int i;
22387c478bd9Sstevel@tonic-gate 
22397c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LUSAGE);
22407c478bd9Sstevel@tonic-gate 
22417c478bd9Sstevel@tonic-gate 	/*
22427c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
22437c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
22447c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
22457c478bd9Sstevel@tonic-gate 	 */
22467c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
22477c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
22487c478bd9Sstevel@tonic-gate 	if (p == NULL)
22497c478bd9Sstevel@tonic-gate 		return (ENOENT);
22507c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
22517c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt) == 0) {
22527c478bd9Sstevel@tonic-gate 		prunlock(pnp);
22537c478bd9Sstevel@tonic-gate 		return (ENOENT);
22547c478bd9Sstevel@tonic-gate 	}
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	size = sizeof (prheader32_t) + (nlwp + 1) * LSPAN32(prusage32_t);
22577c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
22587c478bd9Sstevel@tonic-gate 		prunlock(pnp);
22597c478bd9Sstevel@tonic-gate 		return (0);
22607c478bd9Sstevel@tonic-gate 	}
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
22637c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
22647c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(size + sizeof (prhusage_t), KM_SLEEP);
22657c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22667c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
22677c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	php = (prheader32_t *)(pup + 1);
22707c478bd9Sstevel@tonic-gate 	upup = (prusage32_t *)(php + 1);
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp + 1;
22737c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(prusage32_t);
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	curtime = gethrtime();
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	/*
22787c478bd9Sstevel@tonic-gate 	 * First the summation over defunct lwps.
22797c478bd9Sstevel@tonic-gate 	 */
22807c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
22817c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
22827c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
22837c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
22867c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
22877c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
22887c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
22897c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
22907c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
22917c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
22927c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
22937c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
22947c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
22957c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
22987c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
22997c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
23007c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
23017c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
23027c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
23037c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
23047c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
23057c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
23067c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
23077c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
23087c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 	prcvtusage32(pup, upup);
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate 	/*
23137c478bd9Sstevel@tonic-gate 	 * Fill one prusage struct for each active lwp.
23147c478bd9Sstevel@tonic-gate 	 */
23157c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
23167c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
23177c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
23187c478bd9Sstevel@tonic-gate 			continue;
23197c478bd9Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
23207c478bd9Sstevel@tonic-gate 		ASSERT(nlwp > 0);
23217c478bd9Sstevel@tonic-gate 		--nlwp;
23227c478bd9Sstevel@tonic-gate 		upup = (prusage32_t *)
23237c478bd9Sstevel@tonic-gate 		    ((caddr_t)upup + LSPAN32(prusage32_t));
23247c478bd9Sstevel@tonic-gate 		prgetusage(t, pup);
23257c478bd9Sstevel@tonic-gate 		prcvtusage32(pup, upup);
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == 0);
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	prunlock(pnp);
23307c478bd9Sstevel@tonic-gate 
23317c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
23327c478bd9Sstevel@tonic-gate 	kmem_free(pup, size + sizeof (prhusage_t));
23337c478bd9Sstevel@tonic-gate 	return (error);
23347c478bd9Sstevel@tonic-gate }
23357c478bd9Sstevel@tonic-gate 
23367c478bd9Sstevel@tonic-gate static int
23377c478bd9Sstevel@tonic-gate pr_read_pagedata_32(prnode_t *pnp, uio_t *uiop)
23387c478bd9Sstevel@tonic-gate {
23397c478bd9Sstevel@tonic-gate 	proc_t *p;
23407c478bd9Sstevel@tonic-gate 	int error;
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PAGEDATA);
23437c478bd9Sstevel@tonic-gate 
23447c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
23457c478bd9Sstevel@tonic-gate 		return (error);
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
23487c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
23497c478bd9Sstevel@tonic-gate 		prunlock(pnp);
23507c478bd9Sstevel@tonic-gate 		return (0);
23517c478bd9Sstevel@tonic-gate 	}
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
23547c478bd9Sstevel@tonic-gate 		prunlock(pnp);
23557c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
23567c478bd9Sstevel@tonic-gate 	}
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
23597c478bd9Sstevel@tonic-gate 	error = prpdread32(p, pnp->pr_hatid, uiop);
23607c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate 	prunlock(pnp);
23637c478bd9Sstevel@tonic-gate 	return (error);
23647c478bd9Sstevel@tonic-gate }
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate static int
23677c478bd9Sstevel@tonic-gate pr_read_opagedata_32(prnode_t *pnp, uio_t *uiop)
23687c478bd9Sstevel@tonic-gate {
23697c478bd9Sstevel@tonic-gate 	proc_t *p;
23707c478bd9Sstevel@tonic-gate 	struct as *as;
23717c478bd9Sstevel@tonic-gate 	int error;
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OPAGEDATA);
23747c478bd9Sstevel@tonic-gate 
23757c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
23767c478bd9Sstevel@tonic-gate 		return (error);
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
23797c478bd9Sstevel@tonic-gate 	as = p->p_as;
23807c478bd9Sstevel@tonic-gate 
23817c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
23827c478bd9Sstevel@tonic-gate 		prunlock(pnp);
23837c478bd9Sstevel@tonic-gate 		return (0);
23847c478bd9Sstevel@tonic-gate 	}
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
23877c478bd9Sstevel@tonic-gate 		prunlock(pnp);
23887c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
23897c478bd9Sstevel@tonic-gate 	}
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
23927c478bd9Sstevel@tonic-gate 	error = oprpdread32(as, pnp->pr_hatid, uiop);
23937c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	prunlock(pnp);
23967c478bd9Sstevel@tonic-gate 	return (error);
23977c478bd9Sstevel@tonic-gate }
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate static int
24007c478bd9Sstevel@tonic-gate pr_read_watch_32(prnode_t *pnp, uio_t *uiop)
24017c478bd9Sstevel@tonic-gate {
24027c478bd9Sstevel@tonic-gate 	proc_t *p;
24037c478bd9Sstevel@tonic-gate 	int error;
24047c478bd9Sstevel@tonic-gate 	prwatch32_t *Bpwp;
24057c478bd9Sstevel@tonic-gate 	size_t size;
24067c478bd9Sstevel@tonic-gate 	prwatch32_t *pwp;
24077c478bd9Sstevel@tonic-gate 	int nwarea;
24087c478bd9Sstevel@tonic-gate 	struct watched_area *pwarea;
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_WATCH);
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
24137c478bd9Sstevel@tonic-gate 		return (error);
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
24167c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
24177c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24187c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
24197c478bd9Sstevel@tonic-gate 	}
24207c478bd9Sstevel@tonic-gate 	nwarea = avl_numnodes(&p->p_warea);
24217c478bd9Sstevel@tonic-gate 	size = nwarea * sizeof (prwatch32_t);
24227c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
24237c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24247c478bd9Sstevel@tonic-gate 		return (0);
24257c478bd9Sstevel@tonic-gate 	}
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
24287c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
24297c478bd9Sstevel@tonic-gate 	Bpwp = pwp = kmem_zalloc(size, KM_SLEEP);
24307c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
24317c478bd9Sstevel@tonic-gate 	/* p->p_nwarea can't change while process is locked */
24327c478bd9Sstevel@tonic-gate 	ASSERT(nwarea == avl_numnodes(&p->p_warea));
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate 	/* gather the watched areas */
24357c478bd9Sstevel@tonic-gate 	for (pwarea = avl_first(&p->p_warea); pwarea != NULL;
24367c478bd9Sstevel@tonic-gate 	    pwarea = AVL_NEXT(&p->p_warea, pwarea), pwp++) {
24377c478bd9Sstevel@tonic-gate 		pwp->pr_vaddr = (caddr32_t)(uintptr_t)pwarea->wa_vaddr;
24387c478bd9Sstevel@tonic-gate 		pwp->pr_size = (size32_t)(pwarea->wa_eaddr - pwarea->wa_vaddr);
24397c478bd9Sstevel@tonic-gate 		pwp->pr_wflags = (int)pwarea->wa_flags;
24407c478bd9Sstevel@tonic-gate 	}
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	prunlock(pnp);
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	error = pr_uioread(Bpwp, size, uiop);
24457c478bd9Sstevel@tonic-gate 	kmem_free(Bpwp, size);
24467c478bd9Sstevel@tonic-gate 	return (error);
24477c478bd9Sstevel@tonic-gate }
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate static int
24507c478bd9Sstevel@tonic-gate pr_read_lwpstatus_32(prnode_t *pnp, uio_t *uiop)
24517c478bd9Sstevel@tonic-gate {
24527c478bd9Sstevel@tonic-gate 	lwpstatus32_t *sp;
24537c478bd9Sstevel@tonic-gate 	proc_t *p;
24547c478bd9Sstevel@tonic-gate 	int error;
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSTATUS);
24577c478bd9Sstevel@tonic-gate 
24587c478bd9Sstevel@tonic-gate 	/*
24597c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the lwpstatus structure because
24607c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
24617c478bd9Sstevel@tonic-gate 	 */
24627c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
24657c478bd9Sstevel@tonic-gate 		goto out;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	/*
24687c478bd9Sstevel@tonic-gate 	 * A 32-bit process cannot get the status of a 64-bit process.
24697c478bd9Sstevel@tonic-gate 	 * The fields for the 64-bit quantities are not large enough.
24707c478bd9Sstevel@tonic-gate 	 */
24717c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
24727c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
24737c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24747c478bd9Sstevel@tonic-gate 		error = EOVERFLOW;
24757c478bd9Sstevel@tonic-gate 		goto out;
24767c478bd9Sstevel@tonic-gate 	}
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (*sp)) {
24797c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24807c478bd9Sstevel@tonic-gate 		goto out;
24817c478bd9Sstevel@tonic-gate 	}
24827c478bd9Sstevel@tonic-gate 
2483fa9e4066Sahrens 	prgetlwpstatus32(pnp->pr_common->prc_thread, sp, VTOZONE(PTOV(pnp)));
24847c478bd9Sstevel@tonic-gate 	prunlock(pnp);
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate 	error = pr_uioread(sp, sizeof (*sp), uiop);
24877c478bd9Sstevel@tonic-gate out:
24887c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
24897c478bd9Sstevel@tonic-gate 	return (error);
24907c478bd9Sstevel@tonic-gate }
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate static int
24937c478bd9Sstevel@tonic-gate pr_read_lwpsinfo_32(prnode_t *pnp, uio_t *uiop)
24947c478bd9Sstevel@tonic-gate {
24957c478bd9Sstevel@tonic-gate 	lwpsinfo32_t lwpsinfo;
24967c478bd9Sstevel@tonic-gate 	proc_t *p;
24977c478bd9Sstevel@tonic-gate 	kthread_t *t;
24987c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSINFO);
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	/*
25037c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
25047c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
25057c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
25067c478bd9Sstevel@tonic-gate 	 */
25077c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
25087c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
25097c478bd9Sstevel@tonic-gate 	if (p == NULL)
25107c478bd9Sstevel@tonic-gate 		return (ENOENT);
25117c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
25127c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_tslot == -1) {
25137c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25147c478bd9Sstevel@tonic-gate 		return (ENOENT);
25157c478bd9Sstevel@tonic-gate 	}
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpsinfo)) {
25187c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25197c478bd9Sstevel@tonic-gate 		return (0);
25207c478bd9Sstevel@tonic-gate 	}
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 	if ((t = pnp->pr_common->prc_thread) != NULL)
25237c478bd9Sstevel@tonic-gate 		prgetlwpsinfo32(t, &lwpsinfo);
25247c478bd9Sstevel@tonic-gate 	else {
25257c478bd9Sstevel@tonic-gate 		lep = p->p_lwpdir[pnp->pr_common->prc_tslot].ld_entry;
25267c478bd9Sstevel@tonic-gate 		bzero(&lwpsinfo, sizeof (lwpsinfo));
25277c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_lwpid = lep->le_lwpid;
25287c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_state = SZOMB;
25297c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_sname = 'Z';
25307c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_start.tv_sec = (time32_t)lep->le_start;
25317c478bd9Sstevel@tonic-gate 	}
25327c478bd9Sstevel@tonic-gate 	prunlock(pnp);
25337c478bd9Sstevel@tonic-gate 
25347c478bd9Sstevel@tonic-gate 	return (pr_uioread(&lwpsinfo, sizeof (lwpsinfo), uiop));
25357c478bd9Sstevel@tonic-gate }
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate static int
25387c478bd9Sstevel@tonic-gate pr_read_lwpusage_32(prnode_t *pnp, uio_t *uiop)
25397c478bd9Sstevel@tonic-gate {
25407c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
25417c478bd9Sstevel@tonic-gate 	prusage32_t *upup;
25427c478bd9Sstevel@tonic-gate 	proc_t *p;
25437c478bd9Sstevel@tonic-gate 	int error;
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPUSAGE);
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
25487c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
25497c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
25507c478bd9Sstevel@tonic-gate 
25517c478bd9Sstevel@tonic-gate 	/*
25527c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
25537c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
25547c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
25557c478bd9Sstevel@tonic-gate 	 */
25567c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
25577c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
25587c478bd9Sstevel@tonic-gate 	if (p == NULL) {
25597c478bd9Sstevel@tonic-gate 		error = ENOENT;
25607c478bd9Sstevel@tonic-gate 		goto out;
25617c478bd9Sstevel@tonic-gate 	}
25627c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
25637c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_thread == NULL) {
25647c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25657c478bd9Sstevel@tonic-gate 		error = ENOENT;
25667c478bd9Sstevel@tonic-gate 		goto out;
25677c478bd9Sstevel@tonic-gate 	}
25687c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage32_t)) {
25697c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25707c478bd9Sstevel@tonic-gate 		error = 0;
25717c478bd9Sstevel@tonic-gate 		goto out;
25727c478bd9Sstevel@tonic-gate 	}
25737c478bd9Sstevel@tonic-gate 
25747c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
25757c478bd9Sstevel@tonic-gate 	prgetusage(pnp->pr_common->prc_thread, pup);
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	prunlock(pnp);
25787c478bd9Sstevel@tonic-gate 
25797c478bd9Sstevel@tonic-gate 	prcvtusage32(pup, upup);
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage32_t), uiop);
25827c478bd9Sstevel@tonic-gate out:
25837c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
25847c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
25857c478bd9Sstevel@tonic-gate 	return (error);
25867c478bd9Sstevel@tonic-gate }
25877c478bd9Sstevel@tonic-gate 
2588f971a346SBryan Cantrill static int
2589f971a346SBryan Cantrill pr_read_spymaster_32(prnode_t *pnp, uio_t *uiop)
2590f971a346SBryan Cantrill {
2591f971a346SBryan Cantrill 	psinfo32_t psinfo;
2592f971a346SBryan Cantrill 	int error;
2593f971a346SBryan Cantrill 	klwp_t *lwp;
2594f971a346SBryan Cantrill 
2595f971a346SBryan Cantrill 	ASSERT(pnp->pr_type == PR_SPYMASTER);
2596f971a346SBryan Cantrill 
2597f971a346SBryan Cantrill 	if ((error = prlock(pnp, ZNO)) != 0)
2598f971a346SBryan Cantrill 		return (error);
2599f971a346SBryan Cantrill 
2600f971a346SBryan Cantrill 	lwp = pnp->pr_common->prc_thread->t_lwp;
2601f971a346SBryan Cantrill 
2602f971a346SBryan Cantrill 	if (lwp->lwp_spymaster == NULL) {
2603f971a346SBryan Cantrill 		prunlock(pnp);
2604f971a346SBryan Cantrill 		return (0);
2605f971a346SBryan Cantrill 	}
2606f971a346SBryan Cantrill 
2607f971a346SBryan Cantrill 	psinfo_kto32(lwp->lwp_spymaster, &psinfo);
2608f971a346SBryan Cantrill 	prunlock(pnp);
2609f971a346SBryan Cantrill 
2610f971a346SBryan Cantrill 	return (pr_uioread(&psinfo, sizeof (psinfo), uiop));
2611f971a346SBryan Cantrill }
2612f971a346SBryan Cantrill 
26137c478bd9Sstevel@tonic-gate #if defined(__sparc)
26147c478bd9Sstevel@tonic-gate static int
26157c478bd9Sstevel@tonic-gate pr_read_gwindows_32(prnode_t *pnp, uio_t *uiop)
26167c478bd9Sstevel@tonic-gate {
26177c478bd9Sstevel@tonic-gate 	proc_t *p;
26187c478bd9Sstevel@tonic-gate 	kthread_t *t;
26197c478bd9Sstevel@tonic-gate 	gwindows32_t *gwp;
26207c478bd9Sstevel@tonic-gate 	int error;
26217c478bd9Sstevel@tonic-gate 	size_t size;
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_GWINDOWS);
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate 	gwp = kmem_zalloc(sizeof (gwindows32_t), KM_SLEEP);
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
26287c478bd9Sstevel@tonic-gate 		goto out;
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
26317c478bd9Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
26347c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26357c478bd9Sstevel@tonic-gate 		error = EOVERFLOW;
26367c478bd9Sstevel@tonic-gate 		goto out;
26377c478bd9Sstevel@tonic-gate 	}
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	/*
26407c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock while touching the stack.
26417c478bd9Sstevel@tonic-gate 	 * The P_PR_LOCK flag prevents the lwp from
26427c478bd9Sstevel@tonic-gate 	 * disappearing while we do this.
26437c478bd9Sstevel@tonic-gate 	 */
26447c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
26457c478bd9Sstevel@tonic-gate 	if ((size = prnwindows(ttolwp(t))) != 0)
26467c478bd9Sstevel@tonic-gate 		size = sizeof (gwindows32_t) -
26477c478bd9Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW - size) * sizeof (struct rwindow32);
26487c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
26497c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
26507c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26517c478bd9Sstevel@tonic-gate 		goto out;
26527c478bd9Sstevel@tonic-gate 	}
26537c478bd9Sstevel@tonic-gate 	prgetwindows32(ttolwp(t), gwp);
26547c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
26557c478bd9Sstevel@tonic-gate 	prunlock(pnp);
26567c478bd9Sstevel@tonic-gate 
26577c478bd9Sstevel@tonic-gate 	error = pr_uioread(gwp, size, uiop);
26587c478bd9Sstevel@tonic-gate out:
26597c478bd9Sstevel@tonic-gate 	kmem_free(gwp, sizeof (gwindows32_t));
26607c478bd9Sstevel@tonic-gate 	return (error);
26617c478bd9Sstevel@tonic-gate }
26627c478bd9Sstevel@tonic-gate #endif	/* __sparc */
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate /* ARGSUSED */
26677c478bd9Sstevel@tonic-gate static int
26687c478bd9Sstevel@tonic-gate prread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
26697c478bd9Sstevel@tonic-gate {
26707c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
26757c478bd9Sstevel@tonic-gate 	/*
26767c478bd9Sstevel@tonic-gate 	 * What is read from the /proc files depends on the data
26777c478bd9Sstevel@tonic-gate 	 * model of the caller.  An LP64 process will see LP64
26787c478bd9Sstevel@tonic-gate 	 * data.  An ILP32 process will see ILP32 data.
26797c478bd9Sstevel@tonic-gate 	 */
26807c478bd9Sstevel@tonic-gate 	if (curproc->p_model == DATAMODEL_LP64)
26817c478bd9Sstevel@tonic-gate 		return (pr_read_function[pnp->pr_type](pnp, uiop));
26827c478bd9Sstevel@tonic-gate 	else
26837c478bd9Sstevel@tonic-gate 		return (pr_read_function_32[pnp->pr_type](pnp, uiop));
26847c478bd9Sstevel@tonic-gate #else
26857c478bd9Sstevel@tonic-gate 	return (pr_read_function[pnp->pr_type](pnp, uiop));
26867c478bd9Sstevel@tonic-gate #endif
26877c478bd9Sstevel@tonic-gate }
26887c478bd9Sstevel@tonic-gate 
26897c478bd9Sstevel@tonic-gate /* ARGSUSED */
26907c478bd9Sstevel@tonic-gate static int
26917c478bd9Sstevel@tonic-gate prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
26927c478bd9Sstevel@tonic-gate {
26937c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
26947c478bd9Sstevel@tonic-gate 	int old = 0;
26957c478bd9Sstevel@tonic-gate 	int error;
26967c478bd9Sstevel@tonic-gate 	ssize_t resid;
26977c478bd9Sstevel@tonic-gate 
26987c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate 	/*
27017c478bd9Sstevel@tonic-gate 	 * Only a handful of /proc files are writable, enumerate them here.
27027c478bd9Sstevel@tonic-gate 	 */
27037c478bd9Sstevel@tonic-gate 	switch (pnp->pr_type) {
27047c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:		/* directory write()s: visceral revulsion. */
27057c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_pidfile != NULL);
27067c478bd9Sstevel@tonic-gate 		/* use the underlying PR_PIDFILE to write the process */
27077c478bd9Sstevel@tonic-gate 		vp = pnp->pr_pidfile;
27087c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
27097c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_type == PR_PIDFILE);
27107c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
27117c478bd9Sstevel@tonic-gate 	case PR_PIDFILE:
27127c478bd9Sstevel@tonic-gate 	case PR_LWPIDFILE:
27137c478bd9Sstevel@tonic-gate 		old = 1;
27147c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
27157c478bd9Sstevel@tonic-gate 	case PR_AS:
27167c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) == 0) {
27177c478bd9Sstevel@tonic-gate 			proc_t *p = pnp->pr_common->prc_proc;
27187c478bd9Sstevel@tonic-gate 			struct as *as = p->p_as;
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SSYS) || as == &kas) {
27217c478bd9Sstevel@tonic-gate 				/*
27227c478bd9Sstevel@tonic-gate 				 * /proc I/O cannot be done to a system process.
27237c478bd9Sstevel@tonic-gate 				 */
27247c478bd9Sstevel@tonic-gate 				error = EIO;
27257c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
27267c478bd9Sstevel@tonic-gate 			} else if (curproc->p_model == DATAMODEL_ILP32 &&
27277c478bd9Sstevel@tonic-gate 			    PROCESS_NOT_32BIT(p)) {
27287c478bd9Sstevel@tonic-gate 				error = EOVERFLOW;
27297c478bd9Sstevel@tonic-gate #endif
27307c478bd9Sstevel@tonic-gate 			} else {
27317c478bd9Sstevel@tonic-gate 				/*
27327c478bd9Sstevel@tonic-gate 				 * See comments above (pr_read_pidfile)
27337c478bd9Sstevel@tonic-gate 				 * about this locking dance.
27347c478bd9Sstevel@tonic-gate 				 */
27357c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
27367c478bd9Sstevel@tonic-gate 				error = prusrio(p, UIO_WRITE, uiop, old);
27377c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
27387c478bd9Sstevel@tonic-gate 			}
27397c478bd9Sstevel@tonic-gate 			prunlock(pnp);
27407c478bd9Sstevel@tonic-gate 		}
27417c478bd9Sstevel@tonic-gate 		return (error);
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	case PR_CTL:
27447c478bd9Sstevel@tonic-gate 	case PR_LWPCTL:
27457c478bd9Sstevel@tonic-gate 		resid = uiop->uio_resid;
27467c478bd9Sstevel@tonic-gate 		/*
27477c478bd9Sstevel@tonic-gate 		 * Perform the action on the control file
27487c478bd9Sstevel@tonic-gate 		 * by passing curthreads credentials
27497c478bd9Sstevel@tonic-gate 		 * and not target process's credentials.
27507c478bd9Sstevel@tonic-gate 		 */
27517c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
27527c478bd9Sstevel@tonic-gate 		if (curproc->p_model == DATAMODEL_ILP32)
27537c478bd9Sstevel@tonic-gate 			error = prwritectl32(vp, uiop, CRED());
27547c478bd9Sstevel@tonic-gate 		else
27557c478bd9Sstevel@tonic-gate 			error = prwritectl(vp, uiop, CRED());
27567c478bd9Sstevel@tonic-gate #else
27577c478bd9Sstevel@tonic-gate 		error = prwritectl(vp, uiop, CRED());
27587c478bd9Sstevel@tonic-gate #endif
27597c478bd9Sstevel@tonic-gate 		/*
27607c478bd9Sstevel@tonic-gate 		 * This hack makes sure that the EINTR is passed
27617c478bd9Sstevel@tonic-gate 		 * all the way back to the caller's write() call.
27627c478bd9Sstevel@tonic-gate 		 */
27637c478bd9Sstevel@tonic-gate 		if (error == EINTR)
27647c478bd9Sstevel@tonic-gate 			uiop->uio_resid = resid;
27657c478bd9Sstevel@tonic-gate 		return (error);
27667c478bd9Sstevel@tonic-gate 
27677c478bd9Sstevel@tonic-gate 	default:
27687c478bd9Sstevel@tonic-gate 		return ((vp->v_type == VDIR)? EISDIR : EBADF);
27697c478bd9Sstevel@tonic-gate 	}
27707c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
27717c478bd9Sstevel@tonic-gate }
27727c478bd9Sstevel@tonic-gate 
27737c478bd9Sstevel@tonic-gate static int
2774da6c28aaSamw prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
2775da6c28aaSamw 	caller_context_t *ct)
27767c478bd9Sstevel@tonic-gate {
27777c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
27787c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
27797c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
27807c478bd9Sstevel@tonic-gate 	proc_t *p;
27817c478bd9Sstevel@tonic-gate 	struct as *as;
27827c478bd9Sstevel@tonic-gate 	int error;
27837c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
27847c478bd9Sstevel@tonic-gate 	timestruc_t now;
27857c478bd9Sstevel@tonic-gate 	extern uint_t nproc;
27867c478bd9Sstevel@tonic-gate 	int ngroups;
2787eb9dbf0cSRoger A. Faulkner 	int nsig;
27887c478bd9Sstevel@tonic-gate 
27897c478bd9Sstevel@tonic-gate 	/*
27907c478bd9Sstevel@tonic-gate 	 * This ugly bit of code allows us to keep both versions of this
27917c478bd9Sstevel@tonic-gate 	 * function from the same source.
27927c478bd9Sstevel@tonic-gate 	 */
27937c478bd9Sstevel@tonic-gate #ifdef _LP64
27947c478bd9Sstevel@tonic-gate 	int iam32bit = (curproc->p_model == DATAMODEL_ILP32);
27957c478bd9Sstevel@tonic-gate #define	PR_OBJSIZE(obj32, obj64)	\
27967c478bd9Sstevel@tonic-gate 	(iam32bit ? sizeof (obj32) : sizeof (obj64))
27977c478bd9Sstevel@tonic-gate #define	PR_OBJSPAN(obj32, obj64)	\
27987c478bd9Sstevel@tonic-gate 	(iam32bit ? LSPAN32(obj32) : LSPAN(obj64))
27997c478bd9Sstevel@tonic-gate #else
28007c478bd9Sstevel@tonic-gate #define	PR_OBJSIZE(obj32, obj64)	\
28017c478bd9Sstevel@tonic-gate 	(sizeof (obj64))
28027c478bd9Sstevel@tonic-gate #define	PR_OBJSPAN(obj32, obj64)	\
28037c478bd9Sstevel@tonic-gate 	(LSPAN(obj64))
28047c478bd9Sstevel@tonic-gate #endif
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 	/*
28077c478bd9Sstevel@tonic-gate 	 * Return all the attributes.  Should be refined
28087c478bd9Sstevel@tonic-gate 	 * so that it returns only those asked for.
28097c478bd9Sstevel@tonic-gate 	 * Most of this is complete fakery anyway.
28107c478bd9Sstevel@tonic-gate 	 */
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	/*
28137c478bd9Sstevel@tonic-gate 	 * For files in the /proc/<pid>/object directory,
28147c478bd9Sstevel@tonic-gate 	 * return the attributes of the underlying object.
28157c478bd9Sstevel@tonic-gate 	 * For files in the /proc/<pid>/fd directory,
28167c478bd9Sstevel@tonic-gate 	 * return the attributes of the underlying file, but
28177c478bd9Sstevel@tonic-gate 	 * make it look inaccessible if it is not a regular file.
28187c478bd9Sstevel@tonic-gate 	 * Make directories look like symlinks.
28197c478bd9Sstevel@tonic-gate 	 */
28207c478bd9Sstevel@tonic-gate 	switch (type) {
28217c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
28227c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
28237c478bd9Sstevel@tonic-gate 		if (!(flags & ATTR_REAL))
28247c478bd9Sstevel@tonic-gate 			break;
28257c478bd9Sstevel@tonic-gate 		/* restrict full knowledge of the attributes to owner or root */
2826da6c28aaSamw 		if ((error = praccess(vp, 0, 0, cr, ct)) != 0)
28277c478bd9Sstevel@tonic-gate 			return (error);
28287c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
28297c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
28307c478bd9Sstevel@tonic-gate 	case PR_FD:
28317c478bd9Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
2832da6c28aaSamw 		error = VOP_GETATTR(rvp, vap, flags, cr, ct);
28337c478bd9Sstevel@tonic-gate 		if (error)
28347c478bd9Sstevel@tonic-gate 			return (error);
28357c478bd9Sstevel@tonic-gate 		if (type == PR_FD) {
28367c478bd9Sstevel@tonic-gate 			if (rvp->v_type != VREG && rvp->v_type != VDIR)
28377c478bd9Sstevel@tonic-gate 				vap->va_mode = 0;
28387c478bd9Sstevel@tonic-gate 			else
28397c478bd9Sstevel@tonic-gate 				vap->va_mode &= pnp->pr_mode;
28407c478bd9Sstevel@tonic-gate 		}
28417c478bd9Sstevel@tonic-gate 		if (type == PR_OBJECT)
28427c478bd9Sstevel@tonic-gate 			vap->va_mode &= 07555;
28437c478bd9Sstevel@tonic-gate 		if (rvp->v_type == VDIR && !(flags & ATTR_REAL)) {
28447c478bd9Sstevel@tonic-gate 			vap->va_type = VLNK;
28457c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
28467c478bd9Sstevel@tonic-gate 			vap->va_nlink = 1;
28477c478bd9Sstevel@tonic-gate 		}
28487c478bd9Sstevel@tonic-gate 		return (0);
28497c478bd9Sstevel@tonic-gate 	default:
28507c478bd9Sstevel@tonic-gate 		break;
28517c478bd9Sstevel@tonic-gate 	}
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate 	bzero(vap, sizeof (*vap));
28547c478bd9Sstevel@tonic-gate 	/*
28557c478bd9Sstevel@tonic-gate 	 * Large Files: Internally proc now uses VPROC to indicate
28567c478bd9Sstevel@tonic-gate 	 * a proc file. Since we have been returning VREG through
28577c478bd9Sstevel@tonic-gate 	 * VOP_GETATTR() until now, we continue to do this so as
28587c478bd9Sstevel@tonic-gate 	 * not to break apps depending on this return value.
28597c478bd9Sstevel@tonic-gate 	 */
28607c478bd9Sstevel@tonic-gate 	vap->va_type = (vp->v_type == VPROC) ? VREG : vp->v_type;
28617c478bd9Sstevel@tonic-gate 	vap->va_mode = pnp->pr_mode;
28627c478bd9Sstevel@tonic-gate 	vap->va_fsid = vp->v_vfsp->vfs_dev;
28637c478bd9Sstevel@tonic-gate 	vap->va_blksize = DEV_BSIZE;
28647c478bd9Sstevel@tonic-gate 	vap->va_rdev = 0;
28657c478bd9Sstevel@tonic-gate 	vap->va_seq = 0;
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR) {
28687c478bd9Sstevel@tonic-gate 		vap->va_uid = 0;
28697c478bd9Sstevel@tonic-gate 		vap->va_gid = 0;
28707c478bd9Sstevel@tonic-gate 		vap->va_nlink = nproc + 2;
28717c478bd9Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)PRROOTINO;
28727c478bd9Sstevel@tonic-gate 		gethrestime(&now);
28737c478bd9Sstevel@tonic-gate 		vap->va_atime = vap->va_mtime = vap->va_ctime = now;
28747c478bd9Sstevel@tonic-gate 		vap->va_size = (v.v_proc + 2) * PRSDSIZE;
28757c478bd9Sstevel@tonic-gate 		vap->va_nblocks = btod(vap->va_size);
28767c478bd9Sstevel@tonic-gate 		return (0);
28777c478bd9Sstevel@tonic-gate 	}
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	/*
28807c478bd9Sstevel@tonic-gate 	 * /proc/<pid>/self is a symbolic link, and has no prcommon member
28817c478bd9Sstevel@tonic-gate 	 */
28827c478bd9Sstevel@tonic-gate 	if (type == PR_SELF) {
28837c478bd9Sstevel@tonic-gate 		vap->va_uid = crgetruid(CRED());
28847c478bd9Sstevel@tonic-gate 		vap->va_gid = crgetrgid(CRED());
28857c478bd9Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)PR_SELF;
28867c478bd9Sstevel@tonic-gate 		gethrestime(&now);
28877c478bd9Sstevel@tonic-gate 		vap->va_atime = vap->va_mtime = vap->va_ctime = now;
28887c478bd9Sstevel@tonic-gate 		vap->va_nlink = 1;
28897c478bd9Sstevel@tonic-gate 		vap->va_type = VLNK;
28907c478bd9Sstevel@tonic-gate 		vap->va_size = 0;
28917c478bd9Sstevel@tonic-gate 		return (0);
28927c478bd9Sstevel@tonic-gate 	}
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
28957c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
28967c478bd9Sstevel@tonic-gate 	if (p == NULL)
28977c478bd9Sstevel@tonic-gate 		return (ENOENT);
28987c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
29017c478bd9Sstevel@tonic-gate 	vap->va_uid = crgetruid(p->p_cred);
29027c478bd9Sstevel@tonic-gate 	vap->va_gid = crgetrgid(p->p_cred);
29037c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	vap->va_nlink = 1;
29067c478bd9Sstevel@tonic-gate 	vap->va_nodeid = pnp->pr_ino? pnp->pr_ino :
29077c478bd9Sstevel@tonic-gate 	    pmkino(pcp->prc_tslot, pcp->prc_slot, pnp->pr_type);
29087c478bd9Sstevel@tonic-gate 	if ((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot != -1) {
29097c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
29107c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_sec =
29117c478bd9Sstevel@tonic-gate 		    p->p_lwpdir[pcp->prc_tslot].ld_entry->le_start;
29127c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec =
29137c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_nsec = 0;
29147c478bd9Sstevel@tonic-gate 	} else {
29157c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
29167c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
29177c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_sec = up->u_start.tv_sec;
29187c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec =
29197c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_nsec = up->u_start.tv_nsec;
29207c478bd9Sstevel@tonic-gate 	}
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate 	switch (type) {
29237c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:
29247c478bd9Sstevel@tonic-gate 		/* va_nlink: count 'lwp', 'object' and 'fd' directory links */
29257c478bd9Sstevel@tonic-gate 		vap->va_nlink = 5;
29267c478bd9Sstevel@tonic-gate 		vap->va_size = sizeof (piddir);
29277c478bd9Sstevel@tonic-gate 		break;
29287c478bd9Sstevel@tonic-gate 	case PR_OBJECTDIR:
29297c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
29307c478bd9Sstevel@tonic-gate 			vap->va_size = 2 * PRSDSIZE;
29317c478bd9Sstevel@tonic-gate 		else {
29327c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
2933*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
29347c478bd9Sstevel@tonic-gate 			if (as->a_updatedir)
29357c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
29367c478bd9Sstevel@tonic-gate 			vap->va_size = (as->a_sizedir + 2) * PRSDSIZE;
2937*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
29387c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
29397c478bd9Sstevel@tonic-gate 		}
29407c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
29417c478bd9Sstevel@tonic-gate 		break;
29427c478bd9Sstevel@tonic-gate 	case PR_PATHDIR:
29437c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
29447c478bd9Sstevel@tonic-gate 			vap->va_size = (P_FINFO(p)->fi_nfiles + 4) * PRSDSIZE;
29457c478bd9Sstevel@tonic-gate 		else {
29467c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
2947*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
29487c478bd9Sstevel@tonic-gate 			if (as->a_updatedir)
29497c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
29507c478bd9Sstevel@tonic-gate 			vap->va_size = (as->a_sizedir + 4 +
29517c478bd9Sstevel@tonic-gate 			    P_FINFO(p)->fi_nfiles) * PRSDSIZE;
2952*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
29537c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
29547c478bd9Sstevel@tonic-gate 		}
29557c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
29567c478bd9Sstevel@tonic-gate 		break;
29577c478bd9Sstevel@tonic-gate 	case PR_PATH:
29587c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
29597c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
29607c478bd9Sstevel@tonic-gate 	case PR_CT:
29617c478bd9Sstevel@tonic-gate 		vap->va_type = VLNK;
29627c478bd9Sstevel@tonic-gate 		vap->va_size = 0;
29637c478bd9Sstevel@tonic-gate 		break;
29647c478bd9Sstevel@tonic-gate 	case PR_FDDIR:
29657c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
29667c478bd9Sstevel@tonic-gate 		vap->va_size = (P_FINFO(p)->fi_nfiles + 2) * PRSDSIZE;
29677c478bd9Sstevel@tonic-gate 		break;
29687c478bd9Sstevel@tonic-gate 	case PR_LWPDIR:
29697c478bd9Sstevel@tonic-gate 		/*
29707c478bd9Sstevel@tonic-gate 		 * va_nlink: count each lwp as a directory link.
29717c478bd9Sstevel@tonic-gate 		 * va_size: size of p_lwpdir + 2
29727c478bd9Sstevel@tonic-gate 		 */
29737c478bd9Sstevel@tonic-gate 		vap->va_nlink = p->p_lwpcnt + p->p_zombcnt + 2;
29747c478bd9Sstevel@tonic-gate 		vap->va_size = (p->p_lwpdir_sz + 2) * PRSDSIZE;
29757c478bd9Sstevel@tonic-gate 		break;
29767c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
29777c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
29787c478bd9Sstevel@tonic-gate 		vap->va_size = sizeof (lwpiddir);
29797c478bd9Sstevel@tonic-gate 		break;
29807c478bd9Sstevel@tonic-gate 	case PR_CTDIR:
29817c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
29827c478bd9Sstevel@tonic-gate 		vap->va_size = (avl_numnodes(&p->p_ct_held) + 2) * PRSDSIZE;
29837c478bd9Sstevel@tonic-gate 		break;
29847c478bd9Sstevel@tonic-gate 	case PR_TMPLDIR:
29857c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
29867c478bd9Sstevel@tonic-gate 		vap->va_size = (ct_ntypes + 2) * PRSDSIZE;
29877c478bd9Sstevel@tonic-gate 		break;
29887c478bd9Sstevel@tonic-gate 	case PR_AS:
29897c478bd9Sstevel@tonic-gate 	case PR_PIDFILE:
29907c478bd9Sstevel@tonic-gate 	case PR_LWPIDFILE:
29917c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
29927c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
299340688216SSudheer A 		else
299440688216SSudheer A 			vap->va_size = as->a_resvsize;
29957c478bd9Sstevel@tonic-gate 		break;
29967c478bd9Sstevel@tonic-gate 	case PR_STATUS:
29977c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(pstatus32_t, pstatus_t);
29987c478bd9Sstevel@tonic-gate 		break;
29997c478bd9Sstevel@tonic-gate 	case PR_LSTATUS:
30007c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
30017c478bd9Sstevel@tonic-gate 		    p->p_lwpcnt * PR_OBJSPAN(lwpstatus32_t, lwpstatus_t);
30027c478bd9Sstevel@tonic-gate 		break;
30037c478bd9Sstevel@tonic-gate 	case PR_PSINFO:
30047c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(psinfo32_t, psinfo_t);
30057c478bd9Sstevel@tonic-gate 		break;
30067c478bd9Sstevel@tonic-gate 	case PR_LPSINFO:
30077c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
30087c478bd9Sstevel@tonic-gate 		    (p->p_lwpcnt + p->p_zombcnt) *
30097c478bd9Sstevel@tonic-gate 		    PR_OBJSPAN(lwpsinfo32_t, lwpsinfo_t);
30107c478bd9Sstevel@tonic-gate 		break;
30117c478bd9Sstevel@tonic-gate 	case PR_MAP:
30127c478bd9Sstevel@tonic-gate 	case PR_RMAP:
30137c478bd9Sstevel@tonic-gate 	case PR_XMAP:
30147c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
30157c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
30167c478bd9Sstevel@tonic-gate 		else {
30177c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3018*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
30197c478bd9Sstevel@tonic-gate 			if (type == PR_MAP)
30207c478bd9Sstevel@tonic-gate 				vap->va_mtime = as->a_updatetime;
30217c478bd9Sstevel@tonic-gate 			if (type == PR_XMAP)
30227c478bd9Sstevel@tonic-gate 				vap->va_size = prnsegs(as, 0) *
30237c478bd9Sstevel@tonic-gate 				    PR_OBJSIZE(prxmap32_t, prxmap_t);
30247c478bd9Sstevel@tonic-gate 			else
30257c478bd9Sstevel@tonic-gate 				vap->va_size = prnsegs(as, type == PR_RMAP) *
30267c478bd9Sstevel@tonic-gate 				    PR_OBJSIZE(prmap32_t, prmap_t);
3027*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
30287c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
30297c478bd9Sstevel@tonic-gate 		}
30307c478bd9Sstevel@tonic-gate 		break;
30317c478bd9Sstevel@tonic-gate 	case PR_CRED:
30327c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_crlock);
30337c478bd9Sstevel@tonic-gate 		vap->va_size = sizeof (prcred_t);
30347c478bd9Sstevel@tonic-gate 		ngroups = crgetngroups(p->p_cred);
30357c478bd9Sstevel@tonic-gate 		if (ngroups > 1)
30367c478bd9Sstevel@tonic-gate 			vap->va_size += (ngroups - 1) * sizeof (gid_t);
30377c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
30387c478bd9Sstevel@tonic-gate 		break;
30397c478bd9Sstevel@tonic-gate 	case PR_PRIV:
30407c478bd9Sstevel@tonic-gate 		vap->va_size = prgetprivsize();
30417c478bd9Sstevel@tonic-gate 		break;
30427c478bd9Sstevel@tonic-gate 	case PR_SIGACT:
3043eb9dbf0cSRoger A. Faulkner 		nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
3044eb9dbf0cSRoger A. Faulkner 		vap->va_size = (nsig-1) *
30457c478bd9Sstevel@tonic-gate 		    PR_OBJSIZE(struct sigaction32, struct sigaction);
30467c478bd9Sstevel@tonic-gate 		break;
30477c478bd9Sstevel@tonic-gate 	case PR_AUXV:
30487c478bd9Sstevel@tonic-gate 		vap->va_size = __KERN_NAUXV_IMPL * PR_OBJSIZE(auxv32_t, auxv_t);
30497c478bd9Sstevel@tonic-gate 		break;
30507c478bd9Sstevel@tonic-gate #if defined(__x86)
30517c478bd9Sstevel@tonic-gate 	case PR_LDT:
30526e092be7SVamsi Nagineni 		mutex_exit(&p->p_lock);
30537c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_ldtlock);
30547c478bd9Sstevel@tonic-gate 		vap->va_size = prnldt(p) * sizeof (struct ssd);
30557c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_ldtlock);
30566e092be7SVamsi Nagineni 		mutex_enter(&p->p_lock);
30577c478bd9Sstevel@tonic-gate 		break;
30587c478bd9Sstevel@tonic-gate #endif
30597c478bd9Sstevel@tonic-gate 	case PR_USAGE:
30607c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prusage32_t, prusage_t);
30617c478bd9Sstevel@tonic-gate 		break;
30627c478bd9Sstevel@tonic-gate 	case PR_LUSAGE:
30637c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
30647c478bd9Sstevel@tonic-gate 		    (p->p_lwpcnt + 1) * PR_OBJSPAN(prusage32_t, prusage_t);
30657c478bd9Sstevel@tonic-gate 		break;
30667c478bd9Sstevel@tonic-gate 	case PR_PAGEDATA:
30677c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
30687c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
30697c478bd9Sstevel@tonic-gate 		else {
30707c478bd9Sstevel@tonic-gate 			/*
30717c478bd9Sstevel@tonic-gate 			 * We can drop p->p_lock before grabbing the
30727c478bd9Sstevel@tonic-gate 			 * address space lock because p->p_as will not
30737c478bd9Sstevel@tonic-gate 			 * change while the process is marked P_PR_LOCK.
30747c478bd9Sstevel@tonic-gate 			 */
30757c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3076*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
30777c478bd9Sstevel@tonic-gate #ifdef _LP64
30787c478bd9Sstevel@tonic-gate 			vap->va_size = iam32bit?
30797c478bd9Sstevel@tonic-gate 			    prpdsize32(as) : prpdsize(as);
30807c478bd9Sstevel@tonic-gate #else
30817c478bd9Sstevel@tonic-gate 			vap->va_size = prpdsize(as);
30827c478bd9Sstevel@tonic-gate #endif
3083*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
30847c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
30857c478bd9Sstevel@tonic-gate 		}
30867c478bd9Sstevel@tonic-gate 		break;
30877c478bd9Sstevel@tonic-gate 	case PR_OPAGEDATA:
30887c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
30897c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
30907c478bd9Sstevel@tonic-gate 		else {
30917c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3092*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
30937c478bd9Sstevel@tonic-gate #ifdef _LP64
30947c478bd9Sstevel@tonic-gate 			vap->va_size = iam32bit?
30957c478bd9Sstevel@tonic-gate 			    oprpdsize32(as) : oprpdsize(as);
30967c478bd9Sstevel@tonic-gate #else
30977c478bd9Sstevel@tonic-gate 			vap->va_size = oprpdsize(as);
30987c478bd9Sstevel@tonic-gate #endif
3099*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
31007c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
31017c478bd9Sstevel@tonic-gate 		}
31027c478bd9Sstevel@tonic-gate 		break;
31037c478bd9Sstevel@tonic-gate 	case PR_WATCH:
31047c478bd9Sstevel@tonic-gate 		vap->va_size = avl_numnodes(&p->p_warea) *
31057c478bd9Sstevel@tonic-gate 		    PR_OBJSIZE(prwatch32_t, prwatch_t);
31067c478bd9Sstevel@tonic-gate 		break;
31077c478bd9Sstevel@tonic-gate 	case PR_LWPSTATUS:
31087c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(lwpstatus32_t, lwpstatus_t);
31097c478bd9Sstevel@tonic-gate 		break;
31107c478bd9Sstevel@tonic-gate 	case PR_LWPSINFO:
31117c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(lwpsinfo32_t, lwpsinfo_t);
31127c478bd9Sstevel@tonic-gate 		break;
31137c478bd9Sstevel@tonic-gate 	case PR_LWPUSAGE:
31147c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prusage32_t, prusage_t);
31157c478bd9Sstevel@tonic-gate 		break;
31167c478bd9Sstevel@tonic-gate 	case PR_XREGS:
31177c478bd9Sstevel@tonic-gate 		if (prhasx(p))
31187c478bd9Sstevel@tonic-gate 			vap->va_size = prgetprxregsize(p);
31197c478bd9Sstevel@tonic-gate 		else
31207c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
31217c478bd9Sstevel@tonic-gate 		break;
3122f971a346SBryan Cantrill 	case PR_SPYMASTER:
3123f971a346SBryan Cantrill 		if (pnp->pr_common->prc_thread->t_lwp->lwp_spymaster != NULL) {
3124f971a346SBryan Cantrill 			vap->va_size = PR_OBJSIZE(psinfo32_t, psinfo_t);
3125f971a346SBryan Cantrill 		} else {
3126f971a346SBryan Cantrill 			vap->va_size = 0;
3127f971a346SBryan Cantrill 		}
3128f971a346SBryan Cantrill 		break;
31297c478bd9Sstevel@tonic-gate #if defined(__sparc)
31307c478bd9Sstevel@tonic-gate 	case PR_GWINDOWS:
31317c478bd9Sstevel@tonic-gate 	{
31327c478bd9Sstevel@tonic-gate 		kthread_t *t;
31337c478bd9Sstevel@tonic-gate 		int n;
31347c478bd9Sstevel@tonic-gate 
31357c478bd9Sstevel@tonic-gate 		/*
31367c478bd9Sstevel@tonic-gate 		 * If there is no lwp then just make the size zero.
31377c478bd9Sstevel@tonic-gate 		 * This can happen if the lwp exits between the VOP_LOOKUP()
31387c478bd9Sstevel@tonic-gate 		 * of the /proc/<pid>/lwp/<lwpid>/gwindows file and the
31397c478bd9Sstevel@tonic-gate 		 * VOP_GETATTR() of the resulting vnode.
31407c478bd9Sstevel@tonic-gate 		 */
31417c478bd9Sstevel@tonic-gate 		if ((t = pcp->prc_thread) == NULL) {
31427c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
31437c478bd9Sstevel@tonic-gate 			break;
31447c478bd9Sstevel@tonic-gate 		}
31457c478bd9Sstevel@tonic-gate 		/*
31467c478bd9Sstevel@tonic-gate 		 * Drop p->p_lock while touching the stack.
31477c478bd9Sstevel@tonic-gate 		 * The P_PR_LOCK flag prevents the lwp from
31487c478bd9Sstevel@tonic-gate 		 * disappearing while we do this.
31497c478bd9Sstevel@tonic-gate 		 */
31507c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
31517c478bd9Sstevel@tonic-gate 		if ((n = prnwindows(ttolwp(t))) == 0)
31527c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
31537c478bd9Sstevel@tonic-gate 		else
31547c478bd9Sstevel@tonic-gate 			vap->va_size = PR_OBJSIZE(gwindows32_t, gwindows_t) -
31557c478bd9Sstevel@tonic-gate 			    (SPARC_MAXREGWINDOW - n) *
31567c478bd9Sstevel@tonic-gate 			    PR_OBJSIZE(struct rwindow32, struct rwindow);
31577c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
31587c478bd9Sstevel@tonic-gate 		break;
31597c478bd9Sstevel@tonic-gate 	}
31607c478bd9Sstevel@tonic-gate 	case PR_ASRS:
31617c478bd9Sstevel@tonic-gate #ifdef _LP64
31627c478bd9Sstevel@tonic-gate 		if (p->p_model == DATAMODEL_LP64)
31637c478bd9Sstevel@tonic-gate 			vap->va_size = sizeof (asrset_t);
31647c478bd9Sstevel@tonic-gate 		else
31657c478bd9Sstevel@tonic-gate #endif
31667c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
31677c478bd9Sstevel@tonic-gate 		break;
31687c478bd9Sstevel@tonic-gate #endif
31697c478bd9Sstevel@tonic-gate 	case PR_CTL:
31707c478bd9Sstevel@tonic-gate 	case PR_LWPCTL:
31717c478bd9Sstevel@tonic-gate 	default:
31727c478bd9Sstevel@tonic-gate 		vap->va_size = 0;
31737c478bd9Sstevel@tonic-gate 		break;
31747c478bd9Sstevel@tonic-gate 	}
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 	prunlock(pnp);
31777c478bd9Sstevel@tonic-gate 	vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
31787c478bd9Sstevel@tonic-gate 	return (0);
31797c478bd9Sstevel@tonic-gate }
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate static int
3182da6c28aaSamw praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
31837c478bd9Sstevel@tonic-gate {
31847c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
31857c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
31867c478bd9Sstevel@tonic-gate 	int vmode;
31877c478bd9Sstevel@tonic-gate 	vtype_t vtype;
31887c478bd9Sstevel@tonic-gate 	proc_t *p;
31897c478bd9Sstevel@tonic-gate 	int error = 0;
31907c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
31917c478bd9Sstevel@tonic-gate 	vnode_t *xvp;
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate 	if ((mode & VWRITE) && vn_is_readonly(vp))
31947c478bd9Sstevel@tonic-gate 		return (EROFS);
31957c478bd9Sstevel@tonic-gate 
31967c478bd9Sstevel@tonic-gate 	switch (type) {
31977c478bd9Sstevel@tonic-gate 	case PR_PROCDIR:
31987c478bd9Sstevel@tonic-gate 		break;
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
32017c478bd9Sstevel@tonic-gate 	case PR_FD:
32027c478bd9Sstevel@tonic-gate 		/*
32037c478bd9Sstevel@tonic-gate 		 * Disallow write access to the underlying objects.
32047c478bd9Sstevel@tonic-gate 		 * Disallow access to underlying non-regular-file fds.
32057c478bd9Sstevel@tonic-gate 		 * Disallow access to fds with other than existing open modes.
32067c478bd9Sstevel@tonic-gate 		 */
32077c478bd9Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
32087c478bd9Sstevel@tonic-gate 		vtype = rvp->v_type;
32097c478bd9Sstevel@tonic-gate 		vmode = pnp->pr_mode;
32107c478bd9Sstevel@tonic-gate 		if ((type == PR_OBJECT && (mode & VWRITE)) ||
32117c478bd9Sstevel@tonic-gate 		    (type == PR_FD && vtype != VREG && vtype != VDIR) ||
32127c478bd9Sstevel@tonic-gate 		    (type == PR_FD && (vmode & mode) != mode &&
32137c478bd9Sstevel@tonic-gate 		    secpolicy_proc_access(cr) != 0))
32147c478bd9Sstevel@tonic-gate 			return (EACCES);
3215da6c28aaSamw 		return (VOP_ACCESS(rvp, mode, flags, cr, ct));
32167c478bd9Sstevel@tonic-gate 
32177c478bd9Sstevel@tonic-gate 	case PR_PSINFO:		/* these files can be read by anyone */
32187c478bd9Sstevel@tonic-gate 	case PR_LPSINFO:
32197c478bd9Sstevel@tonic-gate 	case PR_LWPSINFO:
32207c478bd9Sstevel@tonic-gate 	case PR_LWPDIR:
32217c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
32227c478bd9Sstevel@tonic-gate 	case PR_USAGE:
32237c478bd9Sstevel@tonic-gate 	case PR_LUSAGE:
32247c478bd9Sstevel@tonic-gate 	case PR_LWPUSAGE:
32257c478bd9Sstevel@tonic-gate 		p = pr_p_lock(pnp);
32267c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
32277c478bd9Sstevel@tonic-gate 		if (p == NULL)
32287c478bd9Sstevel@tonic-gate 			return (ENOENT);
32297c478bd9Sstevel@tonic-gate 		prunlock(pnp);
32307c478bd9Sstevel@tonic-gate 		break;
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 	default:
32337c478bd9Sstevel@tonic-gate 		/*
32347c478bd9Sstevel@tonic-gate 		 * Except for the world-readable files above,
32357c478bd9Sstevel@tonic-gate 		 * only /proc/pid exists if the process is a zombie.
32367c478bd9Sstevel@tonic-gate 		 */
32377c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp,
32387c478bd9Sstevel@tonic-gate 		    (type == PR_PIDDIR)? ZYES : ZNO)) != 0)
32397c478bd9Sstevel@tonic-gate 			return (error);
32407c478bd9Sstevel@tonic-gate 		p = pnp->pr_common->prc_proc;
32417c478bd9Sstevel@tonic-gate 		if (p != curproc)
32427c478bd9Sstevel@tonic-gate 			error = priv_proc_cred_perm(cr, p, NULL, mode);
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate 		if (error != 0 || p == curproc || (p->p_flag & SSYS) ||
3245ddf7fe95Scasper 		    p->p_as == &kas || (xvp = p->p_exec) == NULL) {
32467c478bd9Sstevel@tonic-gate 			prunlock(pnp);
32477c478bd9Sstevel@tonic-gate 		} else {
32487c478bd9Sstevel@tonic-gate 			/*
32497c478bd9Sstevel@tonic-gate 			 * Determine if the process's executable is readable.
3250ddf7fe95Scasper 			 * We have to drop p->p_lock before the secpolicy
3251ddf7fe95Scasper 			 * and VOP operation.
32527c478bd9Sstevel@tonic-gate 			 */
32537c478bd9Sstevel@tonic-gate 			VN_HOLD(xvp);
32547c478bd9Sstevel@tonic-gate 			prunlock(pnp);
3255ddf7fe95Scasper 			if (secpolicy_proc_access(cr) != 0)
3256da6c28aaSamw 				error = VOP_ACCESS(xvp, VREAD, 0, cr, ct);
32577c478bd9Sstevel@tonic-gate 			VN_RELE(xvp);
32587c478bd9Sstevel@tonic-gate 		}
32597c478bd9Sstevel@tonic-gate 		if (error)
32607c478bd9Sstevel@tonic-gate 			return (error);
32617c478bd9Sstevel@tonic-gate 		break;
32627c478bd9Sstevel@tonic-gate 	}
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 	if (type == PR_CURDIR || type == PR_ROOTDIR) {
32657c478bd9Sstevel@tonic-gate 		/*
32667c478bd9Sstevel@tonic-gate 		 * Final access check on the underlying directory vnode.
32677c478bd9Sstevel@tonic-gate 		 */
3268da6c28aaSamw 		return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr, ct));
32697c478bd9Sstevel@tonic-gate 	}
32707c478bd9Sstevel@tonic-gate 
32717c478bd9Sstevel@tonic-gate 	/*
32727c478bd9Sstevel@tonic-gate 	 * Visceral revulsion:  For compatibility with old /proc,
32737c478bd9Sstevel@tonic-gate 	 * allow the /proc/<pid> directory to be opened for writing.
32747c478bd9Sstevel@tonic-gate 	 */
32757c478bd9Sstevel@tonic-gate 	vmode = pnp->pr_mode;
32767c478bd9Sstevel@tonic-gate 	if (type == PR_PIDDIR)
32777c478bd9Sstevel@tonic-gate 		vmode |= VWRITE;
32787c478bd9Sstevel@tonic-gate 	if ((vmode & mode) != mode)
32797c478bd9Sstevel@tonic-gate 		error = secpolicy_proc_access(cr);
32807c478bd9Sstevel@tonic-gate 	return (error);
32817c478bd9Sstevel@tonic-gate }
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate /*
32847c478bd9Sstevel@tonic-gate  * Array of lookup functions, indexed by /proc file type.
32857c478bd9Sstevel@tonic-gate  */
32867c478bd9Sstevel@tonic-gate static vnode_t *pr_lookup_notdir(), *pr_lookup_procdir(), *pr_lookup_piddir(),
32877c478bd9Sstevel@tonic-gate 	*pr_lookup_objectdir(), *pr_lookup_lwpdir(), *pr_lookup_lwpiddir(),
32887c478bd9Sstevel@tonic-gate 	*pr_lookup_fddir(), *pr_lookup_pathdir(), *pr_lookup_tmpldir(),
32897c478bd9Sstevel@tonic-gate 	*pr_lookup_ctdir();
32907c478bd9Sstevel@tonic-gate 
32917c478bd9Sstevel@tonic-gate static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
32927c478bd9Sstevel@tonic-gate 	pr_lookup_procdir,	/* /proc				*/
32937c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/self				*/
32947c478bd9Sstevel@tonic-gate 	pr_lookup_piddir,	/* /proc/<pid>				*/
32957c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/as			*/
32967c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/ctl			*/
32977c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/status			*/
32987c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lstatus			*/
32997c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/psinfo			*/
33007c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lpsinfo			*/
33017c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/map			*/
33027c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/rmap			*/
33037c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/xmap			*/
33047c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/cred			*/
33057c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/sigact			*/
33067c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/auxv			*/
33077c478bd9Sstevel@tonic-gate #if defined(__x86)
33087c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/ldt			*/
33097c478bd9Sstevel@tonic-gate #endif
33107c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/usage			*/
33117c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lusage			*/
33127c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/pagedata			*/
33137c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/watch			*/
33147c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/cwd			*/
33157c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/root			*/
33167c478bd9Sstevel@tonic-gate 	pr_lookup_fddir,	/* /proc/<pid>/fd			*/
33177c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/fd/nn			*/
33187c478bd9Sstevel@tonic-gate 	pr_lookup_objectdir,	/* /proc/<pid>/object			*/
33197c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/object/xxx		*/
33207c478bd9Sstevel@tonic-gate 	pr_lookup_lwpdir,	/* /proc/<pid>/lwp			*/
33217c478bd9Sstevel@tonic-gate 	pr_lookup_lwpiddir,	/* /proc/<pid>/lwp/<lwpid>		*/
33227c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
33237c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
33247c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
33257c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
33267c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
33277c478bd9Sstevel@tonic-gate 	pr_lookup_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
33287c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
3329f971a346SBryan Cantrill 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
33307c478bd9Sstevel@tonic-gate #if defined(__sparc)
33317c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
33327c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
33337c478bd9Sstevel@tonic-gate #endif
33347c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/priv			*/
33357c478bd9Sstevel@tonic-gate 	pr_lookup_pathdir,	/* /proc/<pid>/path			*/
33367c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/path/xxx			*/
33377c478bd9Sstevel@tonic-gate 	pr_lookup_ctdir,	/* /proc/<pid>/contracts		*/
33387c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/contracts/<ctid>		*/
33397c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* old process file			*/
33407c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* old lwp file				*/
33417c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* old pagedata file			*/
33427c478bd9Sstevel@tonic-gate };
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate static int
33457c478bd9Sstevel@tonic-gate prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
3346da6c28aaSamw 	int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
3347da6c28aaSamw 	int *direntflags, pathname_t *realpnp)
33487c478bd9Sstevel@tonic-gate {
33497c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(dp);
33507c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
33517c478bd9Sstevel@tonic-gate 	int error;
33527c478bd9Sstevel@tonic-gate 
33537c478bd9Sstevel@tonic-gate 	ASSERT(dp->v_type == VDIR);
33547c478bd9Sstevel@tonic-gate 	ASSERT(type < PR_NFILES);
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate 	if (type != PR_PROCDIR && strcmp(comp, "..") == 0) {
33577c478bd9Sstevel@tonic-gate 		VN_HOLD(pnp->pr_parent);
33587c478bd9Sstevel@tonic-gate 		*vpp = pnp->pr_parent;
33597c478bd9Sstevel@tonic-gate 		return (0);
33607c478bd9Sstevel@tonic-gate 	}
33617c478bd9Sstevel@tonic-gate 
33627c478bd9Sstevel@tonic-gate 	if (*comp == '\0' ||
33637c478bd9Sstevel@tonic-gate 	    strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) {
33647c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
33657c478bd9Sstevel@tonic-gate 		*vpp = dp;
33667c478bd9Sstevel@tonic-gate 		return (0);
33677c478bd9Sstevel@tonic-gate 	}
33687c478bd9Sstevel@tonic-gate 
33697c478bd9Sstevel@tonic-gate 	switch (type) {
33707c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
33717c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
33727c478bd9Sstevel@tonic-gate 		/* restrict lookup permission to owner or root */
3373da6c28aaSamw 		if ((error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
33747c478bd9Sstevel@tonic-gate 			return (error);
33757c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
33767c478bd9Sstevel@tonic-gate 	case PR_FD:
33777c478bd9Sstevel@tonic-gate 		dp = pnp->pr_realvp;
3378da6c28aaSamw 		return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr, ct,
3379da6c28aaSamw 		    direntflags, realpnp));
33807c478bd9Sstevel@tonic-gate 	default:
33817c478bd9Sstevel@tonic-gate 		break;
33827c478bd9Sstevel@tonic-gate 	}
33837c478bd9Sstevel@tonic-gate 
33847c478bd9Sstevel@tonic-gate 	if ((type == PR_OBJECTDIR || type == PR_FDDIR || type == PR_PATHDIR) &&
3385da6c28aaSamw 	    (error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
33867c478bd9Sstevel@tonic-gate 		return (error);
33877c478bd9Sstevel@tonic-gate 
3388da6c28aaSamw 	/* XXX - Do we need to pass ct, direntflags, or realpnp? */
33897c478bd9Sstevel@tonic-gate 	*vpp = (pr_lookup_function[type](dp, comp));
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate 	return ((*vpp == NULL) ? ENOENT : 0);
33927c478bd9Sstevel@tonic-gate }
33937c478bd9Sstevel@tonic-gate 
33947c478bd9Sstevel@tonic-gate /* ARGSUSED */
33957c478bd9Sstevel@tonic-gate static int
33967c478bd9Sstevel@tonic-gate prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
3397da6c28aaSamw 	int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
3398da6c28aaSamw 	vsecattr_t *vsecp)
33997c478bd9Sstevel@tonic-gate {
34007c478bd9Sstevel@tonic-gate 	int error;
34017c478bd9Sstevel@tonic-gate 
3402da6c28aaSamw 	if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr,
3403da6c28aaSamw 	    ct, NULL, NULL)) != 0) {
34047c478bd9Sstevel@tonic-gate 		if (error == ENOENT)	/* can't O_CREAT nonexistent files */
34057c478bd9Sstevel@tonic-gate 			error = EACCES;		/* unwriteable directories */
34067c478bd9Sstevel@tonic-gate 	} else {
34077c478bd9Sstevel@tonic-gate 		if (excl == EXCL)			/* O_EXCL */
34087c478bd9Sstevel@tonic-gate 			error = EEXIST;
34097c478bd9Sstevel@tonic-gate 		else if (vap->va_mask & AT_SIZE) {	/* O_TRUNC */
34107c478bd9Sstevel@tonic-gate 			vnode_t *vp = *vpp;
34117c478bd9Sstevel@tonic-gate 			uint_t mask;
34127c478bd9Sstevel@tonic-gate 
34137c478bd9Sstevel@tonic-gate 			if (vp->v_type == VDIR)
34147c478bd9Sstevel@tonic-gate 				error = EISDIR;
34157c478bd9Sstevel@tonic-gate 			else if (vp->v_type != VPROC ||
34167c478bd9Sstevel@tonic-gate 			    VTOP(vp)->pr_type != PR_FD)
34177c478bd9Sstevel@tonic-gate 				error = EACCES;
34187c478bd9Sstevel@tonic-gate 			else {		/* /proc/<pid>/fd/<n> */
34197c478bd9Sstevel@tonic-gate 				vp = VTOP(vp)->pr_realvp;
34207c478bd9Sstevel@tonic-gate 				mask = vap->va_mask;
34217c478bd9Sstevel@tonic-gate 				vap->va_mask = AT_SIZE;
3422da6c28aaSamw 				error = VOP_SETATTR(vp, vap, 0, cr, ct);
34237c478bd9Sstevel@tonic-gate 				vap->va_mask = mask;
34247c478bd9Sstevel@tonic-gate 			}
34257c478bd9Sstevel@tonic-gate 		}
34267c478bd9Sstevel@tonic-gate 		if (error) {
34277c478bd9Sstevel@tonic-gate 			VN_RELE(*vpp);
34287c478bd9Sstevel@tonic-gate 			*vpp = NULL;
34297c478bd9Sstevel@tonic-gate 		}
34307c478bd9Sstevel@tonic-gate 	}
34317c478bd9Sstevel@tonic-gate 	return (error);
34327c478bd9Sstevel@tonic-gate }
34337c478bd9Sstevel@tonic-gate 
34347c478bd9Sstevel@tonic-gate /* ARGSUSED */
34357c478bd9Sstevel@tonic-gate static vnode_t *
34367c478bd9Sstevel@tonic-gate pr_lookup_notdir(vnode_t *dp, char *comp)
34377c478bd9Sstevel@tonic-gate {
34387c478bd9Sstevel@tonic-gate 	return (NULL);
34397c478bd9Sstevel@tonic-gate }
34407c478bd9Sstevel@tonic-gate 
34417c478bd9Sstevel@tonic-gate /*
34427c478bd9Sstevel@tonic-gate  * Find or construct a process vnode for the given pid.
34437c478bd9Sstevel@tonic-gate  */
34447c478bd9Sstevel@tonic-gate static vnode_t *
34457c478bd9Sstevel@tonic-gate pr_lookup_procdir(vnode_t *dp, char *comp)
34467c478bd9Sstevel@tonic-gate {
34477c478bd9Sstevel@tonic-gate 	pid_t pid;
34487c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
34497c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
34507c478bd9Sstevel@tonic-gate 	vnode_t *vp;
34517c478bd9Sstevel@tonic-gate 	proc_t *p;
34527c478bd9Sstevel@tonic-gate 	int c;
34537c478bd9Sstevel@tonic-gate 
34547c478bd9Sstevel@tonic-gate 	ASSERT(VTOP(dp)->pr_type == PR_PROCDIR);
34557c478bd9Sstevel@tonic-gate 
34567c478bd9Sstevel@tonic-gate 	if (strcmp(comp, "self") == 0) {
34577c478bd9Sstevel@tonic-gate 		pnp = prgetnode(dp, PR_SELF);
34587c478bd9Sstevel@tonic-gate 		return (PTOV(pnp));
34597c478bd9Sstevel@tonic-gate 	} else {
34607c478bd9Sstevel@tonic-gate 		pid = 0;
34617c478bd9Sstevel@tonic-gate 		while ((c = *comp++) != '\0') {
34627c478bd9Sstevel@tonic-gate 			if (c < '0' || c > '9')
34637c478bd9Sstevel@tonic-gate 				return (NULL);
34647c478bd9Sstevel@tonic-gate 			pid = 10*pid + c - '0';
34657c478bd9Sstevel@tonic-gate 			if (pid > maxpid)
34667c478bd9Sstevel@tonic-gate 				return (NULL);
34677c478bd9Sstevel@tonic-gate 		}
34687c478bd9Sstevel@tonic-gate 	}
34697c478bd9Sstevel@tonic-gate 
34707c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_PIDDIR);
34717c478bd9Sstevel@tonic-gate 
34727c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
34737c478bd9Sstevel@tonic-gate 	if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
34747c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
34757c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
34767c478bd9Sstevel@tonic-gate 		return (NULL);
34777c478bd9Sstevel@tonic-gate 	}
34787c478bd9Sstevel@tonic-gate 	ASSERT(p->p_stat != 0);
34797c478bd9Sstevel@tonic-gate 
3480ddf7fe95Scasper 	/* NOTE: we're holding pidlock across the policy call. */
34817c478bd9Sstevel@tonic-gate 	if (secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
3482ddf7fe95Scasper 		mutex_exit(&pidlock);
34837c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
34847c478bd9Sstevel@tonic-gate 		return (NULL);
34857c478bd9Sstevel@tonic-gate 	}
34867c478bd9Sstevel@tonic-gate 
3487ddf7fe95Scasper 	mutex_enter(&p->p_lock);
3488ddf7fe95Scasper 	mutex_exit(&pidlock);
3489ddf7fe95Scasper 
34907c478bd9Sstevel@tonic-gate 	/*
34917c478bd9Sstevel@tonic-gate 	 * If a process vnode already exists and it is not invalid
34927c478bd9Sstevel@tonic-gate 	 * and it was created by the current process and it belongs
34937c478bd9Sstevel@tonic-gate 	 * to the same /proc mount point as our parent vnode, then
34947c478bd9Sstevel@tonic-gate 	 * just use it and discard the newly-allocated prnode.
34957c478bd9Sstevel@tonic-gate 	 */
34967c478bd9Sstevel@tonic-gate 	for (vp = p->p_trace; vp != NULL; vp = VTOP(vp)->pr_next) {
34977c478bd9Sstevel@tonic-gate 		if (!(VTOP(VTOP(vp)->pr_pidfile)->pr_flags & PR_INVAL) &&
34987c478bd9Sstevel@tonic-gate 		    VTOP(vp)->pr_owner == curproc &&
34997c478bd9Sstevel@tonic-gate 		    vp->v_vfsp == dp->v_vfsp) {
35007c478bd9Sstevel@tonic-gate 			ASSERT(!(VTOP(vp)->pr_flags & PR_INVAL));
35017c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
35027c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
35037c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
35047c478bd9Sstevel@tonic-gate 			return (vp);
35057c478bd9Sstevel@tonic-gate 		}
35067c478bd9Sstevel@tonic-gate 	}
35077c478bd9Sstevel@tonic-gate 	pnp->pr_owner = curproc;
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate 	/*
35107c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
35117c478bd9Sstevel@tonic-gate 	 * Finish the job.
35127c478bd9Sstevel@tonic-gate 	 */
35137c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;	/* the newly-allocated prcommon struct */
35147c478bd9Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
35157c478bd9Sstevel@tonic-gate 		/* discard the new prcommon and use the existing prcommon */
35167c478bd9Sstevel@tonic-gate 		prfreecommon(pcp);
35177c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
35187c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
35197c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt > 0);
35207c478bd9Sstevel@tonic-gate 		pcp->prc_refcnt++;
35217c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
35227c478bd9Sstevel@tonic-gate 		pnp->pr_common = pcp;
35237c478bd9Sstevel@tonic-gate 	} else {
35247c478bd9Sstevel@tonic-gate 		/* initialize the new prcommon struct */
35257c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || p->p_as == &kas)
35267c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_SYS;
35277c478bd9Sstevel@tonic-gate 		if (p->p_stat == SZOMB)
35287c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
35297c478bd9Sstevel@tonic-gate 		pcp->prc_proc = p;
35307c478bd9Sstevel@tonic-gate 		pcp->prc_datamodel = p->p_model;
35317c478bd9Sstevel@tonic-gate 		pcp->prc_pid = p->p_pid;
35327c478bd9Sstevel@tonic-gate 		pcp->prc_slot = p->p_slot;
35337c478bd9Sstevel@tonic-gate 	}
35347c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = pcp;
35357c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
35367c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
35377c478bd9Sstevel@tonic-gate 	/*
35387c478bd9Sstevel@tonic-gate 	 * Link in the old, invalid directory vnode so we
35397c478bd9Sstevel@tonic-gate 	 * can later determine the last close of the file.
35407c478bd9Sstevel@tonic-gate 	 */
35417c478bd9Sstevel@tonic-gate 	pnp->pr_next = p->p_trace;
35427c478bd9Sstevel@tonic-gate 	p->p_trace = dp = PTOV(pnp);
35437c478bd9Sstevel@tonic-gate 
35447c478bd9Sstevel@tonic-gate 	/*
35457c478bd9Sstevel@tonic-gate 	 * Kludge for old /proc: initialize the PR_PIDFILE as well.
35467c478bd9Sstevel@tonic-gate 	 */
35477c478bd9Sstevel@tonic-gate 	vp = pnp->pr_pidfile;
35487c478bd9Sstevel@tonic-gate 	pnp = VTOP(vp);
35497c478bd9Sstevel@tonic-gate 	pnp->pr_ino = ptoi(pcp->prc_pid);
35507c478bd9Sstevel@tonic-gate 	pnp->pr_common = pcp;
35517c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = pcp;
35527c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
35537c478bd9Sstevel@tonic-gate 	pnp->pr_next = p->p_plist;
35547c478bd9Sstevel@tonic-gate 	p->p_plist = vp;
35557c478bd9Sstevel@tonic-gate 
35567c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
35577c478bd9Sstevel@tonic-gate 	return (dp);
35587c478bd9Sstevel@tonic-gate }
35597c478bd9Sstevel@tonic-gate 
35607c478bd9Sstevel@tonic-gate static vnode_t *
35617c478bd9Sstevel@tonic-gate pr_lookup_piddir(vnode_t *dp, char *comp)
35627c478bd9Sstevel@tonic-gate {
35637c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
35647c478bd9Sstevel@tonic-gate 	vnode_t *vp;
35657c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
35667c478bd9Sstevel@tonic-gate 	proc_t *p;
35677c478bd9Sstevel@tonic-gate 	user_t *up;
35687c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
35697c478bd9Sstevel@tonic-gate 	int i;
35707c478bd9Sstevel@tonic-gate 	enum prnodetype type;
35717c478bd9Sstevel@tonic-gate 
35727c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_PIDDIR);
35737c478bd9Sstevel@tonic-gate 
35747c478bd9Sstevel@tonic-gate 	for (i = 0; i < NPIDDIRFILES; i++) {
35757c478bd9Sstevel@tonic-gate 		/* Skip "." and ".." */
35767c478bd9Sstevel@tonic-gate 		dirp = &piddir[i+2];
35777c478bd9Sstevel@tonic-gate 		if (strcmp(comp, dirp->d_name) == 0)
35787c478bd9Sstevel@tonic-gate 			break;
35797c478bd9Sstevel@tonic-gate 	}
35807c478bd9Sstevel@tonic-gate 
35817c478bd9Sstevel@tonic-gate 	if (i >= NPIDDIRFILES)
35827c478bd9Sstevel@tonic-gate 		return (NULL);
35837c478bd9Sstevel@tonic-gate 
35847c478bd9Sstevel@tonic-gate 	type = (int)dirp->d_ino;
35857c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, type);
35867c478bd9Sstevel@tonic-gate 
35877c478bd9Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
35887c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
35897c478bd9Sstevel@tonic-gate 	if (p == NULL) {
35907c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
35917c478bd9Sstevel@tonic-gate 		return (NULL);
35927c478bd9Sstevel@tonic-gate 	}
35937c478bd9Sstevel@tonic-gate 	if (dpnp->pr_pcommon->prc_flags & PRC_DESTROY) {
35947c478bd9Sstevel@tonic-gate 		switch (type) {
35957c478bd9Sstevel@tonic-gate 		case PR_PSINFO:
35967c478bd9Sstevel@tonic-gate 		case PR_USAGE:
35977c478bd9Sstevel@tonic-gate 			break;
35987c478bd9Sstevel@tonic-gate 		default:
35997c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
36007c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
36017c478bd9Sstevel@tonic-gate 			return (NULL);
36027c478bd9Sstevel@tonic-gate 		}
36037c478bd9Sstevel@tonic-gate 	}
36047c478bd9Sstevel@tonic-gate 
36057c478bd9Sstevel@tonic-gate 	switch (type) {
36067c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
36077c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
36087c478bd9Sstevel@tonic-gate 		up = PTOU(p);
36097c478bd9Sstevel@tonic-gate 		vp = (type == PR_CURDIR)? up->u_cdir :
36107c478bd9Sstevel@tonic-gate 		    (up->u_rdir? up->u_rdir : rootdir);
36117c478bd9Sstevel@tonic-gate 
36127c478bd9Sstevel@tonic-gate 		if (vp == NULL) {	/* can't happen? */
36137c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
36147c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
36157c478bd9Sstevel@tonic-gate 			return (NULL);
36167c478bd9Sstevel@tonic-gate 		}
36177c478bd9Sstevel@tonic-gate 		/*
36187c478bd9Sstevel@tonic-gate 		 * Fill in the prnode so future references will
36197c478bd9Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
36207c478bd9Sstevel@tonic-gate 		 */
36217c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
36227c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
36237c478bd9Sstevel@tonic-gate 		break;
36247c478bd9Sstevel@tonic-gate 	default:
36257c478bd9Sstevel@tonic-gate 		break;
36267c478bd9Sstevel@tonic-gate 	}
36277c478bd9Sstevel@tonic-gate 
36287c478bd9Sstevel@tonic-gate 	mutex_enter(&dpnp->pr_mutex);
36297c478bd9Sstevel@tonic-gate 
36307c478bd9Sstevel@tonic-gate 	if ((vp = dpnp->pr_files[i]) != NULL &&
36317c478bd9Sstevel@tonic-gate 	    !(VTOP(vp)->pr_flags & PR_INVAL)) {
36327c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
36337c478bd9Sstevel@tonic-gate 		mutex_exit(&dpnp->pr_mutex);
36347c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
36357c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
36367c478bd9Sstevel@tonic-gate 		return (vp);
36377c478bd9Sstevel@tonic-gate 	}
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	/*
36407c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
36417c478bd9Sstevel@tonic-gate 	 * Finish the job.
36427c478bd9Sstevel@tonic-gate 	 */
36437c478bd9Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
36447c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
36457c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
36467c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
36477c478bd9Sstevel@tonic-gate 	pnp->pr_index = i;
36487c478bd9Sstevel@tonic-gate 
36497c478bd9Sstevel@tonic-gate 	dpnp->pr_files[i] = vp = PTOV(pnp);
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate 	/*
36527c478bd9Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
36537c478bd9Sstevel@tonic-gate 	 */
36547c478bd9Sstevel@tonic-gate 	if (vp->v_type == VPROC) {
36557c478bd9Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
36567c478bd9Sstevel@tonic-gate 		p->p_plist = vp;
36577c478bd9Sstevel@tonic-gate 	}
36587c478bd9Sstevel@tonic-gate 	mutex_exit(&dpnp->pr_mutex);
36597c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
36607c478bd9Sstevel@tonic-gate 	return (vp);
36617c478bd9Sstevel@tonic-gate }
36627c478bd9Sstevel@tonic-gate 
36637c478bd9Sstevel@tonic-gate static vnode_t *
36647c478bd9Sstevel@tonic-gate pr_lookup_objectdir(vnode_t *dp, char *comp)
36657c478bd9Sstevel@tonic-gate {
36667c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
36677c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
36687c478bd9Sstevel@tonic-gate 	proc_t *p;
36697c478bd9Sstevel@tonic-gate 	struct seg *seg;
36707c478bd9Sstevel@tonic-gate 	struct as *as;
36717c478bd9Sstevel@tonic-gate 	vnode_t *vp;
36727c478bd9Sstevel@tonic-gate 	vattr_t vattr;
36737c478bd9Sstevel@tonic-gate 
36747c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_OBJECTDIR);
36757c478bd9Sstevel@tonic-gate 
36767c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_OBJECT);
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
36797c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
36807c478bd9Sstevel@tonic-gate 		return (NULL);
36817c478bd9Sstevel@tonic-gate 	}
36827c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
36837c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
36847c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
36857c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
36867c478bd9Sstevel@tonic-gate 		return (NULL);
36877c478bd9Sstevel@tonic-gate 	}
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 	/*
36907c478bd9Sstevel@tonic-gate 	 * We drop p_lock before grabbing the address space lock
36917c478bd9Sstevel@tonic-gate 	 * in order to avoid a deadlock with the clock thread.
36927c478bd9Sstevel@tonic-gate 	 * The process will not disappear and its address space
36937c478bd9Sstevel@tonic-gate 	 * will not change because it is marked P_PR_LOCK.
36947c478bd9Sstevel@tonic-gate 	 */
36957c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
3696*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_READER);
36977c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
36987c478bd9Sstevel@tonic-gate 		vp = NULL;
36997c478bd9Sstevel@tonic-gate 		goto out;
37007c478bd9Sstevel@tonic-gate 	}
37017c478bd9Sstevel@tonic-gate 	if (strcmp(comp, "a.out") == 0) {
37027c478bd9Sstevel@tonic-gate 		vp = p->p_exec;
37037c478bd9Sstevel@tonic-gate 		goto out;
37047c478bd9Sstevel@tonic-gate 	}
37057c478bd9Sstevel@tonic-gate 	do {
37067c478bd9Sstevel@tonic-gate 		/*
37077c478bd9Sstevel@tonic-gate 		 * Manufacture a filename for the "object" directory.
37087c478bd9Sstevel@tonic-gate 		 */
37097c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID|AT_NODEID;
37107c478bd9Sstevel@tonic-gate 		if (seg->s_ops == &segvn_ops &&
37117c478bd9Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
37127c478bd9Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
3713da6c28aaSamw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
37147c478bd9Sstevel@tonic-gate 			char name[64];
37157c478bd9Sstevel@tonic-gate 
37167c478bd9Sstevel@tonic-gate 			if (vp == p->p_exec)	/* "a.out" */
37177c478bd9Sstevel@tonic-gate 				continue;
37187c478bd9Sstevel@tonic-gate 			pr_object_name(name, vp, &vattr);
37197c478bd9Sstevel@tonic-gate 			if (strcmp(name, comp) == 0)
37207c478bd9Sstevel@tonic-gate 				goto out;
37217c478bd9Sstevel@tonic-gate 		}
37227c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
37237c478bd9Sstevel@tonic-gate 
37247c478bd9Sstevel@tonic-gate 	vp = NULL;
37257c478bd9Sstevel@tonic-gate out:
37267c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
37277c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
37287c478bd9Sstevel@tonic-gate 	}
3729*dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
37307c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
37317c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
37327c478bd9Sstevel@tonic-gate 
37337c478bd9Sstevel@tonic-gate 	if (vp == NULL)
37347c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
37357c478bd9Sstevel@tonic-gate 	else {
37367c478bd9Sstevel@tonic-gate 		/*
37377c478bd9Sstevel@tonic-gate 		 * Fill in the prnode so future references will
37387c478bd9Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
37397c478bd9Sstevel@tonic-gate 		 * Don't link this prnode into the list of all
37407c478bd9Sstevel@tonic-gate 		 * prnodes for the process; this is a one-use node.
37417c478bd9Sstevel@tonic-gate 		 * Its use is entirely to catch and fail opens for writing.
37427c478bd9Sstevel@tonic-gate 		 */
37437c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
37447c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
37457c478bd9Sstevel@tonic-gate 	}
37467c478bd9Sstevel@tonic-gate 
37477c478bd9Sstevel@tonic-gate 	return (vp);
37487c478bd9Sstevel@tonic-gate }
37497c478bd9Sstevel@tonic-gate 
37507c478bd9Sstevel@tonic-gate /*
37517c478bd9Sstevel@tonic-gate  * Find or construct an lwp vnode for the given lwpid.
37527c478bd9Sstevel@tonic-gate  */
37537c478bd9Sstevel@tonic-gate static vnode_t *
37547c478bd9Sstevel@tonic-gate pr_lookup_lwpdir(vnode_t *dp, char *comp)
37557c478bd9Sstevel@tonic-gate {
37567c478bd9Sstevel@tonic-gate 	id_t tid;	/* same type as t->t_tid */
37577c478bd9Sstevel@tonic-gate 	int want_agent;
37587c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
37597c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
37607c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
37617c478bd9Sstevel@tonic-gate 	vnode_t *vp;
37627c478bd9Sstevel@tonic-gate 	proc_t *p;
37637c478bd9Sstevel@tonic-gate 	kthread_t *t;
37647c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
37657c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
37667c478bd9Sstevel@tonic-gate 	int tslot;
37677c478bd9Sstevel@tonic-gate 	int c;
37687c478bd9Sstevel@tonic-gate 
37697c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_LWPDIR);
37707c478bd9Sstevel@tonic-gate 
37717c478bd9Sstevel@tonic-gate 	tid = 0;
37727c478bd9Sstevel@tonic-gate 	if (strcmp(comp, "agent") == 0)
37737c478bd9Sstevel@tonic-gate 		want_agent = 1;
37747c478bd9Sstevel@tonic-gate 	else {
37757c478bd9Sstevel@tonic-gate 		want_agent = 0;
37767c478bd9Sstevel@tonic-gate 		while ((c = *comp++) != '\0') {
37777c478bd9Sstevel@tonic-gate 			id_t otid;
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate 			if (c < '0' || c > '9')
37807c478bd9Sstevel@tonic-gate 				return (NULL);
37817c478bd9Sstevel@tonic-gate 			otid = tid;
37827c478bd9Sstevel@tonic-gate 			tid = 10*tid + c - '0';
37837c478bd9Sstevel@tonic-gate 			if (tid/10 != otid)	/* integer overflow */
37847c478bd9Sstevel@tonic-gate 				return (NULL);
37857c478bd9Sstevel@tonic-gate 		}
37867c478bd9Sstevel@tonic-gate 	}
37877c478bd9Sstevel@tonic-gate 
37887c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_LWPIDDIR);
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
37917c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
37927c478bd9Sstevel@tonic-gate 	if (p == NULL) {
37937c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
37947c478bd9Sstevel@tonic-gate 		return (NULL);
37957c478bd9Sstevel@tonic-gate 	}
37967c478bd9Sstevel@tonic-gate 
37977c478bd9Sstevel@tonic-gate 	if (want_agent) {
37987c478bd9Sstevel@tonic-gate 		if ((t = p->p_agenttp) == NULL)
37997c478bd9Sstevel@tonic-gate 			lep = NULL;
38007c478bd9Sstevel@tonic-gate 		else {
38017c478bd9Sstevel@tonic-gate 			tid = t->t_tid;
38027c478bd9Sstevel@tonic-gate 			tslot = t->t_dslot;
38037c478bd9Sstevel@tonic-gate 			lep = p->p_lwpdir[tslot].ld_entry;
38047c478bd9Sstevel@tonic-gate 		}
38057c478bd9Sstevel@tonic-gate 	} else {
38067c478bd9Sstevel@tonic-gate 		if ((ldp = lwp_hash_lookup(p, tid)) == NULL)
38077c478bd9Sstevel@tonic-gate 			lep = NULL;
38087c478bd9Sstevel@tonic-gate 		else {
38097c478bd9Sstevel@tonic-gate 			tslot = (int)(ldp - p->p_lwpdir);
38107c478bd9Sstevel@tonic-gate 			lep = ldp->ld_entry;
38117c478bd9Sstevel@tonic-gate 		}
38127c478bd9Sstevel@tonic-gate 	}
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate 	if (lep == NULL) {
38157c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
38167c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
38177c478bd9Sstevel@tonic-gate 		return (NULL);
38187c478bd9Sstevel@tonic-gate 	}
38197c478bd9Sstevel@tonic-gate 
38207c478bd9Sstevel@tonic-gate 	/*
38217c478bd9Sstevel@tonic-gate 	 * If an lwp vnode already exists and it is not invalid
38227c478bd9Sstevel@tonic-gate 	 * and it was created by the current process and it belongs
38237c478bd9Sstevel@tonic-gate 	 * to the same /proc mount point as our parent vnode, then
38247c478bd9Sstevel@tonic-gate 	 * just use it and discard the newly-allocated prnode.
38257c478bd9Sstevel@tonic-gate 	 */
38267c478bd9Sstevel@tonic-gate 	for (vp = lep->le_trace; vp != NULL; vp = VTOP(vp)->pr_next) {
38277c478bd9Sstevel@tonic-gate 		if (!(VTOP(vp)->pr_flags & PR_INVAL) &&
38287c478bd9Sstevel@tonic-gate 		    VTOP(vp)->pr_owner == curproc &&
38297c478bd9Sstevel@tonic-gate 		    vp->v_vfsp == dp->v_vfsp) {
38307c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
38317c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
38327c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
38337c478bd9Sstevel@tonic-gate 			return (vp);
38347c478bd9Sstevel@tonic-gate 		}
38357c478bd9Sstevel@tonic-gate 	}
38367c478bd9Sstevel@tonic-gate 	pnp->pr_owner = curproc;
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 	/*
38397c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
38407c478bd9Sstevel@tonic-gate 	 * Finish the job.
38417c478bd9Sstevel@tonic-gate 	 */
38427c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;	/* the newly-allocated prcommon struct */
38437c478bd9Sstevel@tonic-gate 	if ((vp = lep->le_trace) != NULL) {
38447c478bd9Sstevel@tonic-gate 		/* discard the new prcommon and use the existing prcommon */
38457c478bd9Sstevel@tonic-gate 		prfreecommon(pcp);
38467c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
38477c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
38487c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt > 0);
38497c478bd9Sstevel@tonic-gate 		pcp->prc_refcnt++;
38507c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
38517c478bd9Sstevel@tonic-gate 		pnp->pr_common = pcp;
38527c478bd9Sstevel@tonic-gate 	} else {
38537c478bd9Sstevel@tonic-gate 		/* initialize the new prcommon struct */
38547c478bd9Sstevel@tonic-gate 		pcp->prc_flags |= PRC_LWP;
38557c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || p->p_as == &kas)
38567c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_SYS;
38577c478bd9Sstevel@tonic-gate 		if ((t = lep->le_thread) == NULL)
38587c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
38597c478bd9Sstevel@tonic-gate 		pcp->prc_proc = p;
38607c478bd9Sstevel@tonic-gate 		pcp->prc_datamodel = dpnp->pr_pcommon->prc_datamodel;
38617c478bd9Sstevel@tonic-gate 		pcp->prc_pid = p->p_pid;
38627c478bd9Sstevel@tonic-gate 		pcp->prc_slot = p->p_slot;
38637c478bd9Sstevel@tonic-gate 		pcp->prc_thread = t;
38647c478bd9Sstevel@tonic-gate 		pcp->prc_tid = tid;
38657c478bd9Sstevel@tonic-gate 		pcp->prc_tslot = tslot;
38667c478bd9Sstevel@tonic-gate 	}
38677c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
38687c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
38697c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
38707c478bd9Sstevel@tonic-gate 	/*
38717c478bd9Sstevel@tonic-gate 	 * Link in the old, invalid directory vnode so we
38727c478bd9Sstevel@tonic-gate 	 * can later determine the last close of the file.
38737c478bd9Sstevel@tonic-gate 	 */
38747c478bd9Sstevel@tonic-gate 	pnp->pr_next = lep->le_trace;
38757c478bd9Sstevel@tonic-gate 	lep->le_trace = vp = PTOV(pnp);
38767c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
38777c478bd9Sstevel@tonic-gate 	return (vp);
38787c478bd9Sstevel@tonic-gate }
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate static vnode_t *
38817c478bd9Sstevel@tonic-gate pr_lookup_lwpiddir(vnode_t *dp, char *comp)
38827c478bd9Sstevel@tonic-gate {
38837c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
38847c478bd9Sstevel@tonic-gate 	vnode_t *vp;
38857c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
38867c478bd9Sstevel@tonic-gate 	proc_t *p;
38877c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
38887c478bd9Sstevel@tonic-gate 	int i;
38897c478bd9Sstevel@tonic-gate 	enum prnodetype type;
38907c478bd9Sstevel@tonic-gate 
38917c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_LWPIDDIR);
38927c478bd9Sstevel@tonic-gate 
38937c478bd9Sstevel@tonic-gate 	for (i = 0; i < NLWPIDDIRFILES; i++) {
38947c478bd9Sstevel@tonic-gate 		/* Skip "." and ".." */
38957c478bd9Sstevel@tonic-gate 		dirp = &lwpiddir[i+2];
38967c478bd9Sstevel@tonic-gate 		if (strcmp(comp, dirp->d_name) == 0)
38977c478bd9Sstevel@tonic-gate 			break;
38987c478bd9Sstevel@tonic-gate 	}
38997c478bd9Sstevel@tonic-gate 
39007c478bd9Sstevel@tonic-gate 	if (i >= NLWPIDDIRFILES)
39017c478bd9Sstevel@tonic-gate 		return (NULL);
39027c478bd9Sstevel@tonic-gate 
39037c478bd9Sstevel@tonic-gate 	type = (int)dirp->d_ino;
39047c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, type);
39057c478bd9Sstevel@tonic-gate 
39067c478bd9Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
39077c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
39087c478bd9Sstevel@tonic-gate 	if (p == NULL) {
39097c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
39107c478bd9Sstevel@tonic-gate 		return (NULL);
39117c478bd9Sstevel@tonic-gate 	}
39127c478bd9Sstevel@tonic-gate 	if (dpnp->pr_common->prc_flags & PRC_DESTROY) {
39137c478bd9Sstevel@tonic-gate 		/*
39147c478bd9Sstevel@tonic-gate 		 * Only the lwpsinfo file is present for zombie lwps.
39157c478bd9Sstevel@tonic-gate 		 * Nothing is present if the lwp has been reaped.
39167c478bd9Sstevel@tonic-gate 		 */
39177c478bd9Sstevel@tonic-gate 		if (dpnp->pr_common->prc_tslot == -1 ||
39187c478bd9Sstevel@tonic-gate 		    type != PR_LWPSINFO) {
39197c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
39207c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
39217c478bd9Sstevel@tonic-gate 			return (NULL);
39227c478bd9Sstevel@tonic-gate 		}
39237c478bd9Sstevel@tonic-gate 	}
39247c478bd9Sstevel@tonic-gate 
39257c478bd9Sstevel@tonic-gate #if defined(__sparc)
39267c478bd9Sstevel@tonic-gate 	/* the asrs file exists only for sparc v9 _LP64 processes */
39277c478bd9Sstevel@tonic-gate 	if (type == PR_ASRS && p->p_model != DATAMODEL_LP64) {
39287c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
39297c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
39307c478bd9Sstevel@tonic-gate 		return (NULL);
39317c478bd9Sstevel@tonic-gate 	}
39327c478bd9Sstevel@tonic-gate #endif
39337c478bd9Sstevel@tonic-gate 
39347c478bd9Sstevel@tonic-gate 	mutex_enter(&dpnp->pr_mutex);
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	if ((vp = dpnp->pr_files[i]) != NULL &&
39377c478bd9Sstevel@tonic-gate 	    !(VTOP(vp)->pr_flags & PR_INVAL)) {
39387c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
39397c478bd9Sstevel@tonic-gate 		mutex_exit(&dpnp->pr_mutex);
39407c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
39417c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
39427c478bd9Sstevel@tonic-gate 		return (vp);
39437c478bd9Sstevel@tonic-gate 	}
39447c478bd9Sstevel@tonic-gate 
39457c478bd9Sstevel@tonic-gate 	/*
39467c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
39477c478bd9Sstevel@tonic-gate 	 * Finish the job.
39487c478bd9Sstevel@tonic-gate 	 */
39497c478bd9Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
39507c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
39517c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
39527c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
39537c478bd9Sstevel@tonic-gate 	pnp->pr_index = i;
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate 	dpnp->pr_files[i] = vp = PTOV(pnp);
39567c478bd9Sstevel@tonic-gate 
39577c478bd9Sstevel@tonic-gate 	/*
39587c478bd9Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
39597c478bd9Sstevel@tonic-gate 	 */
39607c478bd9Sstevel@tonic-gate 	if (vp->v_type == VPROC) {
39617c478bd9Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
39627c478bd9Sstevel@tonic-gate 		p->p_plist = vp;
39637c478bd9Sstevel@tonic-gate 	}
39647c478bd9Sstevel@tonic-gate 	mutex_exit(&dpnp->pr_mutex);
39657c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
39667c478bd9Sstevel@tonic-gate 	return (vp);
39677c478bd9Sstevel@tonic-gate }
39687c478bd9Sstevel@tonic-gate 
39697c478bd9Sstevel@tonic-gate /*
39707c478bd9Sstevel@tonic-gate  * Lookup one of the process's open files.
39717c478bd9Sstevel@tonic-gate  */
39727c478bd9Sstevel@tonic-gate static vnode_t *
39737c478bd9Sstevel@tonic-gate pr_lookup_fddir(vnode_t *dp, char *comp)
39747c478bd9Sstevel@tonic-gate {
39757c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
39767c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
39777c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
39787c478bd9Sstevel@tonic-gate 	proc_t *p;
39797c478bd9Sstevel@tonic-gate 	file_t *fp;
39807c478bd9Sstevel@tonic-gate 	uint_t fd;
39817c478bd9Sstevel@tonic-gate 	int c;
39827c478bd9Sstevel@tonic-gate 	uf_entry_t *ufp;
39837c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_FDDIR);
39867c478bd9Sstevel@tonic-gate 
39877c478bd9Sstevel@tonic-gate 	fd = 0;
39887c478bd9Sstevel@tonic-gate 	while ((c = *comp++) != '\0') {
39897c478bd9Sstevel@tonic-gate 		int ofd;
39907c478bd9Sstevel@tonic-gate 		if (c < '0' || c > '9')
39917c478bd9Sstevel@tonic-gate 			return (NULL);
39927c478bd9Sstevel@tonic-gate 		ofd = fd;
39937c478bd9Sstevel@tonic-gate 		fd = 10*fd + c - '0';
39947c478bd9Sstevel@tonic-gate 		if (fd/10 != ofd)	/* integer overflow */
39957c478bd9Sstevel@tonic-gate 			return (NULL);
39967c478bd9Sstevel@tonic-gate 	}
39977c478bd9Sstevel@tonic-gate 
39987c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_FD);
39997c478bd9Sstevel@tonic-gate 
40007c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
40017c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
40027c478bd9Sstevel@tonic-gate 		return (NULL);
40037c478bd9Sstevel@tonic-gate 	}
40047c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
40057c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
40067c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
40077c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
40087c478bd9Sstevel@tonic-gate 		return (NULL);
40097c478bd9Sstevel@tonic-gate 	}
40107c478bd9Sstevel@tonic-gate 
40117c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
40127c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
40137c478bd9Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
40147c478bd9Sstevel@tonic-gate 	if (fd < fip->fi_nfiles) {
40157c478bd9Sstevel@tonic-gate 		UF_ENTER(ufp, fip, fd);
40167c478bd9Sstevel@tonic-gate 		if ((fp = ufp->uf_file) != NULL) {
40177c478bd9Sstevel@tonic-gate 			pnp->pr_mode = 07111;
40187c478bd9Sstevel@tonic-gate 			if (fp->f_flag & FREAD)
40197c478bd9Sstevel@tonic-gate 				pnp->pr_mode |= 0444;
40207c478bd9Sstevel@tonic-gate 			if (fp->f_flag & FWRITE)
40217c478bd9Sstevel@tonic-gate 				pnp->pr_mode |= 0222;
40227c478bd9Sstevel@tonic-gate 			vp = fp->f_vnode;
40237c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
40247c478bd9Sstevel@tonic-gate 		}
40257c478bd9Sstevel@tonic-gate 		UF_EXIT(ufp);
40267c478bd9Sstevel@tonic-gate 	}
40277c478bd9Sstevel@tonic-gate 	mutex_exit(&fip->fi_lock);
40287c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
40297c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
40307c478bd9Sstevel@tonic-gate 
40317c478bd9Sstevel@tonic-gate 	if (vp == NULL)
40327c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
40337c478bd9Sstevel@tonic-gate 	else {
40347c478bd9Sstevel@tonic-gate 		/*
40357c478bd9Sstevel@tonic-gate 		 * Fill in the prnode so future references will
40367c478bd9Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
40377c478bd9Sstevel@tonic-gate 		 * Don't link this prnode into the list of all
40387c478bd9Sstevel@tonic-gate 		 * prnodes for the process; this is a one-use node.
40397c478bd9Sstevel@tonic-gate 		 */
40407c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
40417c478bd9Sstevel@tonic-gate 		pnp->pr_parent = dp;		/* needed for prlookup */
40427c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
40437c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
40447c478bd9Sstevel@tonic-gate 		if (pnp->pr_realvp->v_type == VDIR)
40457c478bd9Sstevel@tonic-gate 			vp->v_type = VDIR;
40467c478bd9Sstevel@tonic-gate 	}
40477c478bd9Sstevel@tonic-gate 
40487c478bd9Sstevel@tonic-gate 	return (vp);
40497c478bd9Sstevel@tonic-gate }
40507c478bd9Sstevel@tonic-gate 
40517c478bd9Sstevel@tonic-gate static vnode_t *
40527c478bd9Sstevel@tonic-gate pr_lookup_pathdir(vnode_t *dp, char *comp)
40537c478bd9Sstevel@tonic-gate {
40547c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
40557c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
40567c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
40577c478bd9Sstevel@tonic-gate 	proc_t *p;
40587c478bd9Sstevel@tonic-gate 	uint_t fd, flags = 0;
40597c478bd9Sstevel@tonic-gate 	int c;
40607c478bd9Sstevel@tonic-gate 	uf_entry_t *ufp;
40617c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
40627c478bd9Sstevel@tonic-gate 	enum { NAME_FD, NAME_OBJECT, NAME_ROOT, NAME_CWD, NAME_UNKNOWN } type;
40637c478bd9Sstevel@tonic-gate 	char *tmp;
40647c478bd9Sstevel@tonic-gate 	int idx;
40657c478bd9Sstevel@tonic-gate 	struct seg *seg;
40667c478bd9Sstevel@tonic-gate 	struct as *as = NULL;
40677c478bd9Sstevel@tonic-gate 	vattr_t vattr;
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_PATHDIR);
40707c478bd9Sstevel@tonic-gate 
40717c478bd9Sstevel@tonic-gate 	/*
40727c478bd9Sstevel@tonic-gate 	 * First, check if this is a numeric entry, in which case we have a
40737c478bd9Sstevel@tonic-gate 	 * file descriptor.
40747c478bd9Sstevel@tonic-gate 	 */
40757c478bd9Sstevel@tonic-gate 	fd = 0;
40767c478bd9Sstevel@tonic-gate 	type = NAME_FD;
40777c478bd9Sstevel@tonic-gate 	tmp = comp;
40787c478bd9Sstevel@tonic-gate 	while ((c = *tmp++) != '\0') {
40797c478bd9Sstevel@tonic-gate 		int ofd;
40807c478bd9Sstevel@tonic-gate 		if (c < '0' || c > '9') {
40817c478bd9Sstevel@tonic-gate 			type = NAME_UNKNOWN;
40827c478bd9Sstevel@tonic-gate 			break;
40837c478bd9Sstevel@tonic-gate 		}
40847c478bd9Sstevel@tonic-gate 		ofd = fd;
40857c478bd9Sstevel@tonic-gate 		fd = 10*fd + c - '0';
40867c478bd9Sstevel@tonic-gate 		if (fd/10 != ofd) {	/* integer overflow */
40877c478bd9Sstevel@tonic-gate 			type = NAME_UNKNOWN;
40887c478bd9Sstevel@tonic-gate 			break;
40897c478bd9Sstevel@tonic-gate 		}
40907c478bd9Sstevel@tonic-gate 	}
40917c478bd9Sstevel@tonic-gate 
40927c478bd9Sstevel@tonic-gate 	/*
40937c478bd9Sstevel@tonic-gate 	 * Next, see if it is one of the special values {root, cwd}.
40947c478bd9Sstevel@tonic-gate 	 */
40957c478bd9Sstevel@tonic-gate 	if (type == NAME_UNKNOWN) {
40967c478bd9Sstevel@tonic-gate 		if (strcmp(comp, "root") == 0)
40977c478bd9Sstevel@tonic-gate 			type = NAME_ROOT;
40987c478bd9Sstevel@tonic-gate 		else if (strcmp(comp, "cwd") == 0)
40997c478bd9Sstevel@tonic-gate 			type = NAME_CWD;
41007c478bd9Sstevel@tonic-gate 	}
41017c478bd9Sstevel@tonic-gate 
41027c478bd9Sstevel@tonic-gate 	/*
41037c478bd9Sstevel@tonic-gate 	 * Grab the necessary data from the process
41047c478bd9Sstevel@tonic-gate 	 */
41057c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0)
41067c478bd9Sstevel@tonic-gate 		return (NULL);
41077c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
41107c478bd9Sstevel@tonic-gate 
41117c478bd9Sstevel@tonic-gate 	switch (type) {
41127c478bd9Sstevel@tonic-gate 	case NAME_ROOT:
41137c478bd9Sstevel@tonic-gate 		if ((vp = PTOU(p)->u_rdir) == NULL)
41147c478bd9Sstevel@tonic-gate 			vp = p->p_zone->zone_rootvp;
41157c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
41167c478bd9Sstevel@tonic-gate 		break;
41177c478bd9Sstevel@tonic-gate 	case NAME_CWD:
41187c478bd9Sstevel@tonic-gate 		vp = PTOU(p)->u_cdir;
41197c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
41207c478bd9Sstevel@tonic-gate 		break;
41217c478bd9Sstevel@tonic-gate 	default:
41227c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
41237c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
41247c478bd9Sstevel@tonic-gate 			return (NULL);
41257c478bd9Sstevel@tonic-gate 		}
41267c478bd9Sstevel@tonic-gate 	}
41277c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
41287c478bd9Sstevel@tonic-gate 
41297c478bd9Sstevel@tonic-gate 	/*
41307c478bd9Sstevel@tonic-gate 	 * Determine if this is an object entry
41317c478bd9Sstevel@tonic-gate 	 */
41327c478bd9Sstevel@tonic-gate 	if (type == NAME_UNKNOWN) {
41337c478bd9Sstevel@tonic-gate 		/*
41347c478bd9Sstevel@tonic-gate 		 * Start with the inode index immediately after the number of
41357c478bd9Sstevel@tonic-gate 		 * files.
41367c478bd9Sstevel@tonic-gate 		 */
41377c478bd9Sstevel@tonic-gate 		mutex_enter(&fip->fi_lock);
41387c478bd9Sstevel@tonic-gate 		idx = fip->fi_nfiles + 4;
41397c478bd9Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
41407c478bd9Sstevel@tonic-gate 
41417c478bd9Sstevel@tonic-gate 		if (strcmp(comp, "a.out") == 0) {
41427c478bd9Sstevel@tonic-gate 			if (p->p_execdir != NULL) {
41437c478bd9Sstevel@tonic-gate 				vp = p->p_execdir;
41447c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
41457c478bd9Sstevel@tonic-gate 				type = NAME_OBJECT;
41467c478bd9Sstevel@tonic-gate 				flags |= PR_AOUT;
41477c478bd9Sstevel@tonic-gate 			} else {
41487c478bd9Sstevel@tonic-gate 				vp = p->p_exec;
41497c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
41507c478bd9Sstevel@tonic-gate 				type = NAME_OBJECT;
41517c478bd9Sstevel@tonic-gate 			}
41527c478bd9Sstevel@tonic-gate 		} else {
4153*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_READER);
41547c478bd9Sstevel@tonic-gate 			if ((seg = AS_SEGFIRST(as)) != NULL) {
41557c478bd9Sstevel@tonic-gate 				do {
41567c478bd9Sstevel@tonic-gate 					/*
41577c478bd9Sstevel@tonic-gate 					 * Manufacture a filename for the
41587c478bd9Sstevel@tonic-gate 					 * "object" directory.
41597c478bd9Sstevel@tonic-gate 					 */
41607c478bd9Sstevel@tonic-gate 					vattr.va_mask = AT_FSID|AT_NODEID;
41617c478bd9Sstevel@tonic-gate 					if (seg->s_ops == &segvn_ops &&
41627c478bd9Sstevel@tonic-gate 					    SEGOP_GETVP(seg, seg->s_base, &vp)
41637c478bd9Sstevel@tonic-gate 					    == 0 &&
41647c478bd9Sstevel@tonic-gate 					    vp != NULL && vp->v_type == VREG &&
4165da6c28aaSamw 					    VOP_GETATTR(vp, &vattr, 0, CRED(),
4166da6c28aaSamw 					    NULL) == 0) {
41677c478bd9Sstevel@tonic-gate 						char name[64];
41687c478bd9Sstevel@tonic-gate 
41697c478bd9Sstevel@tonic-gate 						if (vp == p->p_exec)
41707c478bd9Sstevel@tonic-gate 							continue;
41717c478bd9Sstevel@tonic-gate 						idx++;
41727c478bd9Sstevel@tonic-gate 						pr_object_name(name, vp,
41737c478bd9Sstevel@tonic-gate 						    &vattr);
41747c478bd9Sstevel@tonic-gate 						if (strcmp(name, comp) == 0)
41757c478bd9Sstevel@tonic-gate 							break;
41767c478bd9Sstevel@tonic-gate 					}
41777c478bd9Sstevel@tonic-gate 				} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
41787c478bd9Sstevel@tonic-gate 			}
41797c478bd9Sstevel@tonic-gate 
41807c478bd9Sstevel@tonic-gate 			if (seg == NULL) {
41817c478bd9Sstevel@tonic-gate 				vp = NULL;
41827c478bd9Sstevel@tonic-gate 			} else {
41837c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
41847c478bd9Sstevel@tonic-gate 				type = NAME_OBJECT;
41857c478bd9Sstevel@tonic-gate 			}
41867c478bd9Sstevel@tonic-gate 
4187*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
41887c478bd9Sstevel@tonic-gate 		}
41897c478bd9Sstevel@tonic-gate 	}
41907c478bd9Sstevel@tonic-gate 
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 	switch (type) {
41937c478bd9Sstevel@tonic-gate 	case NAME_FD:
41947c478bd9Sstevel@tonic-gate 		mutex_enter(&fip->fi_lock);
41957c478bd9Sstevel@tonic-gate 		if (fd < fip->fi_nfiles) {
41967c478bd9Sstevel@tonic-gate 			UF_ENTER(ufp, fip, fd);
41977c478bd9Sstevel@tonic-gate 			if (ufp->uf_file != NULL) {
41987c478bd9Sstevel@tonic-gate 				vp = ufp->uf_file->f_vnode;
41997c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
42007c478bd9Sstevel@tonic-gate 			}
42017c478bd9Sstevel@tonic-gate 			UF_EXIT(ufp);
42027c478bd9Sstevel@tonic-gate 		}
42037c478bd9Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
42047c478bd9Sstevel@tonic-gate 		idx = fd + 4;
42057c478bd9Sstevel@tonic-gate 		break;
42067c478bd9Sstevel@tonic-gate 	case NAME_ROOT:
42077c478bd9Sstevel@tonic-gate 		idx = 2;
42087c478bd9Sstevel@tonic-gate 		break;
42097c478bd9Sstevel@tonic-gate 	case NAME_CWD:
42107c478bd9Sstevel@tonic-gate 		idx = 3;
42117c478bd9Sstevel@tonic-gate 		break;
42127c478bd9Sstevel@tonic-gate 	case NAME_OBJECT:
42137c478bd9Sstevel@tonic-gate 	case NAME_UNKNOWN:
42147c478bd9Sstevel@tonic-gate 		/* Nothing to do */
42157c478bd9Sstevel@tonic-gate 		break;
42167c478bd9Sstevel@tonic-gate 	}
42177c478bd9Sstevel@tonic-gate 
42187c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
42197c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
42207c478bd9Sstevel@tonic-gate 
42217c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
42227c478bd9Sstevel@tonic-gate 		pnp = prgetnode(dp, PR_PATH);
42237c478bd9Sstevel@tonic-gate 
42247c478bd9Sstevel@tonic-gate 		pnp->pr_flags |= flags;
42257c478bd9Sstevel@tonic-gate 		pnp->pr_common = dpnp->pr_common;
42267c478bd9Sstevel@tonic-gate 		pnp->pr_pcommon = dpnp->pr_pcommon;
42277c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
42287c478bd9Sstevel@tonic-gate 		pnp->pr_parent = dp;		/* needed for prlookup */
42297c478bd9Sstevel@tonic-gate 		pnp->pr_ino = pmkino(idx, dpnp->pr_common->prc_slot, PR_PATH);
42307c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
42317c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
42327c478bd9Sstevel@tonic-gate 		vp->v_type = VLNK;
42337c478bd9Sstevel@tonic-gate 	}
42347c478bd9Sstevel@tonic-gate 
42357c478bd9Sstevel@tonic-gate 	return (vp);
42367c478bd9Sstevel@tonic-gate }
42377c478bd9Sstevel@tonic-gate 
42387c478bd9Sstevel@tonic-gate /*
42397c478bd9Sstevel@tonic-gate  * Look up one of the process's active templates.
42407c478bd9Sstevel@tonic-gate  */
42417c478bd9Sstevel@tonic-gate static vnode_t *
42427c478bd9Sstevel@tonic-gate pr_lookup_tmpldir(vnode_t *dp, char *comp)
42437c478bd9Sstevel@tonic-gate {
42447c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
42457c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
42467c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
42477c478bd9Sstevel@tonic-gate 	proc_t *p;
42487c478bd9Sstevel@tonic-gate 	int i;
42497c478bd9Sstevel@tonic-gate 
42507c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_TMPLDIR);
42517c478bd9Sstevel@tonic-gate 
42527c478bd9Sstevel@tonic-gate 	for (i = 0; i < ct_ntypes; i++)
42537c478bd9Sstevel@tonic-gate 		if (strcmp(comp, ct_types[i]->ct_type_name) == 0)
42547c478bd9Sstevel@tonic-gate 			break;
42557c478bd9Sstevel@tonic-gate 	if (i == ct_ntypes)
42567c478bd9Sstevel@tonic-gate 		return (NULL);
42577c478bd9Sstevel@tonic-gate 
42587c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_TMPL);
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
42617c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
42627c478bd9Sstevel@tonic-gate 		return (NULL);
42637c478bd9Sstevel@tonic-gate 	}
42647c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
42657c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas ||
42667c478bd9Sstevel@tonic-gate 	    (dpnp->pr_common->prc_flags & (PRC_DESTROY | PRC_LWP)) != PRC_LWP) {
42677c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
42687c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
42697c478bd9Sstevel@tonic-gate 		return (NULL);
42707c478bd9Sstevel@tonic-gate 	}
42717c478bd9Sstevel@tonic-gate 	if (ttolwp(dpnp->pr_common->prc_thread)->lwp_ct_active[i] != NULL) {
42727c478bd9Sstevel@tonic-gate 		pnp->pr_common = dpnp->pr_common;
42737c478bd9Sstevel@tonic-gate 		pnp->pr_pcommon = dpnp->pr_pcommon;
42747c478bd9Sstevel@tonic-gate 		pnp->pr_parent = dp;
42757c478bd9Sstevel@tonic-gate 		pnp->pr_cttype = i;
42767c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
42777c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
42787c478bd9Sstevel@tonic-gate 	} else {
42797c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
42807c478bd9Sstevel@tonic-gate 	}
42817c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
42827c478bd9Sstevel@tonic-gate 
42837c478bd9Sstevel@tonic-gate 	return (vp);
42847c478bd9Sstevel@tonic-gate }
42857c478bd9Sstevel@tonic-gate 
42867c478bd9Sstevel@tonic-gate /*
42877c478bd9Sstevel@tonic-gate  * Look up one of the contracts owned by the process.
42887c478bd9Sstevel@tonic-gate  */
42897c478bd9Sstevel@tonic-gate static vnode_t *
42907c478bd9Sstevel@tonic-gate pr_lookup_ctdir(vnode_t *dp, char *comp)
42917c478bd9Sstevel@tonic-gate {
42927c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
42937c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
42947c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
42957c478bd9Sstevel@tonic-gate 	proc_t *p;
42967c478bd9Sstevel@tonic-gate 	id_t id = 0;
42977c478bd9Sstevel@tonic-gate 	contract_t *ct;
42987c478bd9Sstevel@tonic-gate 	int c;
42997c478bd9Sstevel@tonic-gate 
43007c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_CTDIR);
43017c478bd9Sstevel@tonic-gate 
43027c478bd9Sstevel@tonic-gate 	while ((c = *comp++) != '\0') {
43037c478bd9Sstevel@tonic-gate 		id_t oid;
43047c478bd9Sstevel@tonic-gate 		if (c < '0' || c > '9')
43057c478bd9Sstevel@tonic-gate 			return (NULL);
43067c478bd9Sstevel@tonic-gate 		oid = id;
43077c478bd9Sstevel@tonic-gate 		id = 10 * id + c - '0';
43087c478bd9Sstevel@tonic-gate 		if (id / 10 != oid)	/* integer overflow */
43097c478bd9Sstevel@tonic-gate 			return (NULL);
43107c478bd9Sstevel@tonic-gate 	}
43117c478bd9Sstevel@tonic-gate 
43127c478bd9Sstevel@tonic-gate 	/*
43137c478bd9Sstevel@tonic-gate 	 * Search all contracts; we'll filter below.
43147c478bd9Sstevel@tonic-gate 	 */
43157c478bd9Sstevel@tonic-gate 	ct = contract_ptr(id, GLOBAL_ZONEUNIQID);
43167c478bd9Sstevel@tonic-gate 	if (ct == NULL)
43177c478bd9Sstevel@tonic-gate 		return (NULL);
43187c478bd9Sstevel@tonic-gate 
43197c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_CT);
43207c478bd9Sstevel@tonic-gate 
43217c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
43227c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
43237c478bd9Sstevel@tonic-gate 		contract_rele(ct);
43247c478bd9Sstevel@tonic-gate 		return (NULL);
43257c478bd9Sstevel@tonic-gate 	}
43267c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
43277c478bd9Sstevel@tonic-gate 	/*
43287c478bd9Sstevel@tonic-gate 	 * We only allow lookups of contracts owned by this process, or,
43297c478bd9Sstevel@tonic-gate 	 * if we are zsched and this is a zone's procfs, contracts on
43307c478bd9Sstevel@tonic-gate 	 * stuff in the zone which are held by processes or contracts
43317c478bd9Sstevel@tonic-gate 	 * outside the zone.  (see logic in contract_status_common)
43327c478bd9Sstevel@tonic-gate 	 */
43337c478bd9Sstevel@tonic-gate 	if ((ct->ct_owner != p) &&
4334fa9e4066Sahrens 	    !(p == VTOZONE(dp)->zone_zsched && ct->ct_state < CTS_ORPHAN &&
4335fa9e4066Sahrens 	    VTOZONE(dp)->zone_uniqid == contract_getzuniqid(ct) &&
4336fa9e4066Sahrens 	    VTOZONE(dp)->zone_uniqid != GLOBAL_ZONEUNIQID &&
43377c478bd9Sstevel@tonic-gate 	    ct->ct_czuniqid == GLOBAL_ZONEUNIQID)) {
43387c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
43397c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
43407c478bd9Sstevel@tonic-gate 		contract_rele(ct);
43417c478bd9Sstevel@tonic-gate 		return (NULL);
43427c478bd9Sstevel@tonic-gate 	}
43437c478bd9Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
43447c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
43457c478bd9Sstevel@tonic-gate 	pnp->pr_contract = ct;
43467c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
43477c478bd9Sstevel@tonic-gate 	pnp->pr_ino = pmkino(id, pnp->pr_common->prc_slot, PR_CT);
43487c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
43497c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
43507c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate 	return (vp);
43537c478bd9Sstevel@tonic-gate }
43547c478bd9Sstevel@tonic-gate 
43557c478bd9Sstevel@tonic-gate /*
43567c478bd9Sstevel@tonic-gate  * Construct an lwp vnode for the old /proc interface.
43577c478bd9Sstevel@tonic-gate  * We stand on our head to make the /proc plumbing correct.
43587c478bd9Sstevel@tonic-gate  */
43597c478bd9Sstevel@tonic-gate vnode_t *
43607c478bd9Sstevel@tonic-gate prlwpnode(prnode_t *pnp, uint_t tid)
43617c478bd9Sstevel@tonic-gate {
43627c478bd9Sstevel@tonic-gate 	char comp[12];
43637c478bd9Sstevel@tonic-gate 	vnode_t *dp;
43647c478bd9Sstevel@tonic-gate 	vnode_t *vp;
43657c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
43667c478bd9Sstevel@tonic-gate 	proc_t *p;
43677c478bd9Sstevel@tonic-gate 
43687c478bd9Sstevel@tonic-gate 	/*
43697c478bd9Sstevel@tonic-gate 	 * Lookup the /proc/<pid>/lwp/<lwpid> directory vnode.
43707c478bd9Sstevel@tonic-gate 	 */
43717c478bd9Sstevel@tonic-gate 	if (pnp->pr_type == PR_PIDFILE) {
43727c478bd9Sstevel@tonic-gate 		dp = pnp->pr_parent;		/* /proc/<pid> */
43737c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
43747c478bd9Sstevel@tonic-gate 		vp = pr_lookup_piddir(dp, "lwp");
43757c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
43767c478bd9Sstevel@tonic-gate 		if ((dp = vp) == NULL)		/* /proc/<pid>/lwp */
43777c478bd9Sstevel@tonic-gate 			return (NULL);
43787c478bd9Sstevel@tonic-gate 	} else if (pnp->pr_type == PR_LWPIDFILE) {
43797c478bd9Sstevel@tonic-gate 		dp = pnp->pr_parent;		/* /proc/<pid>/lwp/<lwpid> */
43807c478bd9Sstevel@tonic-gate 		dp = VTOP(dp)->pr_parent;	/* /proc/<pid>/lwp */
43817c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
43827c478bd9Sstevel@tonic-gate 	} else {
43837c478bd9Sstevel@tonic-gate 		return (NULL);
43847c478bd9Sstevel@tonic-gate 	}
43857c478bd9Sstevel@tonic-gate 
43867c478bd9Sstevel@tonic-gate 	(void) pr_u32tos(tid, comp, sizeof (comp));
43877c478bd9Sstevel@tonic-gate 	vp = pr_lookup_lwpdir(dp, comp);
43887c478bd9Sstevel@tonic-gate 	VN_RELE(dp);
43897c478bd9Sstevel@tonic-gate 	if ((dp = vp) == NULL)
43907c478bd9Sstevel@tonic-gate 		return (NULL);
43917c478bd9Sstevel@tonic-gate 
43927c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_LWPIDFILE);
43937c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
43947c478bd9Sstevel@tonic-gate 
43957c478bd9Sstevel@tonic-gate 	/*
43967c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
43977c478bd9Sstevel@tonic-gate 	 * Finish the job.
43987c478bd9Sstevel@tonic-gate 	 */
43997c478bd9Sstevel@tonic-gate 	pcp = VTOP(dp)->pr_common;
44007c478bd9Sstevel@tonic-gate 	pnp->pr_ino = ptoi(pcp->prc_pid);
44017c478bd9Sstevel@tonic-gate 	pnp->pr_common = pcp;
44027c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = VTOP(dp)->pr_pcommon;
44037c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
44047c478bd9Sstevel@tonic-gate 	/*
44057c478bd9Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
44067c478bd9Sstevel@tonic-gate 	 */
44077c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
44087c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
44097c478bd9Sstevel@tonic-gate 	if (p == NULL) {
44107c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
44117c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
44127c478bd9Sstevel@tonic-gate 		vp = NULL;
44137c478bd9Sstevel@tonic-gate 	} else if (pcp->prc_thread == NULL) {
44147c478bd9Sstevel@tonic-gate 		prunlock(pnp);
44157c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
44167c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
44177c478bd9Sstevel@tonic-gate 		vp = NULL;
44187c478bd9Sstevel@tonic-gate 	} else {
44197c478bd9Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
44207c478bd9Sstevel@tonic-gate 		p->p_plist = vp;
44217c478bd9Sstevel@tonic-gate 		prunlock(pnp);
44227c478bd9Sstevel@tonic-gate 	}
44237c478bd9Sstevel@tonic-gate 
44247c478bd9Sstevel@tonic-gate 	return (vp);
44257c478bd9Sstevel@tonic-gate }
44267c478bd9Sstevel@tonic-gate 
44277c478bd9Sstevel@tonic-gate #if defined(DEBUG)
44287c478bd9Sstevel@tonic-gate 
44297c478bd9Sstevel@tonic-gate static	uint32_t nprnode;
44307c478bd9Sstevel@tonic-gate static	uint32_t nprcommon;
44317c478bd9Sstevel@tonic-gate 
44321a5e258fSJosef 'Jeff' Sipek #define	INCREMENT(x)	atomic_inc_32(&x);
44331a5e258fSJosef 'Jeff' Sipek #define	DECREMENT(x)	atomic_dec_32(&x);
44347c478bd9Sstevel@tonic-gate 
44357c478bd9Sstevel@tonic-gate #else
44367c478bd9Sstevel@tonic-gate 
44377c478bd9Sstevel@tonic-gate #define	INCREMENT(x)
44387c478bd9Sstevel@tonic-gate #define	DECREMENT(x)
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate /*
44437c478bd9Sstevel@tonic-gate  * New /proc vnode required; allocate it and fill in most of the fields.
44447c478bd9Sstevel@tonic-gate  */
44457c478bd9Sstevel@tonic-gate prnode_t *
44467c478bd9Sstevel@tonic-gate prgetnode(vnode_t *dp, prnodetype_t type)
44477c478bd9Sstevel@tonic-gate {
44487c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
44497c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
44507c478bd9Sstevel@tonic-gate 	vnode_t *vp;
44517c478bd9Sstevel@tonic-gate 	ulong_t nfiles;
44527c478bd9Sstevel@tonic-gate 
44537c478bd9Sstevel@tonic-gate 	INCREMENT(nprnode);
44547c478bd9Sstevel@tonic-gate 	pnp = kmem_zalloc(sizeof (prnode_t), KM_SLEEP);
44557c478bd9Sstevel@tonic-gate 
44567c478bd9Sstevel@tonic-gate 	mutex_init(&pnp->pr_mutex, NULL, MUTEX_DEFAULT, NULL);
44577c478bd9Sstevel@tonic-gate 	pnp->pr_type = type;
44587c478bd9Sstevel@tonic-gate 
44597c478bd9Sstevel@tonic-gate 	pnp->pr_vnode = vn_alloc(KM_SLEEP);
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
44627c478bd9Sstevel@tonic-gate 	vp->v_flag = VNOCACHE|VNOMAP|VNOSWAP|VNOMOUNT;
44637c478bd9Sstevel@tonic-gate 	vn_setops(vp, prvnodeops);
44647c478bd9Sstevel@tonic-gate 	vp->v_vfsp = dp->v_vfsp;
44657c478bd9Sstevel@tonic-gate 	vp->v_type = VPROC;
44667c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)pnp;
44677c478bd9Sstevel@tonic-gate 
44687c478bd9Sstevel@tonic-gate 	switch (type) {
44697c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:
44707c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
44717c478bd9Sstevel@tonic-gate 		/*
44727c478bd9Sstevel@tonic-gate 		 * We need a prcommon and a files array for each of these.
44737c478bd9Sstevel@tonic-gate 		 */
44747c478bd9Sstevel@tonic-gate 		INCREMENT(nprcommon);
44757c478bd9Sstevel@tonic-gate 
44767c478bd9Sstevel@tonic-gate 		pcp = kmem_zalloc(sizeof (prcommon_t), KM_SLEEP);
44777c478bd9Sstevel@tonic-gate 		pcp->prc_refcnt = 1;
44787c478bd9Sstevel@tonic-gate 		pnp->pr_common = pcp;
44797c478bd9Sstevel@tonic-gate 		mutex_init(&pcp->prc_mutex, NULL, MUTEX_DEFAULT, NULL);
44807c478bd9Sstevel@tonic-gate 		cv_init(&pcp->prc_wait, NULL, CV_DEFAULT, NULL);
44817c478bd9Sstevel@tonic-gate 
44827c478bd9Sstevel@tonic-gate 		nfiles = (type == PR_PIDDIR)? NPIDDIRFILES : NLWPIDDIRFILES;
44837c478bd9Sstevel@tonic-gate 		pnp->pr_files =
44847c478bd9Sstevel@tonic-gate 		    kmem_zalloc(nfiles * sizeof (vnode_t *), KM_SLEEP);
44857c478bd9Sstevel@tonic-gate 
44867c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
44877c478bd9Sstevel@tonic-gate 		/*
44887c478bd9Sstevel@tonic-gate 		 * Mode should be read-search by all, but we cannot so long
44897c478bd9Sstevel@tonic-gate 		 * as we must support compatibility mode with old /proc.
44907c478bd9Sstevel@tonic-gate 		 * Make /proc/<pid> be read by owner only, search by all.
44917c478bd9Sstevel@tonic-gate 		 * Make /proc/<pid>/lwp/<lwpid> read-search by all.  Also,
44927c478bd9Sstevel@tonic-gate 		 * set VDIROPEN on /proc/<pid> so it can be opened for writing.
44937c478bd9Sstevel@tonic-gate 		 */
44947c478bd9Sstevel@tonic-gate 		if (type == PR_PIDDIR) {
44957c478bd9Sstevel@tonic-gate 			/* kludge for old /proc interface */
44967c478bd9Sstevel@tonic-gate 			prnode_t *xpnp = prgetnode(dp, PR_PIDFILE);
44977c478bd9Sstevel@tonic-gate 			pnp->pr_pidfile = PTOV(xpnp);
44987c478bd9Sstevel@tonic-gate 			pnp->pr_mode = 0511;
44997c478bd9Sstevel@tonic-gate 			vp->v_flag |= VDIROPEN;
45007c478bd9Sstevel@tonic-gate 		} else {
45017c478bd9Sstevel@tonic-gate 			pnp->pr_mode = 0555;
45027c478bd9Sstevel@tonic-gate 		}
45037c478bd9Sstevel@tonic-gate 
45047c478bd9Sstevel@tonic-gate 		break;
45057c478bd9Sstevel@tonic-gate 
45067c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
45077c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
45087c478bd9Sstevel@tonic-gate 	case PR_FDDIR:
45097c478bd9Sstevel@tonic-gate 	case PR_OBJECTDIR:
45107c478bd9Sstevel@tonic-gate 	case PR_PATHDIR:
45117c478bd9Sstevel@tonic-gate 	case PR_CTDIR:
45127c478bd9Sstevel@tonic-gate 	case PR_TMPLDIR:
45137c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
45147c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0500;	/* read-search by owner only */
45157c478bd9Sstevel@tonic-gate 		break;
45167c478bd9Sstevel@tonic-gate 
45177c478bd9Sstevel@tonic-gate 	case PR_CT:
45187c478bd9Sstevel@tonic-gate 		vp->v_type = VLNK;
45197c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0500;	/* read-search by owner only */
45207c478bd9Sstevel@tonic-gate 		break;
45217c478bd9Sstevel@tonic-gate 
45227c478bd9Sstevel@tonic-gate 	case PR_PATH:
45237c478bd9Sstevel@tonic-gate 	case PR_SELF:
45247c478bd9Sstevel@tonic-gate 		vp->v_type = VLNK;
45257c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0777;
45267c478bd9Sstevel@tonic-gate 		break;
45277c478bd9Sstevel@tonic-gate 
45287c478bd9Sstevel@tonic-gate 	case PR_LWPDIR:
45297c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
45307c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0555;	/* read-search by all */
45317c478bd9Sstevel@tonic-gate 		break;
45327c478bd9Sstevel@tonic-gate 
45337c478bd9Sstevel@tonic-gate 	case PR_AS:
45347c478bd9Sstevel@tonic-gate 	case PR_TMPL:
45357c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0600;	/* read-write by owner only */
45367c478bd9Sstevel@tonic-gate 		break;
45377c478bd9Sstevel@tonic-gate 
45387c478bd9Sstevel@tonic-gate 	case PR_CTL:
45397c478bd9Sstevel@tonic-gate 	case PR_LWPCTL:
45407c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0200;	/* write-only by owner only */
45417c478bd9Sstevel@tonic-gate 		break;
45427c478bd9Sstevel@tonic-gate 
45437c478bd9Sstevel@tonic-gate 	case PR_PIDFILE:
45447c478bd9Sstevel@tonic-gate 	case PR_LWPIDFILE:
45457c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0600;	/* read-write by owner only */
45467c478bd9Sstevel@tonic-gate 		break;
45477c478bd9Sstevel@tonic-gate 
45487c478bd9Sstevel@tonic-gate 	case PR_PSINFO:
45497c478bd9Sstevel@tonic-gate 	case PR_LPSINFO:
45507c478bd9Sstevel@tonic-gate 	case PR_LWPSINFO:
45517c478bd9Sstevel@tonic-gate 	case PR_USAGE:
45527c478bd9Sstevel@tonic-gate 	case PR_LUSAGE:
45537c478bd9Sstevel@tonic-gate 	case PR_LWPUSAGE:
45547c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0444;	/* read-only by all */
45557c478bd9Sstevel@tonic-gate 		break;
45567c478bd9Sstevel@tonic-gate 
45577c478bd9Sstevel@tonic-gate 	default:
45587c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0400;	/* read-only by owner only */
45597c478bd9Sstevel@tonic-gate 		break;
45607c478bd9Sstevel@tonic-gate 	}
45617c478bd9Sstevel@tonic-gate 	vn_exists(vp);
45627c478bd9Sstevel@tonic-gate 	return (pnp);
45637c478bd9Sstevel@tonic-gate }
45647c478bd9Sstevel@tonic-gate 
45657c478bd9Sstevel@tonic-gate /*
45667c478bd9Sstevel@tonic-gate  * Free the storage obtained from prgetnode().
45677c478bd9Sstevel@tonic-gate  */
45687c478bd9Sstevel@tonic-gate void
45697c478bd9Sstevel@tonic-gate prfreenode(prnode_t *pnp)
45707c478bd9Sstevel@tonic-gate {
45717c478bd9Sstevel@tonic-gate 	vnode_t *vp;
45727c478bd9Sstevel@tonic-gate 	ulong_t nfiles;
45737c478bd9Sstevel@tonic-gate 
45747c478bd9Sstevel@tonic-gate 	vn_invalid(PTOV(pnp));
45757c478bd9Sstevel@tonic-gate 	vn_free(PTOV(pnp));
45767c478bd9Sstevel@tonic-gate 	mutex_destroy(&pnp->pr_mutex);
45777c478bd9Sstevel@tonic-gate 
45787c478bd9Sstevel@tonic-gate 	switch (pnp->pr_type) {
45797c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:
45807c478bd9Sstevel@tonic-gate 		/* kludge for old /proc interface */
45817c478bd9Sstevel@tonic-gate 		if (pnp->pr_pidfile != NULL) {
45827c478bd9Sstevel@tonic-gate 			prfreenode(VTOP(pnp->pr_pidfile));
45837c478bd9Sstevel@tonic-gate 			pnp->pr_pidfile = NULL;
45847c478bd9Sstevel@tonic-gate 		}
45857c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
45867c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
45877c478bd9Sstevel@tonic-gate 		/*
45887c478bd9Sstevel@tonic-gate 		 * We allocated a prcommon and a files array for each of these.
45897c478bd9Sstevel@tonic-gate 		 */
45907c478bd9Sstevel@tonic-gate 		prfreecommon(pnp->pr_common);
45917c478bd9Sstevel@tonic-gate 		nfiles = (pnp->pr_type == PR_PIDDIR)?
45927c478bd9Sstevel@tonic-gate 		    NPIDDIRFILES : NLWPIDDIRFILES;
45937c478bd9Sstevel@tonic-gate 		kmem_free(pnp->pr_files, nfiles * sizeof (vnode_t *));
45947c478bd9Sstevel@tonic-gate 		break;
45957c478bd9Sstevel@tonic-gate 	default:
45967c478bd9Sstevel@tonic-gate 		break;
45977c478bd9Sstevel@tonic-gate 	}
45987c478bd9Sstevel@tonic-gate 	/*
45997c478bd9Sstevel@tonic-gate 	 * If there is an underlying vnode, be sure
46007c478bd9Sstevel@tonic-gate 	 * to release it after freeing the prnode.
46017c478bd9Sstevel@tonic-gate 	 */
46027c478bd9Sstevel@tonic-gate 	vp = pnp->pr_realvp;
46037c478bd9Sstevel@tonic-gate 	kmem_free(pnp, sizeof (*pnp));
46047c478bd9Sstevel@tonic-gate 	DECREMENT(nprnode);
46057c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
46067c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
46077c478bd9Sstevel@tonic-gate 	}
46087c478bd9Sstevel@tonic-gate }
46097c478bd9Sstevel@tonic-gate 
46107c478bd9Sstevel@tonic-gate /*
4611da6c28aaSamw  * Free a prcommon structure, if the reference count reaches zero.
46127c478bd9Sstevel@tonic-gate  */
46137c478bd9Sstevel@tonic-gate static void
46147c478bd9Sstevel@tonic-gate prfreecommon(prcommon_t *pcp)
46157c478bd9Sstevel@tonic-gate {
46167c478bd9Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
46177c478bd9Sstevel@tonic-gate 	ASSERT(pcp->prc_refcnt > 0);
46187c478bd9Sstevel@tonic-gate 	if (--pcp->prc_refcnt != 0)
46197c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
46207c478bd9Sstevel@tonic-gate 	else {
46217c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
46227c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_pollhead.ph_list == NULL);
46237c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt == 0);
46247c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_selfopens == 0 && pcp->prc_writers == 0);
46257c478bd9Sstevel@tonic-gate 		mutex_destroy(&pcp->prc_mutex);
46267c478bd9Sstevel@tonic-gate 		cv_destroy(&pcp->prc_wait);
46277c478bd9Sstevel@tonic-gate 		kmem_free(pcp, sizeof (prcommon_t));
46287c478bd9Sstevel@tonic-gate 		DECREMENT(nprcommon);
46297c478bd9Sstevel@tonic-gate 	}
46307c478bd9Sstevel@tonic-gate }
46317c478bd9Sstevel@tonic-gate 
46327c478bd9Sstevel@tonic-gate /*
46337c478bd9Sstevel@tonic-gate  * Array of readdir functions, indexed by /proc file type.
46347c478bd9Sstevel@tonic-gate  */
46357c478bd9Sstevel@tonic-gate static int pr_readdir_notdir(), pr_readdir_procdir(), pr_readdir_piddir(),
46367c478bd9Sstevel@tonic-gate 	pr_readdir_objectdir(), pr_readdir_lwpdir(), pr_readdir_lwpiddir(),
46377c478bd9Sstevel@tonic-gate 	pr_readdir_fddir(), pr_readdir_pathdir(), pr_readdir_tmpldir(),
46387c478bd9Sstevel@tonic-gate 	pr_readdir_ctdir();
46397c478bd9Sstevel@tonic-gate 
46407c478bd9Sstevel@tonic-gate static int (*pr_readdir_function[PR_NFILES])() = {
46417c478bd9Sstevel@tonic-gate 	pr_readdir_procdir,	/* /proc				*/
46427c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/self				*/
46437c478bd9Sstevel@tonic-gate 	pr_readdir_piddir,	/* /proc/<pid>				*/
46447c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/as			*/
46457c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/ctl			*/
46467c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/status			*/
46477c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lstatus			*/
46487c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/psinfo			*/
46497c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lpsinfo			*/
46507c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/map			*/
46517c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/rmap			*/
46527c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/xmap			*/
46537c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/cred			*/
46547c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/sigact			*/
46557c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/auxv			*/
46567c478bd9Sstevel@tonic-gate #if defined(__x86)
46577c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/ldt			*/
46587c478bd9Sstevel@tonic-gate #endif
46597c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/usage			*/
46607c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lusage			*/
46617c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/pagedata			*/
46627c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/watch			*/
46637c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/cwd			*/
46647c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/root			*/
46657c478bd9Sstevel@tonic-gate 	pr_readdir_fddir,	/* /proc/<pid>/fd			*/
46667c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/fd/nn			*/
46677c478bd9Sstevel@tonic-gate 	pr_readdir_objectdir,	/* /proc/<pid>/object			*/
46687c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/object/xxx		*/
46697c478bd9Sstevel@tonic-gate 	pr_readdir_lwpdir,	/* /proc/<pid>/lwp			*/
46707c478bd9Sstevel@tonic-gate 	pr_readdir_lwpiddir,	/* /proc/<pid>/lwp/<lwpid>		*/
46717c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
46727c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
46737c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
46747c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
46757c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
46767c478bd9Sstevel@tonic-gate 	pr_readdir_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
46777c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
4678f971a346SBryan Cantrill 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
46797c478bd9Sstevel@tonic-gate #if defined(__sparc)
46807c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
46817c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
46827c478bd9Sstevel@tonic-gate #endif
46837c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/priv			*/
46847c478bd9Sstevel@tonic-gate 	pr_readdir_pathdir,	/* /proc/<pid>/path			*/
46857c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/path/xxx			*/
46867c478bd9Sstevel@tonic-gate 	pr_readdir_ctdir,	/* /proc/<pid>/contracts		*/
46877c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/contracts/<ctid>		*/
46887c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* old process file			*/
46897c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* old lwp file				*/
46907c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* old pagedata file			*/
46917c478bd9Sstevel@tonic-gate };
46927c478bd9Sstevel@tonic-gate 
46937c478bd9Sstevel@tonic-gate /* ARGSUSED */
46947c478bd9Sstevel@tonic-gate static int
4695da6c28aaSamw prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
4696da6c28aaSamw 	caller_context_t *ct, int flags)
46977c478bd9Sstevel@tonic-gate {
46987c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
46997c478bd9Sstevel@tonic-gate 
47007c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
47017c478bd9Sstevel@tonic-gate 
4702da6c28aaSamw 	/* XXX - Do we need to pass ct and flags? */
47037c478bd9Sstevel@tonic-gate 	return (pr_readdir_function[pnp->pr_type](pnp, uiop, eofp));
47047c478bd9Sstevel@tonic-gate }
47057c478bd9Sstevel@tonic-gate 
47067c478bd9Sstevel@tonic-gate /* ARGSUSED */
47077c478bd9Sstevel@tonic-gate static int
47087c478bd9Sstevel@tonic-gate pr_readdir_notdir(prnode_t *pnp, uio_t *uiop, int *eofp)
47097c478bd9Sstevel@tonic-gate {
47107c478bd9Sstevel@tonic-gate 	return (ENOTDIR);
47117c478bd9Sstevel@tonic-gate }
47127c478bd9Sstevel@tonic-gate 
47137c478bd9Sstevel@tonic-gate /* ARGSUSED */
47147c478bd9Sstevel@tonic-gate static int
47157c478bd9Sstevel@tonic-gate pr_readdir_procdir(prnode_t *pnp, uio_t *uiop, int *eofp)
47167c478bd9Sstevel@tonic-gate {
47177c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
47187c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
47197c478bd9Sstevel@tonic-gate 	int error, eof = 0;
47207c478bd9Sstevel@tonic-gate 	offset_t n;
47217c478bd9Sstevel@tonic-gate 
47227c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PROCDIR);
47237c478bd9Sstevel@tonic-gate 
4724fa9e4066Sahrens 	zoneid = VTOZONE(PTOV(pnp))->zone_id;
47257c478bd9Sstevel@tonic-gate 
47267c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PNSIZ, PRSDSIZE, uiop,
4727b38f0970Sck153898 	    PRROOTINO, PRROOTINO, 0)) != 0)
47287c478bd9Sstevel@tonic-gate 		return (error);
47297c478bd9Sstevel@tonic-gate 
47307c478bd9Sstevel@tonic-gate 	/*
47317c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until all processes
47327c478bd9Sstevel@tonic-gate 	 * have been examined.
47337c478bd9Sstevel@tonic-gate 	 */
47347c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
47357c478bd9Sstevel@tonic-gate 		uint_t pid;
47367c478bd9Sstevel@tonic-gate 		int pslot;
47377c478bd9Sstevel@tonic-gate 		proc_t *p;
47387c478bd9Sstevel@tonic-gate 
47397c478bd9Sstevel@tonic-gate 		/*
47407c478bd9Sstevel@tonic-gate 		 * Find next entry.  Skip processes not visible where
47417c478bd9Sstevel@tonic-gate 		 * this /proc was mounted.
47427c478bd9Sstevel@tonic-gate 		 */
47437c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
47447c478bd9Sstevel@tonic-gate 		while (n < v.v_proc &&
47457c478bd9Sstevel@tonic-gate 		    ((p = pid_entry(n)) == NULL || p->p_stat == SIDL ||
47467c478bd9Sstevel@tonic-gate 		    (zoneid != GLOBAL_ZONEID && p->p_zone->zone_id != zoneid) ||
47477c478bd9Sstevel@tonic-gate 		    secpolicy_basic_procinfo(CRED(), p, curproc) != 0))
47487c478bd9Sstevel@tonic-gate 			n++;
47497c478bd9Sstevel@tonic-gate 
47507c478bd9Sstevel@tonic-gate 		/*
47517c478bd9Sstevel@tonic-gate 		 * Stop when entire proc table has been examined.
47527c478bd9Sstevel@tonic-gate 		 */
47537c478bd9Sstevel@tonic-gate 		if (n >= v.v_proc) {
47547c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
47557c478bd9Sstevel@tonic-gate 			eof = 1;
47567c478bd9Sstevel@tonic-gate 			break;
47577c478bd9Sstevel@tonic-gate 		}
47587c478bd9Sstevel@tonic-gate 
47597c478bd9Sstevel@tonic-gate 		ASSERT(p->p_stat != 0);
47607c478bd9Sstevel@tonic-gate 		pid = p->p_pid;
47617c478bd9Sstevel@tonic-gate 		pslot = p->p_slot;
47627c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
47637c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, n,
47647c478bd9Sstevel@tonic-gate 		    pmkino(0, pslot, PR_PIDDIR), pid);
47657c478bd9Sstevel@tonic-gate 		if (error)
47667c478bd9Sstevel@tonic-gate 			break;
47677c478bd9Sstevel@tonic-gate 	}
47687c478bd9Sstevel@tonic-gate 
47697c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
47707c478bd9Sstevel@tonic-gate }
47717c478bd9Sstevel@tonic-gate 
47727c478bd9Sstevel@tonic-gate /* ARGSUSED */
47737c478bd9Sstevel@tonic-gate static int
47747c478bd9Sstevel@tonic-gate pr_readdir_piddir(prnode_t *pnp, uio_t *uiop, int *eofp)
47757c478bd9Sstevel@tonic-gate {
47767c478bd9Sstevel@tonic-gate 	int zombie = ((pnp->pr_pcommon->prc_flags & PRC_DESTROY) != 0);
47777c478bd9Sstevel@tonic-gate 	prdirent_t dirent;
47787c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
47797c478bd9Sstevel@tonic-gate 	offset_t off;
47807c478bd9Sstevel@tonic-gate 	int error;
47817c478bd9Sstevel@tonic-gate 
47827c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDDIR);
47837c478bd9Sstevel@tonic-gate 
47847c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
47857c478bd9Sstevel@tonic-gate 	    uiop->uio_offset % sizeof (prdirent_t) != 0 ||
47867c478bd9Sstevel@tonic-gate 	    uiop->uio_resid < sizeof (prdirent_t))
47877c478bd9Sstevel@tonic-gate 		return (EINVAL);
47887c478bd9Sstevel@tonic-gate 	if (pnp->pr_pcommon->prc_proc == NULL)
47897c478bd9Sstevel@tonic-gate 		return (ENOENT);
47907c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (piddir))
47917c478bd9Sstevel@tonic-gate 		goto out;
47927c478bd9Sstevel@tonic-gate 
47937c478bd9Sstevel@tonic-gate 	/*
47947c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied, omitting some
47957c478bd9Sstevel@tonic-gate 	 * files along the way if the process is a zombie.
47967c478bd9Sstevel@tonic-gate 	 */
47977c478bd9Sstevel@tonic-gate 	for (dirp = &piddir[uiop->uio_offset / sizeof (prdirent_t)];
47987c478bd9Sstevel@tonic-gate 	    uiop->uio_resid >= sizeof (prdirent_t) &&
47997c478bd9Sstevel@tonic-gate 	    dirp < &piddir[NPIDDIRFILES+2];
48007c478bd9Sstevel@tonic-gate 	    uiop->uio_offset = off + sizeof (prdirent_t), dirp++) {
48017c478bd9Sstevel@tonic-gate 		off = uiop->uio_offset;
48027c478bd9Sstevel@tonic-gate 		if (zombie) {
48037c478bd9Sstevel@tonic-gate 			switch (dirp->d_ino) {
48047c478bd9Sstevel@tonic-gate 			case PR_PIDDIR:
48057c478bd9Sstevel@tonic-gate 			case PR_PROCDIR:
48067c478bd9Sstevel@tonic-gate 			case PR_PSINFO:
48077c478bd9Sstevel@tonic-gate 			case PR_USAGE:
48087c478bd9Sstevel@tonic-gate 				break;
48097c478bd9Sstevel@tonic-gate 			default:
48107c478bd9Sstevel@tonic-gate 				continue;
48117c478bd9Sstevel@tonic-gate 			}
48127c478bd9Sstevel@tonic-gate 		}
48137c478bd9Sstevel@tonic-gate 		bcopy(dirp, &dirent, sizeof (prdirent_t));
48147c478bd9Sstevel@tonic-gate 		if (dirent.d_ino == PR_PROCDIR)
48157c478bd9Sstevel@tonic-gate 			dirent.d_ino = PRROOTINO;
48167c478bd9Sstevel@tonic-gate 		else
48177c478bd9Sstevel@tonic-gate 			dirent.d_ino = pmkino(0, pnp->pr_pcommon->prc_slot,
48187c478bd9Sstevel@tonic-gate 			    dirent.d_ino);
48197c478bd9Sstevel@tonic-gate 		if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
48207c478bd9Sstevel@tonic-gate 		    UIO_READ, uiop)) != 0)
48217c478bd9Sstevel@tonic-gate 			return (error);
48227c478bd9Sstevel@tonic-gate 	}
48237c478bd9Sstevel@tonic-gate out:
48247c478bd9Sstevel@tonic-gate 	if (eofp)
48257c478bd9Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= sizeof (piddir));
48267c478bd9Sstevel@tonic-gate 	return (0);
48277c478bd9Sstevel@tonic-gate }
48287c478bd9Sstevel@tonic-gate 
48297c478bd9Sstevel@tonic-gate static void
48307c478bd9Sstevel@tonic-gate rebuild_objdir(struct as *as)
48317c478bd9Sstevel@tonic-gate {
48327c478bd9Sstevel@tonic-gate 	struct seg *seg;
48337c478bd9Sstevel@tonic-gate 	vnode_t *vp;
48347c478bd9Sstevel@tonic-gate 	vattr_t vattr;
48357c478bd9Sstevel@tonic-gate 	vnode_t **dir;
48367c478bd9Sstevel@tonic-gate 	ulong_t nalloc;
48377c478bd9Sstevel@tonic-gate 	ulong_t nentries;
48387c478bd9Sstevel@tonic-gate 	int i, j;
48397c478bd9Sstevel@tonic-gate 	ulong_t nold, nnew;
48407c478bd9Sstevel@tonic-gate 
4841*dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_WRITE_HELD(as));
48427c478bd9Sstevel@tonic-gate 
48437c478bd9Sstevel@tonic-gate 	if (as->a_updatedir == 0 && as->a_objectdir != NULL)
48447c478bd9Sstevel@tonic-gate 		return;
48457c478bd9Sstevel@tonic-gate 	as->a_updatedir = 0;
48467c478bd9Sstevel@tonic-gate 
48477c478bd9Sstevel@tonic-gate 	if ((nalloc = avl_numnodes(&as->a_segtree)) == 0 ||
48487c478bd9Sstevel@tonic-gate 	    (seg = AS_SEGFIRST(as)) == NULL)	/* can't happen? */
48497c478bd9Sstevel@tonic-gate 		return;
48507c478bd9Sstevel@tonic-gate 
48517c478bd9Sstevel@tonic-gate 	/*
48527c478bd9Sstevel@tonic-gate 	 * Allocate space for the new object directory.
48537c478bd9Sstevel@tonic-gate 	 * (This is usually about two times too many entries.)
48547c478bd9Sstevel@tonic-gate 	 */
48557c478bd9Sstevel@tonic-gate 	nalloc = (nalloc + 0xf) & ~0xf;		/* multiple of 16 */
48567c478bd9Sstevel@tonic-gate 	dir = kmem_zalloc(nalloc * sizeof (vnode_t *), KM_SLEEP);
48577c478bd9Sstevel@tonic-gate 
48587c478bd9Sstevel@tonic-gate 	/* fill in the new directory with desired entries */
48597c478bd9Sstevel@tonic-gate 	nentries = 0;
48607c478bd9Sstevel@tonic-gate 	do {
48617c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID|AT_NODEID;
48627c478bd9Sstevel@tonic-gate 		if (seg->s_ops == &segvn_ops &&
48637c478bd9Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
48647c478bd9Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
4865da6c28aaSamw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
48667c478bd9Sstevel@tonic-gate 			for (i = 0; i < nentries; i++)
48677c478bd9Sstevel@tonic-gate 				if (vp == dir[i])
48687c478bd9Sstevel@tonic-gate 					break;
48697c478bd9Sstevel@tonic-gate 			if (i == nentries) {
48707c478bd9Sstevel@tonic-gate 				ASSERT(nentries < nalloc);
48717c478bd9Sstevel@tonic-gate 				dir[nentries++] = vp;
48727c478bd9Sstevel@tonic-gate 			}
48737c478bd9Sstevel@tonic-gate 		}
48747c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
48757c478bd9Sstevel@tonic-gate 
48767c478bd9Sstevel@tonic-gate 	if (as->a_objectdir == NULL) {	/* first time */
48777c478bd9Sstevel@tonic-gate 		as->a_objectdir = dir;
48787c478bd9Sstevel@tonic-gate 		as->a_sizedir = nalloc;
48797c478bd9Sstevel@tonic-gate 		return;
48807c478bd9Sstevel@tonic-gate 	}
48817c478bd9Sstevel@tonic-gate 
48827c478bd9Sstevel@tonic-gate 	/*
48837c478bd9Sstevel@tonic-gate 	 * Null out all of the defunct entries in the old directory.
48847c478bd9Sstevel@tonic-gate 	 */
48857c478bd9Sstevel@tonic-gate 	nold = 0;
48867c478bd9Sstevel@tonic-gate 	nnew = nentries;
48877c478bd9Sstevel@tonic-gate 	for (i = 0; i < as->a_sizedir; i++) {
48887c478bd9Sstevel@tonic-gate 		if ((vp = as->a_objectdir[i]) != NULL) {
48897c478bd9Sstevel@tonic-gate 			for (j = 0; j < nentries; j++) {
48907c478bd9Sstevel@tonic-gate 				if (vp == dir[j]) {
48917c478bd9Sstevel@tonic-gate 					dir[j] = NULL;
48927c478bd9Sstevel@tonic-gate 					nnew--;
48937c478bd9Sstevel@tonic-gate 					break;
48947c478bd9Sstevel@tonic-gate 				}
48957c478bd9Sstevel@tonic-gate 			}
48967c478bd9Sstevel@tonic-gate 			if (j == nentries)
48977c478bd9Sstevel@tonic-gate 				as->a_objectdir[i] = NULL;
48987c478bd9Sstevel@tonic-gate 			else
48997c478bd9Sstevel@tonic-gate 				nold++;
49007c478bd9Sstevel@tonic-gate 		}
49017c478bd9Sstevel@tonic-gate 	}
49027c478bd9Sstevel@tonic-gate 
49037c478bd9Sstevel@tonic-gate 	if (nold + nnew > as->a_sizedir) {
49047c478bd9Sstevel@tonic-gate 		/*
49057c478bd9Sstevel@tonic-gate 		 * Reallocate the old directory to have enough
49067c478bd9Sstevel@tonic-gate 		 * space for the old and new entries combined.
49077c478bd9Sstevel@tonic-gate 		 * Round up to the next multiple of 16.
49087c478bd9Sstevel@tonic-gate 		 */
49097c478bd9Sstevel@tonic-gate 		ulong_t newsize = (nold + nnew + 0xf) & ~0xf;
49107c478bd9Sstevel@tonic-gate 		vnode_t **newdir = kmem_zalloc(newsize * sizeof (vnode_t *),
49117c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
49127c478bd9Sstevel@tonic-gate 		bcopy(as->a_objectdir, newdir,
49137c478bd9Sstevel@tonic-gate 		    as->a_sizedir * sizeof (vnode_t *));
49147c478bd9Sstevel@tonic-gate 		kmem_free(as->a_objectdir, as->a_sizedir * sizeof (vnode_t *));
49157c478bd9Sstevel@tonic-gate 		as->a_objectdir = newdir;
49167c478bd9Sstevel@tonic-gate 		as->a_sizedir = newsize;
49177c478bd9Sstevel@tonic-gate 	}
49187c478bd9Sstevel@tonic-gate 
49197c478bd9Sstevel@tonic-gate 	/*
49207c478bd9Sstevel@tonic-gate 	 * Move all new entries to the old directory and
49217c478bd9Sstevel@tonic-gate 	 * deallocate the space used by the new directory.
49227c478bd9Sstevel@tonic-gate 	 */
49237c478bd9Sstevel@tonic-gate 	if (nnew) {
49247c478bd9Sstevel@tonic-gate 		for (i = 0, j = 0; i < nentries; i++) {
49257c478bd9Sstevel@tonic-gate 			if ((vp = dir[i]) == NULL)
49267c478bd9Sstevel@tonic-gate 				continue;
49277c478bd9Sstevel@tonic-gate 			for (; j < as->a_sizedir; j++) {
49287c478bd9Sstevel@tonic-gate 				if (as->a_objectdir[j] != NULL)
49297c478bd9Sstevel@tonic-gate 					continue;
49307c478bd9Sstevel@tonic-gate 				as->a_objectdir[j++] = vp;
49317c478bd9Sstevel@tonic-gate 				break;
49327c478bd9Sstevel@tonic-gate 			}
49337c478bd9Sstevel@tonic-gate 		}
49347c478bd9Sstevel@tonic-gate 	}
49357c478bd9Sstevel@tonic-gate 	kmem_free(dir, nalloc * sizeof (vnode_t *));
49367c478bd9Sstevel@tonic-gate }
49377c478bd9Sstevel@tonic-gate 
49387c478bd9Sstevel@tonic-gate /*
49397c478bd9Sstevel@tonic-gate  * Return the vnode from a slot in the process's object directory.
49407c478bd9Sstevel@tonic-gate  * The caller must have locked the process's address space.
49417c478bd9Sstevel@tonic-gate  * The only caller is below, in pr_readdir_objectdir().
49427c478bd9Sstevel@tonic-gate  */
49437c478bd9Sstevel@tonic-gate static vnode_t *
49447c478bd9Sstevel@tonic-gate obj_entry(struct as *as, int slot)
49457c478bd9Sstevel@tonic-gate {
4946*dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_LOCK_HELD(as));
49477c478bd9Sstevel@tonic-gate 	if (as->a_objectdir == NULL)
49487c478bd9Sstevel@tonic-gate 		return (NULL);
49497c478bd9Sstevel@tonic-gate 	ASSERT(slot < as->a_sizedir);
49507c478bd9Sstevel@tonic-gate 	return (as->a_objectdir[slot]);
49517c478bd9Sstevel@tonic-gate }
49527c478bd9Sstevel@tonic-gate 
49537c478bd9Sstevel@tonic-gate /* ARGSUSED */
49547c478bd9Sstevel@tonic-gate static int
49557c478bd9Sstevel@tonic-gate pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
49567c478bd9Sstevel@tonic-gate {
49577c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
49587c478bd9Sstevel@tonic-gate 	int error, eof = 0;
49597c478bd9Sstevel@tonic-gate 	offset_t n;
49607c478bd9Sstevel@tonic-gate 	int pslot;
49617c478bd9Sstevel@tonic-gate 	size_t objdirsize;
49627c478bd9Sstevel@tonic-gate 	proc_t *p;
49637c478bd9Sstevel@tonic-gate 	struct as *as;
49647c478bd9Sstevel@tonic-gate 	vnode_t *vp;
49657c478bd9Sstevel@tonic-gate 
49667c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OBJECTDIR);
49677c478bd9Sstevel@tonic-gate 
49687c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
49697c478bd9Sstevel@tonic-gate 		return (error);
49707c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
49717c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
49727c478bd9Sstevel@tonic-gate 
49737c478bd9Sstevel@tonic-gate 	/*
49747c478bd9Sstevel@tonic-gate 	 * We drop p_lock before grabbing the address space lock
49757c478bd9Sstevel@tonic-gate 	 * in order to avoid a deadlock with the clock thread.
49767c478bd9Sstevel@tonic-gate 	 * The process will not disappear and its address space
49777c478bd9Sstevel@tonic-gate 	 * will not change because it is marked P_PR_LOCK.
49787c478bd9Sstevel@tonic-gate 	 */
49797c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
49807c478bd9Sstevel@tonic-gate 
49817c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, 64, PRSDSIZE, uiop,
49827c478bd9Sstevel@tonic-gate 	    pmkino(0, pslot, PR_PIDDIR),
4983b38f0970Sck153898 	    pmkino(0, pslot, PR_OBJECTDIR), 0)) != 0) {
49847c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
49857c478bd9Sstevel@tonic-gate 		prunlock(pnp);
49867c478bd9Sstevel@tonic-gate 		return (error);
49877c478bd9Sstevel@tonic-gate 	}
49887c478bd9Sstevel@tonic-gate 
49897c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
49907c478bd9Sstevel@tonic-gate 		as = NULL;
49917c478bd9Sstevel@tonic-gate 		objdirsize = 0;
499243d09bd4Spetede 	}
499343d09bd4Spetede 
499443d09bd4Spetede 	/*
499543d09bd4Spetede 	 * Loop until user's request is satisfied or until
499643d09bd4Spetede 	 * all mapped objects have been examined. Cannot hold
499743d09bd4Spetede 	 * the address space lock for the following call as
499843d09bd4Spetede 	 * gfs_readdir_pred() utimately causes a call to uiomove().
499943d09bd4Spetede 	 */
500043d09bd4Spetede 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
500143d09bd4Spetede 		vattr_t vattr;
500243d09bd4Spetede 		char str[64];
500343d09bd4Spetede 
500443d09bd4Spetede 		/*
500543d09bd4Spetede 		 * Set the correct size of the directory just
500643d09bd4Spetede 		 * in case the process has changed it's address
500743d09bd4Spetede 		 * space via mmap/munmap calls.
500843d09bd4Spetede 		 */
500943d09bd4Spetede 		if (as != NULL) {
5010*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
50117c478bd9Sstevel@tonic-gate 			if (as->a_updatedir)
50127c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
50137c478bd9Sstevel@tonic-gate 			objdirsize = as->a_sizedir;
50147c478bd9Sstevel@tonic-gate 		}
50157c478bd9Sstevel@tonic-gate 
50167c478bd9Sstevel@tonic-gate 		/*
50177c478bd9Sstevel@tonic-gate 		 * Find next object.
50187c478bd9Sstevel@tonic-gate 		 */
50197c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID | AT_NODEID;
50207c478bd9Sstevel@tonic-gate 		while (n < objdirsize && (((vp = obj_entry(as, n)) == NULL) ||
5021da6c28aaSamw 		    (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)
5022da6c28aaSamw 		    != 0))) {
50237c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID | AT_NODEID;
50247c478bd9Sstevel@tonic-gate 			n++;
50257c478bd9Sstevel@tonic-gate 		}
50267c478bd9Sstevel@tonic-gate 
502743d09bd4Spetede 		if (as != NULL)
5028*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
502943d09bd4Spetede 
50307c478bd9Sstevel@tonic-gate 		/*
50317c478bd9Sstevel@tonic-gate 		 * Stop when all objects have been reported.
50327c478bd9Sstevel@tonic-gate 		 */
50337c478bd9Sstevel@tonic-gate 		if (n >= objdirsize) {
50347c478bd9Sstevel@tonic-gate 			eof = 1;
50357c478bd9Sstevel@tonic-gate 			break;
50367c478bd9Sstevel@tonic-gate 		}
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate 		if (vp == p->p_exec)
50397c478bd9Sstevel@tonic-gate 			(void) strcpy(str, "a.out");
50407c478bd9Sstevel@tonic-gate 		else
50417c478bd9Sstevel@tonic-gate 			pr_object_name(str, vp, &vattr);
50427c478bd9Sstevel@tonic-gate 
50437c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emit(&gstate, uiop, n, vattr.va_nodeid,
5044b38f0970Sck153898 		    str, 0);
504543d09bd4Spetede 
50467c478bd9Sstevel@tonic-gate 		if (error)
50477c478bd9Sstevel@tonic-gate 			break;
50487c478bd9Sstevel@tonic-gate 	}
50497c478bd9Sstevel@tonic-gate 
50507c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
50517c478bd9Sstevel@tonic-gate 	prunlock(pnp);
50527c478bd9Sstevel@tonic-gate 
50537c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
50547c478bd9Sstevel@tonic-gate }
50557c478bd9Sstevel@tonic-gate 
50567c478bd9Sstevel@tonic-gate /* ARGSUSED */
50577c478bd9Sstevel@tonic-gate static int
50587c478bd9Sstevel@tonic-gate pr_readdir_lwpdir(prnode_t *pnp, uio_t *uiop, int *eofp)
50597c478bd9Sstevel@tonic-gate {
50607c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
50617c478bd9Sstevel@tonic-gate 	int error, eof = 0;
50627c478bd9Sstevel@tonic-gate 	offset_t tslot;
50637c478bd9Sstevel@tonic-gate 	proc_t *p;
50647c478bd9Sstevel@tonic-gate 	int pslot;
50657c478bd9Sstevel@tonic-gate 	lwpdir_t *lwpdir;
50667c478bd9Sstevel@tonic-gate 	int lwpdirsize;
50677c478bd9Sstevel@tonic-gate 
50687c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPDIR);
50697c478bd9Sstevel@tonic-gate 
50707c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
50717c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
50727c478bd9Sstevel@tonic-gate 	if (p == NULL)
50737c478bd9Sstevel@tonic-gate 		return (ENOENT);
50747c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
50757c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
50767c478bd9Sstevel@tonic-gate 	lwpdir = p->p_lwpdir;
50777c478bd9Sstevel@tonic-gate 	lwpdirsize = p->p_lwpdir_sz;
50787c478bd9Sstevel@tonic-gate 
50797c478bd9Sstevel@tonic-gate 	/*
50807c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock so we can safely do uiomove().
50817c478bd9Sstevel@tonic-gate 	 * The lwp directory will not change because
50827c478bd9Sstevel@tonic-gate 	 * we have the process locked with P_PR_LOCK.
50837c478bd9Sstevel@tonic-gate 	 */
50847c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
50857c478bd9Sstevel@tonic-gate 
50867c478bd9Sstevel@tonic-gate 
50877c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
5088b38f0970Sck153898 	    pmkino(0, pslot, PR_PIDDIR),
5089b38f0970Sck153898 	    pmkino(0, pslot, PR_LWPDIR), 0)) != 0) {
50907c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
50917c478bd9Sstevel@tonic-gate 		prunlock(pnp);
50927c478bd9Sstevel@tonic-gate 		return (error);
50937c478bd9Sstevel@tonic-gate 	}
50947c478bd9Sstevel@tonic-gate 
50957c478bd9Sstevel@tonic-gate 	/*
50967c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until all lwps
50977c478bd9Sstevel@tonic-gate 	 * have been examined.
50987c478bd9Sstevel@tonic-gate 	 */
50997c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &tslot)) == 0) {
51007c478bd9Sstevel@tonic-gate 		lwpent_t *lep;
51017c478bd9Sstevel@tonic-gate 		uint_t tid;
51027c478bd9Sstevel@tonic-gate 
51037c478bd9Sstevel@tonic-gate 		/*
51047c478bd9Sstevel@tonic-gate 		 * Find next LWP.
51057c478bd9Sstevel@tonic-gate 		 */
51067c478bd9Sstevel@tonic-gate 		while (tslot < lwpdirsize &&
51077c478bd9Sstevel@tonic-gate 		    ((lep = lwpdir[tslot].ld_entry) == NULL))
51087c478bd9Sstevel@tonic-gate 			tslot++;
51097c478bd9Sstevel@tonic-gate 		/*
51107c478bd9Sstevel@tonic-gate 		 * Stop when all lwps have been reported.
51117c478bd9Sstevel@tonic-gate 		 */
51127c478bd9Sstevel@tonic-gate 		if (tslot >= lwpdirsize) {
51137c478bd9Sstevel@tonic-gate 			eof = 1;
51147c478bd9Sstevel@tonic-gate 			break;
51157c478bd9Sstevel@tonic-gate 		}
51167c478bd9Sstevel@tonic-gate 
51177c478bd9Sstevel@tonic-gate 		tid = lep->le_lwpid;
51187c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, tslot,
51197c478bd9Sstevel@tonic-gate 		    pmkino(tslot, pslot, PR_LWPIDDIR), tid);
51207c478bd9Sstevel@tonic-gate 		if (error)
51217c478bd9Sstevel@tonic-gate 			break;
51227c478bd9Sstevel@tonic-gate 	}
51237c478bd9Sstevel@tonic-gate 
51247c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
51257c478bd9Sstevel@tonic-gate 	prunlock(pnp);
51267c478bd9Sstevel@tonic-gate 
51277c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
51287c478bd9Sstevel@tonic-gate }
51297c478bd9Sstevel@tonic-gate 
51307c478bd9Sstevel@tonic-gate /* ARGSUSED */
51317c478bd9Sstevel@tonic-gate static int
51327c478bd9Sstevel@tonic-gate pr_readdir_lwpiddir(prnode_t *pnp, uio_t *uiop, int *eofp)
51337c478bd9Sstevel@tonic-gate {
51347c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
51357c478bd9Sstevel@tonic-gate 	int zombie = ((pcp->prc_flags & PRC_DESTROY) != 0);
51367c478bd9Sstevel@tonic-gate 	prdirent_t dirent;
51377c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
51387c478bd9Sstevel@tonic-gate 	offset_t off;
51397c478bd9Sstevel@tonic-gate 	int error;
51407c478bd9Sstevel@tonic-gate 	int pslot;
51417c478bd9Sstevel@tonic-gate 	int tslot;
51427c478bd9Sstevel@tonic-gate 
51437c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPIDDIR);
51447c478bd9Sstevel@tonic-gate 
51457c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
51467c478bd9Sstevel@tonic-gate 	    uiop->uio_offset % sizeof (prdirent_t) != 0 ||
51477c478bd9Sstevel@tonic-gate 	    uiop->uio_resid < sizeof (prdirent_t))
51487c478bd9Sstevel@tonic-gate 		return (EINVAL);
51497c478bd9Sstevel@tonic-gate 	if (pcp->prc_proc == NULL || pcp->prc_tslot == -1)
51507c478bd9Sstevel@tonic-gate 		return (ENOENT);
51517c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpiddir))
51527c478bd9Sstevel@tonic-gate 		goto out;
51537c478bd9Sstevel@tonic-gate 
51547c478bd9Sstevel@tonic-gate 	/*
51557c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied, omitting some files
51567c478bd9Sstevel@tonic-gate 	 * along the way if the lwp is a zombie and also depending
51577c478bd9Sstevel@tonic-gate 	 * on the data model of the process.
51587c478bd9Sstevel@tonic-gate 	 */
51597c478bd9Sstevel@tonic-gate 	pslot = pcp->prc_slot;
51607c478bd9Sstevel@tonic-gate 	tslot = pcp->prc_tslot;
51617c478bd9Sstevel@tonic-gate 	for (dirp = &lwpiddir[uiop->uio_offset / sizeof (prdirent_t)];
51627c478bd9Sstevel@tonic-gate 	    uiop->uio_resid >= sizeof (prdirent_t) &&
51637c478bd9Sstevel@tonic-gate 	    dirp < &lwpiddir[NLWPIDDIRFILES+2];
51647c478bd9Sstevel@tonic-gate 	    uiop->uio_offset = off + sizeof (prdirent_t), dirp++) {
51657c478bd9Sstevel@tonic-gate 		off = uiop->uio_offset;
51667c478bd9Sstevel@tonic-gate 		if (zombie) {
51677c478bd9Sstevel@tonic-gate 			switch (dirp->d_ino) {
51687c478bd9Sstevel@tonic-gate 			case PR_LWPIDDIR:
51697c478bd9Sstevel@tonic-gate 			case PR_LWPDIR:
51707c478bd9Sstevel@tonic-gate 			case PR_LWPSINFO:
51717c478bd9Sstevel@tonic-gate 				break;
51727c478bd9Sstevel@tonic-gate 			default:
51737c478bd9Sstevel@tonic-gate 				continue;
51747c478bd9Sstevel@tonic-gate 			}
51757c478bd9Sstevel@tonic-gate 		}
51767c478bd9Sstevel@tonic-gate #if defined(__sparc)
51777c478bd9Sstevel@tonic-gate 		/* the asrs file exists only for sparc v9 _LP64 processes */
51787c478bd9Sstevel@tonic-gate 		if (dirp->d_ino == PR_ASRS &&
51797c478bd9Sstevel@tonic-gate 		    pcp->prc_datamodel != DATAMODEL_LP64)
51807c478bd9Sstevel@tonic-gate 			continue;
51817c478bd9Sstevel@tonic-gate #endif
51827c478bd9Sstevel@tonic-gate 		bcopy(dirp, &dirent, sizeof (prdirent_t));
51837c478bd9Sstevel@tonic-gate 		if (dirent.d_ino == PR_LWPDIR)
51847c478bd9Sstevel@tonic-gate 			dirent.d_ino = pmkino(0, pslot, dirp->d_ino);
51857c478bd9Sstevel@tonic-gate 		else
51867c478bd9Sstevel@tonic-gate 			dirent.d_ino = pmkino(tslot, pslot, dirp->d_ino);
51877c478bd9Sstevel@tonic-gate 		if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
51887c478bd9Sstevel@tonic-gate 		    UIO_READ, uiop)) != 0)
51897c478bd9Sstevel@tonic-gate 			return (error);
51907c478bd9Sstevel@tonic-gate 	}
51917c478bd9Sstevel@tonic-gate out:
51927c478bd9Sstevel@tonic-gate 	if (eofp)
51937c478bd9Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= sizeof (lwpiddir));
51947c478bd9Sstevel@tonic-gate 	return (0);
51957c478bd9Sstevel@tonic-gate }
51967c478bd9Sstevel@tonic-gate 
51977c478bd9Sstevel@tonic-gate /* ARGSUSED */
51987c478bd9Sstevel@tonic-gate static int
51997c478bd9Sstevel@tonic-gate pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
52007c478bd9Sstevel@tonic-gate {
52017c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
52027c478bd9Sstevel@tonic-gate 	int error, eof = 0;
52037c478bd9Sstevel@tonic-gate 	offset_t n;
52047c478bd9Sstevel@tonic-gate 	proc_t *p;
52057c478bd9Sstevel@tonic-gate 	int pslot;
52067c478bd9Sstevel@tonic-gate 	int fddirsize;
52077c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
52087c478bd9Sstevel@tonic-gate 
52097c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_FDDIR);
52107c478bd9Sstevel@tonic-gate 
52117c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
52127c478bd9Sstevel@tonic-gate 		return (error);
52137c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
52147c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
52157c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
52167c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
52177c478bd9Sstevel@tonic-gate 
52187c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
5219b38f0970Sck153898 	    pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_FDDIR), 0)) != 0) {
52207c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
52217c478bd9Sstevel@tonic-gate 		prunlock(pnp);
52227c478bd9Sstevel@tonic-gate 		return (error);
52237c478bd9Sstevel@tonic-gate 	}
52247c478bd9Sstevel@tonic-gate 
52257c478bd9Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
52267c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
52277c478bd9Sstevel@tonic-gate 		fddirsize = 0;
52287c478bd9Sstevel@tonic-gate 	else
52297c478bd9Sstevel@tonic-gate 		fddirsize = fip->fi_nfiles;
52307c478bd9Sstevel@tonic-gate 
52317c478bd9Sstevel@tonic-gate 	/*
52327c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until
52337c478bd9Sstevel@tonic-gate 	 * all file descriptors have been examined.
52347c478bd9Sstevel@tonic-gate 	 */
52357c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
52367c478bd9Sstevel@tonic-gate 		/*
52377c478bd9Sstevel@tonic-gate 		 * Find next fd.
52387c478bd9Sstevel@tonic-gate 		 */
52397c478bd9Sstevel@tonic-gate 		while (n < fddirsize && fip->fi_list[n].uf_file == NULL)
52407c478bd9Sstevel@tonic-gate 			n++;
52417c478bd9Sstevel@tonic-gate 		/*
52427c478bd9Sstevel@tonic-gate 		 * Stop when all fds have been reported.
52437c478bd9Sstevel@tonic-gate 		 */
52447c478bd9Sstevel@tonic-gate 		if (n >= fddirsize) {
52457c478bd9Sstevel@tonic-gate 			eof = 1;
52467c478bd9Sstevel@tonic-gate 			break;
52477c478bd9Sstevel@tonic-gate 		}
52487c478bd9Sstevel@tonic-gate 
52497c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, n,
52507c478bd9Sstevel@tonic-gate 		    pmkino(n, pslot, PR_FD), n);
52517c478bd9Sstevel@tonic-gate 		if (error)
52527c478bd9Sstevel@tonic-gate 			break;
52537c478bd9Sstevel@tonic-gate 	}
52547c478bd9Sstevel@tonic-gate 
52557c478bd9Sstevel@tonic-gate 	mutex_exit(&fip->fi_lock);
52567c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
52577c478bd9Sstevel@tonic-gate 	prunlock(pnp);
52587c478bd9Sstevel@tonic-gate 
52597c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
52607c478bd9Sstevel@tonic-gate }
52617c478bd9Sstevel@tonic-gate 
52627c478bd9Sstevel@tonic-gate /* ARGSUSED */
52637c478bd9Sstevel@tonic-gate static int
52647c478bd9Sstevel@tonic-gate pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
52657c478bd9Sstevel@tonic-gate {
52667c478bd9Sstevel@tonic-gate 	longlong_t bp[DIRENT64_RECLEN(64) / sizeof (longlong_t)];
52677c478bd9Sstevel@tonic-gate 	dirent64_t *dirent = (dirent64_t *)bp;
52687c478bd9Sstevel@tonic-gate 	int reclen;
52697c478bd9Sstevel@tonic-gate 	ssize_t oresid;
52707c478bd9Sstevel@tonic-gate 	offset_t off, idx;
52717c478bd9Sstevel@tonic-gate 	int error = 0;
52727c478bd9Sstevel@tonic-gate 	proc_t *p;
52737c478bd9Sstevel@tonic-gate 	int fd, obj;
52747c478bd9Sstevel@tonic-gate 	int pslot;
52757c478bd9Sstevel@tonic-gate 	int fddirsize;
52767c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
52777c478bd9Sstevel@tonic-gate 	struct as *as = NULL;
52787c478bd9Sstevel@tonic-gate 	size_t objdirsize;
52797c478bd9Sstevel@tonic-gate 	vattr_t vattr;
52807c478bd9Sstevel@tonic-gate 	vnode_t *vp;
52817c478bd9Sstevel@tonic-gate 
52827c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PATHDIR);
52837c478bd9Sstevel@tonic-gate 
52847c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
52857c478bd9Sstevel@tonic-gate 	    uiop->uio_resid <= 0 ||
52867c478bd9Sstevel@tonic-gate 	    (uiop->uio_offset % PRSDSIZE) != 0)
52877c478bd9Sstevel@tonic-gate 		return (EINVAL);
52887c478bd9Sstevel@tonic-gate 	oresid = uiop->uio_resid;
52897c478bd9Sstevel@tonic-gate 	bzero(bp, sizeof (bp));
52907c478bd9Sstevel@tonic-gate 
52917c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
52927c478bd9Sstevel@tonic-gate 		return (error);
52937c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
52947c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
52957c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
52967c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
52977c478bd9Sstevel@tonic-gate 
52987c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
52997c478bd9Sstevel@tonic-gate 		as = NULL;
53007c478bd9Sstevel@tonic-gate 		objdirsize = 0;
53017c478bd9Sstevel@tonic-gate 	} else {
5302*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_ENTER(as, RW_WRITER);
53037c478bd9Sstevel@tonic-gate 		if (as->a_updatedir)
53047c478bd9Sstevel@tonic-gate 			rebuild_objdir(as);
53057c478bd9Sstevel@tonic-gate 		objdirsize = as->a_sizedir;
5306*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
53077c478bd9Sstevel@tonic-gate 		as = NULL;
53087c478bd9Sstevel@tonic-gate 	}
53097c478bd9Sstevel@tonic-gate 
53107c478bd9Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
53117c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
53127c478bd9Sstevel@tonic-gate 		fddirsize = 0;
53137c478bd9Sstevel@tonic-gate 	else
53147c478bd9Sstevel@tonic-gate 		fddirsize = fip->fi_nfiles;
53157c478bd9Sstevel@tonic-gate 
53167c478bd9Sstevel@tonic-gate 	for (; uiop->uio_resid > 0; uiop->uio_offset = off + PRSDSIZE) {
53177c478bd9Sstevel@tonic-gate 		/*
53187c478bd9Sstevel@tonic-gate 		 * There are 4 special files in the path directory: ".", "..",
53197c478bd9Sstevel@tonic-gate 		 * "root", and "cwd".  We handle those specially here.
53207c478bd9Sstevel@tonic-gate 		 */
53217c478bd9Sstevel@tonic-gate 		off = uiop->uio_offset;
53227c478bd9Sstevel@tonic-gate 		idx = off / PRSDSIZE;
53237c478bd9Sstevel@tonic-gate 		if (off == 0) {				/* "." */
53247c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(0, pslot, PR_PATHDIR);
53257c478bd9Sstevel@tonic-gate 			dirent->d_name[0] = '.';
53267c478bd9Sstevel@tonic-gate 			dirent->d_name[1] = '\0';
53277c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(1);
53287c478bd9Sstevel@tonic-gate 		} else if (idx == 1) {			/* ".." */
53297c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(0, pslot, PR_PIDDIR);
53307c478bd9Sstevel@tonic-gate 			dirent->d_name[0] = '.';
53317c478bd9Sstevel@tonic-gate 			dirent->d_name[1] = '.';
53327c478bd9Sstevel@tonic-gate 			dirent->d_name[2] = '\0';
53337c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(2);
53347c478bd9Sstevel@tonic-gate 		} else if (idx == 2) {			/* "root" */
53357c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
53367c478bd9Sstevel@tonic-gate 			(void) strcpy(dirent->d_name, "root");
53377c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(4);
53387c478bd9Sstevel@tonic-gate 		} else if (idx == 3) {			/* "cwd" */
53397c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
53407c478bd9Sstevel@tonic-gate 			(void) strcpy(dirent->d_name, "cwd");
53417c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(3);
53427c478bd9Sstevel@tonic-gate 		} else if (idx < 4 + fddirsize) {
53437c478bd9Sstevel@tonic-gate 			/*
53447c478bd9Sstevel@tonic-gate 			 * In this case, we have one of the file descriptors.
53457c478bd9Sstevel@tonic-gate 			 */
53467c478bd9Sstevel@tonic-gate 			fd = idx - 4;
53477c478bd9Sstevel@tonic-gate 			if (fip->fi_list[fd].uf_file == NULL)
53487c478bd9Sstevel@tonic-gate 				continue;
53497c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
53507c478bd9Sstevel@tonic-gate 			(void) pr_u32tos(fd, dirent->d_name, PLNSIZ+1);
53517c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(PLNSIZ);
53527c478bd9Sstevel@tonic-gate 		} else if (idx < 4 + fddirsize + objdirsize) {
53537c478bd9Sstevel@tonic-gate 			if (fip != NULL) {
53547c478bd9Sstevel@tonic-gate 				mutex_exit(&fip->fi_lock);
53557c478bd9Sstevel@tonic-gate 				fip = NULL;
53567c478bd9Sstevel@tonic-gate 			}
53577c478bd9Sstevel@tonic-gate 
53587c478bd9Sstevel@tonic-gate 			/*
53597c478bd9Sstevel@tonic-gate 			 * We drop p_lock before grabbing the address space lock
53607c478bd9Sstevel@tonic-gate 			 * in order to avoid a deadlock with the clock thread.
53617c478bd9Sstevel@tonic-gate 			 * The process will not disappear and its address space
53627c478bd9Sstevel@tonic-gate 			 * will not change because it is marked P_PR_LOCK.
53637c478bd9Sstevel@tonic-gate 			 */
53647c478bd9Sstevel@tonic-gate 			if (as == NULL) {
53657c478bd9Sstevel@tonic-gate 				as = p->p_as;
5366*dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_ENTER(as, RW_WRITER);
53677c478bd9Sstevel@tonic-gate 			}
53687c478bd9Sstevel@tonic-gate 
53697c478bd9Sstevel@tonic-gate 			if (as->a_updatedir) {
53707c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
53717c478bd9Sstevel@tonic-gate 				objdirsize = as->a_sizedir;
53727c478bd9Sstevel@tonic-gate 			}
53737c478bd9Sstevel@tonic-gate 
53747c478bd9Sstevel@tonic-gate 			obj = idx - 4 - fddirsize;
53757c478bd9Sstevel@tonic-gate 			if ((vp = obj_entry(as, obj)) == NULL)
53767c478bd9Sstevel@tonic-gate 				continue;
53777c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
5378da6c28aaSamw 			if (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) != 0)
53797c478bd9Sstevel@tonic-gate 				continue;
53807c478bd9Sstevel@tonic-gate 			if (vp == p->p_exec)
53817c478bd9Sstevel@tonic-gate 				(void) strcpy(dirent->d_name, "a.out");
53827c478bd9Sstevel@tonic-gate 			else
53837c478bd9Sstevel@tonic-gate 				pr_object_name(dirent->d_name, vp, &vattr);
53847c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
53857c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(strlen(dirent->d_name));
53867c478bd9Sstevel@tonic-gate 		} else {
53877c478bd9Sstevel@tonic-gate 			break;
53887c478bd9Sstevel@tonic-gate 		}
53897c478bd9Sstevel@tonic-gate 
53907c478bd9Sstevel@tonic-gate 		dirent->d_off = uiop->uio_offset + PRSDSIZE;
53917c478bd9Sstevel@tonic-gate 		dirent->d_reclen = (ushort_t)reclen;
53927c478bd9Sstevel@tonic-gate 		if (reclen > uiop->uio_resid) {
53937c478bd9Sstevel@tonic-gate 			/*
53947c478bd9Sstevel@tonic-gate 			 * Error if no entries have been returned yet.
53957c478bd9Sstevel@tonic-gate 			 */
53967c478bd9Sstevel@tonic-gate 			if (uiop->uio_resid == oresid)
53977c478bd9Sstevel@tonic-gate 				error = EINVAL;
53987c478bd9Sstevel@tonic-gate 			break;
53997c478bd9Sstevel@tonic-gate 		}
54007c478bd9Sstevel@tonic-gate 		/*
54017c478bd9Sstevel@tonic-gate 		 * Drop the address space lock to do the uiomove().
54027c478bd9Sstevel@tonic-gate 		 */
54037c478bd9Sstevel@tonic-gate 		if (as != NULL)
5404*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
54057c478bd9Sstevel@tonic-gate 
54067c478bd9Sstevel@tonic-gate 		error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop);
54077c478bd9Sstevel@tonic-gate 		if (as != NULL)
5408*dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
54097c478bd9Sstevel@tonic-gate 
54107c478bd9Sstevel@tonic-gate 		if (error)
54117c478bd9Sstevel@tonic-gate 			break;
54127c478bd9Sstevel@tonic-gate 	}
54137c478bd9Sstevel@tonic-gate 
54147c478bd9Sstevel@tonic-gate 	if (error == 0 && eofp)
54157c478bd9Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= (fddirsize + 2) * PRSDSIZE);
54167c478bd9Sstevel@tonic-gate 
54177c478bd9Sstevel@tonic-gate 	if (fip != NULL)
54187c478bd9Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
54197c478bd9Sstevel@tonic-gate 	if (as != NULL)
5420*dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
54217c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
54227c478bd9Sstevel@tonic-gate 	prunlock(pnp);
54237c478bd9Sstevel@tonic-gate 	return (error);
54247c478bd9Sstevel@tonic-gate }
54257c478bd9Sstevel@tonic-gate 
54267c478bd9Sstevel@tonic-gate static int
54277c478bd9Sstevel@tonic-gate pr_readdir_tmpldir(prnode_t *pnp, uio_t *uiop, int *eofp)
54287c478bd9Sstevel@tonic-gate {
54297c478bd9Sstevel@tonic-gate 	proc_t *p;
54307c478bd9Sstevel@tonic-gate 	int pslot, tslot;
54317c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
54327c478bd9Sstevel@tonic-gate 	int error, eof = 0;
54337c478bd9Sstevel@tonic-gate 	offset_t n;
54347c478bd9Sstevel@tonic-gate 
54357c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_TMPLDIR);
54367c478bd9Sstevel@tonic-gate 
54377c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
54387c478bd9Sstevel@tonic-gate 		return (error);
54397c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
54407c478bd9Sstevel@tonic-gate 	pslot = pnp->pr_common->prc_slot;
54417c478bd9Sstevel@tonic-gate 	tslot = pnp->pr_common->prc_tslot;
54427c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
54437c478bd9Sstevel@tonic-gate 
54447c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
54457c478bd9Sstevel@tonic-gate 	    pmkino(tslot, pslot, PR_LWPDIR),
5446b38f0970Sck153898 	    pmkino(tslot, pslot, PR_TMPLDIR), 0)) != 0) {
54477c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
54487c478bd9Sstevel@tonic-gate 		prunlock(pnp);
54497c478bd9Sstevel@tonic-gate 		return (error);
54507c478bd9Sstevel@tonic-gate 	}
54517c478bd9Sstevel@tonic-gate 
54527c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
54537c478bd9Sstevel@tonic-gate 		/*
54547c478bd9Sstevel@tonic-gate 		 * Check for an active template.  Reading a directory's
54557c478bd9Sstevel@tonic-gate 		 * contents is already racy, so we don't bother taking
54567c478bd9Sstevel@tonic-gate 		 * any locks.
54577c478bd9Sstevel@tonic-gate 		 */
54587c478bd9Sstevel@tonic-gate 		while (n < ct_ntypes &&
54597c478bd9Sstevel@tonic-gate 		    pnp->pr_common->prc_thread->t_lwp->lwp_ct_active[n] == NULL)
54607c478bd9Sstevel@tonic-gate 			n++;
54617c478bd9Sstevel@tonic-gate 		/*
54627c478bd9Sstevel@tonic-gate 		 * Stop when all types have been reported.
54637c478bd9Sstevel@tonic-gate 		 */
54647c478bd9Sstevel@tonic-gate 		if (n >= ct_ntypes) {
54657c478bd9Sstevel@tonic-gate 			eof = 1;
54667c478bd9Sstevel@tonic-gate 			break;
54677c478bd9Sstevel@tonic-gate 		}
54687c478bd9Sstevel@tonic-gate 		/*
54697c478bd9Sstevel@tonic-gate 		 * The pmkino invocation below will need to be updated
54707c478bd9Sstevel@tonic-gate 		 * when we create our fifth contract type.
54717c478bd9Sstevel@tonic-gate 		 */
54727c478bd9Sstevel@tonic-gate 		ASSERT(ct_ntypes <= 4);
54737c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emit(&gstate, uiop, n,
54747c478bd9Sstevel@tonic-gate 		    pmkino((tslot << 2) | n, pslot, PR_TMPL),
5475b38f0970Sck153898 		    ct_types[n]->ct_type_name, 0);
54767c478bd9Sstevel@tonic-gate 		if (error)
54777c478bd9Sstevel@tonic-gate 			break;
54787c478bd9Sstevel@tonic-gate 	}
54797c478bd9Sstevel@tonic-gate 
54807c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
54817c478bd9Sstevel@tonic-gate 	prunlock(pnp);
54827c478bd9Sstevel@tonic-gate 
54837c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
54847c478bd9Sstevel@tonic-gate }
54857c478bd9Sstevel@tonic-gate 
54867c478bd9Sstevel@tonic-gate static int
54877c478bd9Sstevel@tonic-gate pr_readdir_ctdir(prnode_t *pnp, uio_t *uiop, int *eofp)
54887c478bd9Sstevel@tonic-gate {
54897c478bd9Sstevel@tonic-gate 	proc_t *p;
54907c478bd9Sstevel@tonic-gate 	int pslot;
54917c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
54927c478bd9Sstevel@tonic-gate 	int error, eof = 0;
54937c478bd9Sstevel@tonic-gate 	offset_t n;
54947c478bd9Sstevel@tonic-gate 	uint64_t zid;
54957c478bd9Sstevel@tonic-gate 
54967c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_CTDIR);
54977c478bd9Sstevel@tonic-gate 
54987c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
54997c478bd9Sstevel@tonic-gate 		return (error);
55007c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
55017c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
55027c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
55037c478bd9Sstevel@tonic-gate 
55047c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
5505b38f0970Sck153898 	    pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_CTDIR), 0)) != 0) {
55067c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
55077c478bd9Sstevel@tonic-gate 		prunlock(pnp);
55087c478bd9Sstevel@tonic-gate 		return (error);
55097c478bd9Sstevel@tonic-gate 	}
55107c478bd9Sstevel@tonic-gate 
5511fa9e4066Sahrens 	zid = VTOZONE(pnp->pr_vnode)->zone_uniqid;
55127c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
55137c478bd9Sstevel@tonic-gate 		id_t next = contract_plookup(p, n, zid);
55147c478bd9Sstevel@tonic-gate 		if (next == -1) {
55157c478bd9Sstevel@tonic-gate 			eof = 1;
55167c478bd9Sstevel@tonic-gate 			break;
55177c478bd9Sstevel@tonic-gate 		}
55187c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, next,
55197c478bd9Sstevel@tonic-gate 		    pmkino(next, pslot, PR_CT), next);
55207c478bd9Sstevel@tonic-gate 		if (error)
55217c478bd9Sstevel@tonic-gate 			break;
55227c478bd9Sstevel@tonic-gate 	}
55237c478bd9Sstevel@tonic-gate 
55247c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
55257c478bd9Sstevel@tonic-gate 	prunlock(pnp);
55267c478bd9Sstevel@tonic-gate 
55277c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
55287c478bd9Sstevel@tonic-gate }
55297c478bd9Sstevel@tonic-gate 
55307c478bd9Sstevel@tonic-gate /* ARGSUSED */
55317c478bd9Sstevel@tonic-gate static int
5532da6c28aaSamw prfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
55337c478bd9Sstevel@tonic-gate {
55347c478bd9Sstevel@tonic-gate 	return (0);
55357c478bd9Sstevel@tonic-gate }
55367c478bd9Sstevel@tonic-gate 
55377c478bd9Sstevel@tonic-gate /*
55387c478bd9Sstevel@tonic-gate  * Utility: remove a /proc vnode from a linked list, threaded through pr_next.
55397c478bd9Sstevel@tonic-gate  */
55407c478bd9Sstevel@tonic-gate static void
55417c478bd9Sstevel@tonic-gate pr_list_unlink(vnode_t *pvp, vnode_t **listp)
55427c478bd9Sstevel@tonic-gate {
55437c478bd9Sstevel@tonic-gate 	vnode_t *vp;
55447c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
55457c478bd9Sstevel@tonic-gate 
55467c478bd9Sstevel@tonic-gate 	while ((vp = *listp) != NULL) {
55477c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
55487c478bd9Sstevel@tonic-gate 		if (vp == pvp) {
55497c478bd9Sstevel@tonic-gate 			*listp = pnp->pr_next;
55507c478bd9Sstevel@tonic-gate 			pnp->pr_next = NULL;
55517c478bd9Sstevel@tonic-gate 			break;
55527c478bd9Sstevel@tonic-gate 		}
55537c478bd9Sstevel@tonic-gate 		listp = &pnp->pr_next;
55547c478bd9Sstevel@tonic-gate 	}
55557c478bd9Sstevel@tonic-gate }
55567c478bd9Sstevel@tonic-gate 
55577c478bd9Sstevel@tonic-gate /* ARGSUSED */
55587c478bd9Sstevel@tonic-gate static void
5559da6c28aaSamw prinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
55607c478bd9Sstevel@tonic-gate {
55617c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
55627c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
55637c478bd9Sstevel@tonic-gate 	proc_t *p;
55647c478bd9Sstevel@tonic-gate 	vnode_t *dp;
55657c478bd9Sstevel@tonic-gate 	vnode_t *ovp = NULL;
55667c478bd9Sstevel@tonic-gate 	prnode_t *opnp = NULL;
55677c478bd9Sstevel@tonic-gate 
55687c478bd9Sstevel@tonic-gate 	switch (type) {
55697c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
55707c478bd9Sstevel@tonic-gate 	case PR_FD:
55717c478bd9Sstevel@tonic-gate 	case PR_SELF:
55727c478bd9Sstevel@tonic-gate 	case PR_PATH:
55737c478bd9Sstevel@tonic-gate 		/* These are not linked into the usual lists */
55747c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_count == 1);
55757c478bd9Sstevel@tonic-gate 		if ((dp = pnp->pr_parent) != NULL)
55767c478bd9Sstevel@tonic-gate 			VN_RELE(dp);
55777c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
55787c478bd9Sstevel@tonic-gate 		return;
55797c478bd9Sstevel@tonic-gate 	default:
55807c478bd9Sstevel@tonic-gate 		break;
55817c478bd9Sstevel@tonic-gate 	}
55827c478bd9Sstevel@tonic-gate 
55837c478bd9Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);
55847c478bd9Sstevel@tonic-gate 	if (pnp->pr_pcommon == NULL)
55857c478bd9Sstevel@tonic-gate 		p = NULL;
55867c478bd9Sstevel@tonic-gate 	else if ((p = pnp->pr_pcommon->prc_proc) != NULL)
55877c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
55887c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
55897c478bd9Sstevel@tonic-gate 
55907c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR || vp->v_count > 1) {
55917c478bd9Sstevel@tonic-gate 		vp->v_count--;
55927c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
55937c478bd9Sstevel@tonic-gate 		if (p != NULL)
55947c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
55957c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
55967c478bd9Sstevel@tonic-gate 		return;
55977c478bd9Sstevel@tonic-gate 	}
55987c478bd9Sstevel@tonic-gate 
55997c478bd9Sstevel@tonic-gate 	if ((dp = pnp->pr_parent) != NULL) {
56007c478bd9Sstevel@tonic-gate 		prnode_t *dpnp;
56017c478bd9Sstevel@tonic-gate 
56027c478bd9Sstevel@tonic-gate 		switch (type) {
56037c478bd9Sstevel@tonic-gate 		case PR_PIDFILE:
56047c478bd9Sstevel@tonic-gate 		case PR_LWPIDFILE:
56057c478bd9Sstevel@tonic-gate 		case PR_OPAGEDATA:
56067c478bd9Sstevel@tonic-gate 			break;
56077c478bd9Sstevel@tonic-gate 		default:
56087c478bd9Sstevel@tonic-gate 			dpnp = VTOP(dp);
56097c478bd9Sstevel@tonic-gate 			mutex_enter(&dpnp->pr_mutex);
56107c478bd9Sstevel@tonic-gate 			if (dpnp->pr_files != NULL &&
56117c478bd9Sstevel@tonic-gate 			    dpnp->pr_files[pnp->pr_index] == vp)
56127c478bd9Sstevel@tonic-gate 				dpnp->pr_files[pnp->pr_index] = NULL;
56137c478bd9Sstevel@tonic-gate 			mutex_exit(&dpnp->pr_mutex);
56147c478bd9Sstevel@tonic-gate 			break;
56157c478bd9Sstevel@tonic-gate 		}
56167c478bd9Sstevel@tonic-gate 		pnp->pr_parent = NULL;
56177c478bd9Sstevel@tonic-gate 	}
56187c478bd9Sstevel@tonic-gate 
56197c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count == 1);
56207c478bd9Sstevel@tonic-gate 
56217c478bd9Sstevel@tonic-gate 	/*
56227c478bd9Sstevel@tonic-gate 	 * If we allocated an old /proc/pid node, free it too.
56237c478bd9Sstevel@tonic-gate 	 */
56247c478bd9Sstevel@tonic-gate 	if (pnp->pr_pidfile != NULL) {
56257c478bd9Sstevel@tonic-gate 		ASSERT(type == PR_PIDDIR);
56267c478bd9Sstevel@tonic-gate 		ovp = pnp->pr_pidfile;
56277c478bd9Sstevel@tonic-gate 		opnp = VTOP(ovp);
56287c478bd9Sstevel@tonic-gate 		ASSERT(opnp->pr_type == PR_PIDFILE);
56297c478bd9Sstevel@tonic-gate 		pnp->pr_pidfile = NULL;
56307c478bd9Sstevel@tonic-gate 	}
56317c478bd9Sstevel@tonic-gate 
56327c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
56337c478bd9Sstevel@tonic-gate 
56347c478bd9Sstevel@tonic-gate 	if (p != NULL) {
56357c478bd9Sstevel@tonic-gate 		/*
56367c478bd9Sstevel@tonic-gate 		 * Remove the vnodes from the lists of
56377c478bd9Sstevel@tonic-gate 		 * /proc vnodes for the process.
56387c478bd9Sstevel@tonic-gate 		 */
56397c478bd9Sstevel@tonic-gate 		int slot;
56407c478bd9Sstevel@tonic-gate 
56417c478bd9Sstevel@tonic-gate 		switch (type) {
56427c478bd9Sstevel@tonic-gate 		case PR_PIDDIR:
56437c478bd9Sstevel@tonic-gate 			pr_list_unlink(vp, &p->p_trace);
56447c478bd9Sstevel@tonic-gate 			break;
56457c478bd9Sstevel@tonic-gate 		case PR_LWPIDDIR:
56467c478bd9Sstevel@tonic-gate 			if ((slot = pnp->pr_common->prc_tslot) != -1) {
56477c478bd9Sstevel@tonic-gate 				lwpent_t *lep = p->p_lwpdir[slot].ld_entry;
56487c478bd9Sstevel@tonic-gate 				pr_list_unlink(vp, &lep->le_trace);
56497c478bd9Sstevel@tonic-gate 			}
56507c478bd9Sstevel@tonic-gate 			break;
56517c478bd9Sstevel@tonic-gate 		default:
56527c478bd9Sstevel@tonic-gate 			pr_list_unlink(vp, &p->p_plist);
56537c478bd9Sstevel@tonic-gate 			break;
56547c478bd9Sstevel@tonic-gate 		}
56557c478bd9Sstevel@tonic-gate 		if (ovp != NULL)
56567c478bd9Sstevel@tonic-gate 			pr_list_unlink(ovp, &p->p_plist);
56577c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
56587c478bd9Sstevel@tonic-gate 	}
56597c478bd9Sstevel@tonic-gate 
56607c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
56617c478bd9Sstevel@tonic-gate 
56627c478bd9Sstevel@tonic-gate 	if (type == PR_CT && pnp->pr_contract != NULL) {
56637c478bd9Sstevel@tonic-gate 		contract_rele(pnp->pr_contract);
56647c478bd9Sstevel@tonic-gate 		pnp->pr_contract = NULL;
56657c478bd9Sstevel@tonic-gate 	}
56667c478bd9Sstevel@tonic-gate 
56677c478bd9Sstevel@tonic-gate 	if (opnp != NULL)
56687c478bd9Sstevel@tonic-gate 		prfreenode(opnp);
56697c478bd9Sstevel@tonic-gate 	prfreenode(pnp);
56707c478bd9Sstevel@tonic-gate 	if (dp != NULL) {
56717c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
56727c478bd9Sstevel@tonic-gate 	}
56737c478bd9Sstevel@tonic-gate }
56747c478bd9Sstevel@tonic-gate 
56757c478bd9Sstevel@tonic-gate /* ARGSUSED */
56767c478bd9Sstevel@tonic-gate static int
5677da6c28aaSamw prseek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
56787c478bd9Sstevel@tonic-gate {
56797c478bd9Sstevel@tonic-gate 	return (0);
56807c478bd9Sstevel@tonic-gate }
56817c478bd9Sstevel@tonic-gate 
56827c478bd9Sstevel@tonic-gate /*
56837c478bd9Sstevel@tonic-gate  * We use the p_execdir member of proc_t to expand the %d token in core file
56847c478bd9Sstevel@tonic-gate  * paths (the directory path for the executable that dumped core; see
56857c478bd9Sstevel@tonic-gate  * coreadm(1M) for details). We'd like gcore(1) to be able to expand %d in
56867c478bd9Sstevel@tonic-gate  * the same way as core dumping from the kernel, but there's no convenient
56877c478bd9Sstevel@tonic-gate  * and comprehensible way to export the path name for p_execdir. To solve
56887c478bd9Sstevel@tonic-gate  * this, we try to find the actual path to the executable that was used. In
56897c478bd9Sstevel@tonic-gate  * pr_lookup_pathdir(), we mark the a.out path name vnode with the PR_AOUT
56907c478bd9Sstevel@tonic-gate  * flag, and use that here to indicate that more work is needed beyond the
56917c478bd9Sstevel@tonic-gate  * call to vnodetopath().
56927c478bd9Sstevel@tonic-gate  */
56937c478bd9Sstevel@tonic-gate static int
56947c478bd9Sstevel@tonic-gate prreadlink_lookup(prnode_t *pnp, char *buf, size_t size, cred_t *cr)
56957c478bd9Sstevel@tonic-gate {
56967c478bd9Sstevel@tonic-gate 	proc_t *p;
56977c478bd9Sstevel@tonic-gate 	vnode_t *vp, *execvp, *vrootp;
56987c478bd9Sstevel@tonic-gate 	int ret;
56997c478bd9Sstevel@tonic-gate 	size_t len;
57007c478bd9Sstevel@tonic-gate 	dirent64_t *dp;
57017c478bd9Sstevel@tonic-gate 	size_t dlen = DIRENT64_RECLEN(MAXPATHLEN);
57027c478bd9Sstevel@tonic-gate 	char *dbuf;
57037c478bd9Sstevel@tonic-gate 
57047c478bd9Sstevel@tonic-gate 	p = curproc;
57057c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
57067c478bd9Sstevel@tonic-gate 	if ((vrootp = PTOU(p)->u_rdir) == NULL)
57077c478bd9Sstevel@tonic-gate 		vrootp = rootdir;
57087c478bd9Sstevel@tonic-gate 	VN_HOLD(vrootp);
57097c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
57107c478bd9Sstevel@tonic-gate 
57117c478bd9Sstevel@tonic-gate 	ret = vnodetopath(vrootp, pnp->pr_realvp, buf, size, cr);
57127c478bd9Sstevel@tonic-gate 
57137c478bd9Sstevel@tonic-gate 	/*
57147c478bd9Sstevel@tonic-gate 	 * If PR_AOUT isn't set, then we looked up the path for the vnode;
57157c478bd9Sstevel@tonic-gate 	 * otherwise, we looked up the path for (what we believe to be) the
57167c478bd9Sstevel@tonic-gate 	 * containing directory.
57177c478bd9Sstevel@tonic-gate 	 */
57187c478bd9Sstevel@tonic-gate 	if ((pnp->pr_flags & PR_AOUT) == 0) {
57197c478bd9Sstevel@tonic-gate 		VN_RELE(vrootp);
57207c478bd9Sstevel@tonic-gate 		return (ret);
57217c478bd9Sstevel@tonic-gate 	}
57227c478bd9Sstevel@tonic-gate 
57237c478bd9Sstevel@tonic-gate 	/*
57247c478bd9Sstevel@tonic-gate 	 * Fail if there's a problem locking the process. This will only
57257c478bd9Sstevel@tonic-gate 	 * occur if the process is changing so the information we would
57267c478bd9Sstevel@tonic-gate 	 * report would already be invalid.
57277c478bd9Sstevel@tonic-gate 	 */
57287c478bd9Sstevel@tonic-gate 	if (prlock(pnp, ZNO) != 0) {
57297c478bd9Sstevel@tonic-gate 		VN_RELE(vrootp);
57307c478bd9Sstevel@tonic-gate 		return (EIO);
57317c478bd9Sstevel@tonic-gate 	}
57327c478bd9Sstevel@tonic-gate 
57337c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
57347c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
57357c478bd9Sstevel@tonic-gate 
57367c478bd9Sstevel@tonic-gate 	execvp = p->p_exec;
57377c478bd9Sstevel@tonic-gate 	VN_HOLD(execvp);
57387c478bd9Sstevel@tonic-gate 
57397c478bd9Sstevel@tonic-gate 	/*
57407c478bd9Sstevel@tonic-gate 	 * If our initial lookup of the directory failed, fall back to
57417c478bd9Sstevel@tonic-gate 	 * the path name information for p_exec.
57427c478bd9Sstevel@tonic-gate 	 */
57437c478bd9Sstevel@tonic-gate 	if (ret != 0) {
57447c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
57457c478bd9Sstevel@tonic-gate 		prunlock(pnp);
57467c478bd9Sstevel@tonic-gate 		ret = vnodetopath(vrootp, execvp, buf, size, cr);
57477c478bd9Sstevel@tonic-gate 		VN_RELE(execvp);
57487c478bd9Sstevel@tonic-gate 		VN_RELE(vrootp);
57497c478bd9Sstevel@tonic-gate 		return (ret);
57507c478bd9Sstevel@tonic-gate 	}
57517c478bd9Sstevel@tonic-gate 
57527c478bd9Sstevel@tonic-gate 	len = strlen(buf);
57537c478bd9Sstevel@tonic-gate 
57547c478bd9Sstevel@tonic-gate 	/*
57557c478bd9Sstevel@tonic-gate 	 * We use u_comm as a guess for the last component of the full
57567c478bd9Sstevel@tonic-gate 	 * executable path name. If there isn't going to be enough space
57577c478bd9Sstevel@tonic-gate 	 * we fall back to using the p_exec so that we can have _an_
57587c478bd9Sstevel@tonic-gate 	 * answer even if it's not perfect.
57597c478bd9Sstevel@tonic-gate 	 */
57607c478bd9Sstevel@tonic-gate 	if (strlen(PTOU(p)->u_comm) + len + 1 < size) {
57617c478bd9Sstevel@tonic-gate 		buf[len] = '/';
57627c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, PTOU(p)->u_comm);
57637c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
57647c478bd9Sstevel@tonic-gate 		prunlock(pnp);
57657c478bd9Sstevel@tonic-gate 
57667c478bd9Sstevel@tonic-gate 		/*
57677c478bd9Sstevel@tonic-gate 		 * Do a forward lookup of our u_comm guess.
57687c478bd9Sstevel@tonic-gate 		 */
57697c478bd9Sstevel@tonic-gate 		if (lookupnameat(buf + len + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
57707c478bd9Sstevel@tonic-gate 		    &vp, pnp->pr_realvp) == 0) {
57717c478bd9Sstevel@tonic-gate 			if (vn_compare(vp, execvp)) {
57727c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
57737c478bd9Sstevel@tonic-gate 				VN_RELE(execvp);
57747c478bd9Sstevel@tonic-gate 				VN_RELE(vrootp);
57757c478bd9Sstevel@tonic-gate 				return (0);
57767c478bd9Sstevel@tonic-gate 			}
57777c478bd9Sstevel@tonic-gate 
57787c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
57797c478bd9Sstevel@tonic-gate 		}
57807c478bd9Sstevel@tonic-gate 	} else {
57817c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
57827c478bd9Sstevel@tonic-gate 		prunlock(pnp);
57837c478bd9Sstevel@tonic-gate 	}
57847c478bd9Sstevel@tonic-gate 
57857c478bd9Sstevel@tonic-gate 	dbuf = kmem_alloc(dlen, KM_SLEEP);
57867c478bd9Sstevel@tonic-gate 
57877c478bd9Sstevel@tonic-gate 	/*
57887c478bd9Sstevel@tonic-gate 	 * Try to find a matching vnode by iterating through the directory's
57897c478bd9Sstevel@tonic-gate 	 * entries. If that fails, fall back to the path information for
57907c478bd9Sstevel@tonic-gate 	 * p_exec.
57917c478bd9Sstevel@tonic-gate 	 */
57927c478bd9Sstevel@tonic-gate 	if ((ret = dirfindvp(vrootp, pnp->pr_realvp, execvp, cr, dbuf,
57937c478bd9Sstevel@tonic-gate 	    dlen, &dp)) == 0 && strlen(dp->d_name) + len + 1 < size) {
57947c478bd9Sstevel@tonic-gate 		buf[len] = '/';
57957c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, dp->d_name);
57967c478bd9Sstevel@tonic-gate 	} else {
57977c478bd9Sstevel@tonic-gate 		ret = vnodetopath(vrootp, execvp, buf, size, cr);
57987c478bd9Sstevel@tonic-gate 	}
57997c478bd9Sstevel@tonic-gate 
58007c478bd9Sstevel@tonic-gate 	kmem_free(dbuf, dlen);
58017c478bd9Sstevel@tonic-gate 	VN_RELE(execvp);
58027c478bd9Sstevel@tonic-gate 	VN_RELE(vrootp);
58037c478bd9Sstevel@tonic-gate 
58047c478bd9Sstevel@tonic-gate 	return (ret);
58057c478bd9Sstevel@tonic-gate }
58067c478bd9Sstevel@tonic-gate 
58077c478bd9Sstevel@tonic-gate /* ARGSUSED */
58087c478bd9Sstevel@tonic-gate static int
5809da6c28aaSamw prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ctp)
58107c478bd9Sstevel@tonic-gate {
58117c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
58127c478bd9Sstevel@tonic-gate 	char *buf;
58137c478bd9Sstevel@tonic-gate 	int ret = EINVAL;
58147c478bd9Sstevel@tonic-gate 	char idbuf[16];
58157c478bd9Sstevel@tonic-gate 	int length, rlength;
58167c478bd9Sstevel@tonic-gate 	contract_t *ct;
58177c478bd9Sstevel@tonic-gate 
58187c478bd9Sstevel@tonic-gate 	switch (pnp->pr_type) {
58197c478bd9Sstevel@tonic-gate 	case PR_SELF:
58207c478bd9Sstevel@tonic-gate 		(void) snprintf(idbuf, sizeof (idbuf), "%d", curproc->p_pid);
58217c478bd9Sstevel@tonic-gate 		ret = uiomove(idbuf, strlen(idbuf), UIO_READ, uiop);
58227c478bd9Sstevel@tonic-gate 		break;
58237c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
58247c478bd9Sstevel@tonic-gate 	case PR_FD:
58257c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
58267c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
58277c478bd9Sstevel@tonic-gate 		if (pnp->pr_realvp->v_type == VDIR)
58287c478bd9Sstevel@tonic-gate 			ret = 0;
58297c478bd9Sstevel@tonic-gate 		break;
58307c478bd9Sstevel@tonic-gate 	case PR_PATH:
58317c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
58327c478bd9Sstevel@tonic-gate 
58337c478bd9Sstevel@tonic-gate 		if ((ret = prreadlink_lookup(pnp, buf, MAXPATHLEN, cr)) == 0)
58347c478bd9Sstevel@tonic-gate 			ret = uiomove(buf, strlen(buf), UIO_READ, uiop);
58357c478bd9Sstevel@tonic-gate 
58367c478bd9Sstevel@tonic-gate 		kmem_free(buf, MAXPATHLEN);
58377c478bd9Sstevel@tonic-gate 		break;
58387c478bd9Sstevel@tonic-gate 	case PR_CT:
58397c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_contract != NULL);
58407c478bd9Sstevel@tonic-gate 		ct = pnp->pr_contract;
58417c478bd9Sstevel@tonic-gate 		length = sizeof (CTFS_ROOT "//") + sizeof (idbuf) +
58427c478bd9Sstevel@tonic-gate 		    strlen(ct->ct_type->ct_type_name);
58437c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(length, KM_SLEEP);
58447c478bd9Sstevel@tonic-gate 		rlength = snprintf(buf, length, CTFS_ROOT "/%s/%d",
58457c478bd9Sstevel@tonic-gate 		    ct->ct_type->ct_type_name, ct->ct_id);
58467c478bd9Sstevel@tonic-gate 		ASSERT(rlength < length);
58477c478bd9Sstevel@tonic-gate 		ret = uiomove(buf, rlength, UIO_READ, uiop);
58487c478bd9Sstevel@tonic-gate 		kmem_free(buf, length);
58497c478bd9Sstevel@tonic-gate 		break;
58507c478bd9Sstevel@tonic-gate 	default:
58517c478bd9Sstevel@tonic-gate 		break;
58527c478bd9Sstevel@tonic-gate 	}
58537c478bd9Sstevel@tonic-gate 
58547c478bd9Sstevel@tonic-gate 	return (ret);
58557c478bd9Sstevel@tonic-gate }
58567c478bd9Sstevel@tonic-gate 
5857da6c28aaSamw /*ARGSUSED2*/
58587c478bd9Sstevel@tonic-gate static int
5859da6c28aaSamw prcmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
58607c478bd9Sstevel@tonic-gate {
58617c478bd9Sstevel@tonic-gate 	prnode_t *pp1, *pp2;
58627c478bd9Sstevel@tonic-gate 
58637c478bd9Sstevel@tonic-gate 	if (vp1 == vp2)
58647c478bd9Sstevel@tonic-gate 		return (1);
58657c478bd9Sstevel@tonic-gate 
58667c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp1, prvnodeops) || !vn_matchops(vp2, prvnodeops))
58677c478bd9Sstevel@tonic-gate 		return (0);
58687c478bd9Sstevel@tonic-gate 
58697c478bd9Sstevel@tonic-gate 	pp1 = VTOP(vp1);
58707c478bd9Sstevel@tonic-gate 	pp2 = VTOP(vp2);
58717c478bd9Sstevel@tonic-gate 
58727c478bd9Sstevel@tonic-gate 	if (pp1->pr_type != pp2->pr_type)
58737c478bd9Sstevel@tonic-gate 		return (0);
58747c478bd9Sstevel@tonic-gate 	if (pp1->pr_type == PR_PROCDIR)
58757c478bd9Sstevel@tonic-gate 		return (1);
58767c478bd9Sstevel@tonic-gate 	if (pp1->pr_ino || pp2->pr_ino)
58777c478bd9Sstevel@tonic-gate 		return (pp2->pr_ino == pp1->pr_ino);
58787c478bd9Sstevel@tonic-gate 
58797c478bd9Sstevel@tonic-gate 	if (pp1->pr_common == NULL || pp2->pr_common == NULL)
58807c478bd9Sstevel@tonic-gate 		return (0);
58817c478bd9Sstevel@tonic-gate 
58827c478bd9Sstevel@tonic-gate 	return (pp1->pr_common->prc_slot == pp2->pr_common->prc_slot &&
58837c478bd9Sstevel@tonic-gate 	    pp1->pr_common->prc_tslot == pp2->pr_common->prc_tslot);
58847c478bd9Sstevel@tonic-gate }
58857c478bd9Sstevel@tonic-gate 
58867c478bd9Sstevel@tonic-gate static int
5887da6c28aaSamw prrealvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
58887c478bd9Sstevel@tonic-gate {
58897c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
58907c478bd9Sstevel@tonic-gate 
58917c478bd9Sstevel@tonic-gate 	if ((rvp = VTOP(vp)->pr_realvp) != NULL) {
58927c478bd9Sstevel@tonic-gate 		vp = rvp;
5893da6c28aaSamw 		if (VOP_REALVP(vp, &rvp, ct) == 0)
58947c478bd9Sstevel@tonic-gate 			vp = rvp;
58957c478bd9Sstevel@tonic-gate 	}
58967c478bd9Sstevel@tonic-gate 
58977c478bd9Sstevel@tonic-gate 	*vpp = vp;
58987c478bd9Sstevel@tonic-gate 	return (0);
58997c478bd9Sstevel@tonic-gate }
59007c478bd9Sstevel@tonic-gate 
59017c478bd9Sstevel@tonic-gate /*
59027c478bd9Sstevel@tonic-gate  * Return the answer requested to poll().
59037c478bd9Sstevel@tonic-gate  * POLLIN, POLLRDNORM, and POLLOUT are recognized as in fs_poll().
59047c478bd9Sstevel@tonic-gate  * In addition, these have special meaning for /proc files:
59057c478bd9Sstevel@tonic-gate  *	POLLPRI		process or lwp stopped on an event of interest
59067c478bd9Sstevel@tonic-gate  *	POLLERR		/proc file descriptor is invalid
59077c478bd9Sstevel@tonic-gate  *	POLLHUP		process or lwp has terminated
59087c478bd9Sstevel@tonic-gate  */
5909da6c28aaSamw /*ARGSUSED5*/
59107c478bd9Sstevel@tonic-gate static int
59117c478bd9Sstevel@tonic-gate prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
5912da6c28aaSamw 	pollhead_t **phpp, caller_context_t *ct)
59137c478bd9Sstevel@tonic-gate {
59147c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
59157c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
59167c478bd9Sstevel@tonic-gate 	pollhead_t *php = &pcp->prc_pollhead;
59177c478bd9Sstevel@tonic-gate 	proc_t *p;
59187c478bd9Sstevel@tonic-gate 	short revents;
59197c478bd9Sstevel@tonic-gate 	int error;
59207c478bd9Sstevel@tonic-gate 	int lockstate;
59217c478bd9Sstevel@tonic-gate 
59227c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
59237c478bd9Sstevel@tonic-gate 
59247c478bd9Sstevel@tonic-gate 	/*
59257c478bd9Sstevel@tonic-gate 	 * Support for old /proc interface.
59267c478bd9Sstevel@tonic-gate 	 */
59277c478bd9Sstevel@tonic-gate 	if (pnp->pr_pidfile != NULL) {
59287c478bd9Sstevel@tonic-gate 		vp = pnp->pr_pidfile;
59297c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
59307c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_type == PR_PIDFILE);
59317c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_common == pcp);
59327c478bd9Sstevel@tonic-gate 	}
59337c478bd9Sstevel@tonic-gate 
59347c478bd9Sstevel@tonic-gate 	*reventsp = revents = 0;
59357c478bd9Sstevel@tonic-gate 	*phpp = (pollhead_t *)NULL;
59367c478bd9Sstevel@tonic-gate 
59377c478bd9Sstevel@tonic-gate 	if (vp->v_type == VDIR) {
59387c478bd9Sstevel@tonic-gate 		*reventsp |= POLLNVAL;
59397c478bd9Sstevel@tonic-gate 		return (0);
59407c478bd9Sstevel@tonic-gate 	}
59417c478bd9Sstevel@tonic-gate 
5942f3bb54f3SPatrick Mooney 	/* avoid deadlock with prnotify() */
5943f3bb54f3SPatrick Mooney 	if (pollunlock(&lockstate) != 0) {
5944f3bb54f3SPatrick Mooney 		*reventsp = POLLNVAL;
5945f3bb54f3SPatrick Mooney 		return (0);
5946f3bb54f3SPatrick Mooney 	}
59477c478bd9Sstevel@tonic-gate 
59487c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0) {
59497c478bd9Sstevel@tonic-gate 		pollrelock(lockstate);
59507c478bd9Sstevel@tonic-gate 		switch (error) {
59517c478bd9Sstevel@tonic-gate 		case ENOENT:		/* process or lwp died */
59527c478bd9Sstevel@tonic-gate 			*reventsp = POLLHUP;
59537c478bd9Sstevel@tonic-gate 			error = 0;
59547c478bd9Sstevel@tonic-gate 			break;
59557c478bd9Sstevel@tonic-gate 		case EAGAIN:		/* invalidated */
59567c478bd9Sstevel@tonic-gate 			*reventsp = POLLERR;
59577c478bd9Sstevel@tonic-gate 			error = 0;
59587c478bd9Sstevel@tonic-gate 			break;
59597c478bd9Sstevel@tonic-gate 		}
59607c478bd9Sstevel@tonic-gate 		return (error);
59617c478bd9Sstevel@tonic-gate 	}
59627c478bd9Sstevel@tonic-gate 
59637c478bd9Sstevel@tonic-gate 	/*
59647c478bd9Sstevel@tonic-gate 	 * We have the process marked locked (P_PR_LOCK) and we are holding
59657c478bd9Sstevel@tonic-gate 	 * its p->p_lock.  We want to unmark the process but retain
59667c478bd9Sstevel@tonic-gate 	 * exclusive control w.r.t. other /proc controlling processes
59677c478bd9Sstevel@tonic-gate 	 * before reacquiring the polling locks.
59687c478bd9Sstevel@tonic-gate 	 *
59697c478bd9Sstevel@tonic-gate 	 * prunmark() does this for us.  It unmarks the process
59707c478bd9Sstevel@tonic-gate 	 * but retains p->p_lock so we still have exclusive control.
59717c478bd9Sstevel@tonic-gate 	 * We will drop p->p_lock at the end to relinquish control.
59727c478bd9Sstevel@tonic-gate 	 *
59737c478bd9Sstevel@tonic-gate 	 * We cannot call prunlock() at the end to relinquish control
59747c478bd9Sstevel@tonic-gate 	 * because prunlock(), like prunmark(), may drop and reacquire
59757c478bd9Sstevel@tonic-gate 	 * p->p_lock and that would lead to a lock order violation
59767c478bd9Sstevel@tonic-gate 	 * w.r.t. the polling locks we are about to reacquire.
59777c478bd9Sstevel@tonic-gate 	 */
59787c478bd9Sstevel@tonic-gate 	p = pcp->prc_proc;
59797c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
59807c478bd9Sstevel@tonic-gate 	prunmark(p);
59817c478bd9Sstevel@tonic-gate 
59827c478bd9Sstevel@tonic-gate 	pollrelock(lockstate);		/* reacquire dropped poll locks */
59837c478bd9Sstevel@tonic-gate 
59847c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
59857c478bd9Sstevel@tonic-gate 		revents = POLLNVAL;
59867c478bd9Sstevel@tonic-gate 	else {
59877c478bd9Sstevel@tonic-gate 		short ev;
59887c478bd9Sstevel@tonic-gate 
59897c478bd9Sstevel@tonic-gate 		if ((ev = (events & (POLLIN|POLLRDNORM))) != 0)
59907c478bd9Sstevel@tonic-gate 			revents |= ev;
59917c478bd9Sstevel@tonic-gate 		/*
59927c478bd9Sstevel@tonic-gate 		 * POLLWRNORM (same as POLLOUT) really should not be
59937c478bd9Sstevel@tonic-gate 		 * used to indicate that the process or lwp stopped.
59947c478bd9Sstevel@tonic-gate 		 * However, USL chose to use POLLWRNORM rather than
59957c478bd9Sstevel@tonic-gate 		 * POLLPRI to indicate this, so we just accept either
59967c478bd9Sstevel@tonic-gate 		 * requested event to indicate stopped.  (grr...)
59977c478bd9Sstevel@tonic-gate 		 */
59987c478bd9Sstevel@tonic-gate 		if ((ev = (events & (POLLPRI|POLLOUT|POLLWRNORM))) != 0) {
59997c478bd9Sstevel@tonic-gate 			kthread_t *t;
60007c478bd9Sstevel@tonic-gate 
60017c478bd9Sstevel@tonic-gate 			if (pcp->prc_flags & PRC_LWP) {
60027c478bd9Sstevel@tonic-gate 				t = pcp->prc_thread;
60037c478bd9Sstevel@tonic-gate 				ASSERT(t != NULL);
60047c478bd9Sstevel@tonic-gate 				thread_lock(t);
60057c478bd9Sstevel@tonic-gate 			} else {
60067c478bd9Sstevel@tonic-gate 				t = prchoose(p);	/* returns locked t */
60077c478bd9Sstevel@tonic-gate 				ASSERT(t != NULL);
60087c478bd9Sstevel@tonic-gate 			}
60097c478bd9Sstevel@tonic-gate 
60107c478bd9Sstevel@tonic-gate 			if (ISTOPPED(t) || VSTOPPED(t))
60117c478bd9Sstevel@tonic-gate 				revents |= ev;
60127c478bd9Sstevel@tonic-gate 			thread_unlock(t);
60137c478bd9Sstevel@tonic-gate 		}
60147c478bd9Sstevel@tonic-gate 	}
60157c478bd9Sstevel@tonic-gate 
60167c478bd9Sstevel@tonic-gate 	*reventsp = revents;
6017a5eb7107SBryan Cantrill 	if ((!anyyet && revents == 0) || (events & POLLET)) {
60187c478bd9Sstevel@tonic-gate 		/*
60197c478bd9Sstevel@tonic-gate 		 * Arrange to wake up the polling lwp when
60207c478bd9Sstevel@tonic-gate 		 * the target process/lwp stops or terminates
60217c478bd9Sstevel@tonic-gate 		 * or when the file descriptor becomes invalid.
60227c478bd9Sstevel@tonic-gate 		 */
60237c478bd9Sstevel@tonic-gate 		pcp->prc_flags |= PRC_POLL;
60247c478bd9Sstevel@tonic-gate 		*phpp = php;
60257c478bd9Sstevel@tonic-gate 	}
60267c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
60277c478bd9Sstevel@tonic-gate 	return (0);
60287c478bd9Sstevel@tonic-gate }
60297c478bd9Sstevel@tonic-gate 
60307c478bd9Sstevel@tonic-gate /* in prioctl.c */
6031da6c28aaSamw extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
6032da6c28aaSamw 	caller_context_t *);
60337c478bd9Sstevel@tonic-gate 
60347c478bd9Sstevel@tonic-gate /*
60357c478bd9Sstevel@tonic-gate  * /proc vnode operations vector
60367c478bd9Sstevel@tonic-gate  */
60377c478bd9Sstevel@tonic-gate const fs_operation_def_t pr_vnodeops_template[] = {
6038aa59c4cbSrsb 	VOPNAME_OPEN,		{ .vop_open = propen },
6039aa59c4cbSrsb 	VOPNAME_CLOSE,		{ .vop_close = prclose },
6040aa59c4cbSrsb 	VOPNAME_READ,		{ .vop_read = prread },
6041aa59c4cbSrsb 	VOPNAME_WRITE,		{ .vop_write = prwrite },
6042aa59c4cbSrsb 	VOPNAME_IOCTL,		{ .vop_ioctl = prioctl },
6043aa59c4cbSrsb 	VOPNAME_GETATTR,	{ .vop_getattr = prgetattr },
6044aa59c4cbSrsb 	VOPNAME_ACCESS,		{ .vop_access = praccess },
6045aa59c4cbSrsb 	VOPNAME_LOOKUP,		{ .vop_lookup = prlookup },
6046aa59c4cbSrsb 	VOPNAME_CREATE,		{ .vop_create = prcreate },
6047aa59c4cbSrsb 	VOPNAME_READDIR,	{ .vop_readdir = prreaddir },
6048aa59c4cbSrsb 	VOPNAME_READLINK,	{ .vop_readlink = prreadlink },
6049aa59c4cbSrsb 	VOPNAME_FSYNC,		{ .vop_fsync = prfsync },
6050aa59c4cbSrsb 	VOPNAME_INACTIVE,	{ .vop_inactive = prinactive },
6051aa59c4cbSrsb 	VOPNAME_SEEK,		{ .vop_seek = prseek },
6052aa59c4cbSrsb 	VOPNAME_CMP,		{ .vop_cmp = prcmp },
6053aa59c4cbSrsb 	VOPNAME_FRLOCK,		{ .error = fs_error },
6054aa59c4cbSrsb 	VOPNAME_REALVP,		{ .vop_realvp = prrealvp },
6055aa59c4cbSrsb 	VOPNAME_POLL,		{ .vop_poll = prpoll },
6056aa59c4cbSrsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
6057aa59c4cbSrsb 	VOPNAME_SHRLOCK,	{ .error = fs_error },
60587c478bd9Sstevel@tonic-gate 	NULL,			NULL
60597c478bd9Sstevel@tonic-gate };
6060