xref: /illumos-gate/usr/src/uts/common/fs/proc/prvnops.c (revision 552c19f2f4d9396d8a55dbeda82076c2ab380d3f)
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.
24ab618543SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
25ade42b55SSebastien Roy  * Copyright (c) 2017 by Delphix. All rights reserved.
26a02120c4SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
27da29c6a3SDan McDonald  * Copyright 2022 MNX Cloud, Inc.
28ed093b41SRobert Mustacchi  * Copyright 2023 Oxide Computer Company
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984,	 1986, 1987, 1988, 1989 AT&T	*/
327c478bd9Sstevel@tonic-gate /*	  All Rights Reserved	*/
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/types.h>
357c478bd9Sstevel@tonic-gate #include <sys/param.h>
367c478bd9Sstevel@tonic-gate #include <sys/time.h>
377c478bd9Sstevel@tonic-gate #include <sys/cred.h>
387c478bd9Sstevel@tonic-gate #include <sys/policy.h>
397c478bd9Sstevel@tonic-gate #include <sys/debug.h>
407c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
417c478bd9Sstevel@tonic-gate #include <sys/errno.h>
427c478bd9Sstevel@tonic-gate #include <sys/file.h>
437c478bd9Sstevel@tonic-gate #include <sys/inline.h>
447c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
457c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
467c478bd9Sstevel@tonic-gate #include <sys/proc.h>
47eb9dbf0cSRoger A. Faulkner #include <sys/brand.h>
487c478bd9Sstevel@tonic-gate #include <sys/signal.h>
497c478bd9Sstevel@tonic-gate #include <sys/stat.h>
507c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
517c478bd9Sstevel@tonic-gate #include <sys/systm.h>
527c478bd9Sstevel@tonic-gate #include <sys/zone.h>
537c478bd9Sstevel@tonic-gate #include <sys/uio.h>
547c478bd9Sstevel@tonic-gate #include <sys/var.h>
557c478bd9Sstevel@tonic-gate #include <sys/mode.h>
567c478bd9Sstevel@tonic-gate #include <sys/poll.h>
577c478bd9Sstevel@tonic-gate #include <sys/user.h>
587c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
59aa59c4cbSrsb #include <sys/vfs_opreg.h>
607c478bd9Sstevel@tonic-gate #include <sys/gfs.h>
617c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
627c478bd9Sstevel@tonic-gate #include <sys/fault.h>
637c478bd9Sstevel@tonic-gate #include <sys/syscall.h>
647c478bd9Sstevel@tonic-gate #include <sys/procfs.h>
657c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
667c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
677c478bd9Sstevel@tonic-gate #include <sys/contract_impl.h>
687c478bd9Sstevel@tonic-gate #include <sys/ctfs.h>
697c478bd9Sstevel@tonic-gate #include <sys/avl.h>
70ab618543SJohn Levon #include <sys/ctype.h>
717c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
727c478bd9Sstevel@tonic-gate #include <vm/rm.h>
737c478bd9Sstevel@tonic-gate #include <vm/as.h>
747c478bd9Sstevel@tonic-gate #include <vm/seg.h>
757c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
767c478bd9Sstevel@tonic-gate #include <vm/hat.h>
777c478bd9Sstevel@tonic-gate #include <fs/proc/prdata.h>
787c478bd9Sstevel@tonic-gate #if defined(__sparc)
797c478bd9Sstevel@tonic-gate #include <sys/regset.h>
807c478bd9Sstevel@tonic-gate #endif
817c478bd9Sstevel@tonic-gate #if defined(__x86)
827c478bd9Sstevel@tonic-gate #include <sys/sysi86.h>
837c478bd9Sstevel@tonic-gate #endif
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate /*
867c478bd9Sstevel@tonic-gate  * Created by prinit.
877c478bd9Sstevel@tonic-gate  */
887c478bd9Sstevel@tonic-gate vnodeops_t *prvnodeops;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * Directory characteristics (patterned after the s5 file system).
927c478bd9Sstevel@tonic-gate  */
937c478bd9Sstevel@tonic-gate #define	PRROOTINO	2
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #define	PRDIRSIZE	14
967c478bd9Sstevel@tonic-gate struct prdirect {
977c478bd9Sstevel@tonic-gate 	ushort_t	d_ino;
987c478bd9Sstevel@tonic-gate 	char		d_name[PRDIRSIZE];
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate #define	PRSDSIZE	(sizeof (struct prdirect))
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /*
1047c478bd9Sstevel@tonic-gate  * Directory characteristics.
1057c478bd9Sstevel@tonic-gate  */
1067c478bd9Sstevel@tonic-gate typedef struct prdirent {
1077c478bd9Sstevel@tonic-gate 	ino64_t		d_ino;		/* "inode number" of entry */
1087c478bd9Sstevel@tonic-gate 	off64_t		d_off;		/* offset of disk directory entry */
1097c478bd9Sstevel@tonic-gate 	unsigned short	d_reclen;	/* length of this record */
1107c478bd9Sstevel@tonic-gate 	char		d_name[14];	/* name of file */
1117c478bd9Sstevel@tonic-gate } prdirent_t;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * Contents of a /proc/<pid> directory.
1157c478bd9Sstevel@tonic-gate  * Reuse d_ino field for the /proc file type.
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate static prdirent_t piddir[] = {
1187c478bd9Sstevel@tonic-gate 	{ PR_PIDDIR,	 1 * sizeof (prdirent_t), sizeof (prdirent_t),
1197c478bd9Sstevel@tonic-gate 		"." },
1207c478bd9Sstevel@tonic-gate 	{ PR_PROCDIR,	 2 * sizeof (prdirent_t), sizeof (prdirent_t),
1217c478bd9Sstevel@tonic-gate 		".." },
1227c478bd9Sstevel@tonic-gate 	{ PR_AS,	 3 * sizeof (prdirent_t), sizeof (prdirent_t),
1237c478bd9Sstevel@tonic-gate 		"as" },
1247c478bd9Sstevel@tonic-gate 	{ PR_CTL,	 4 * sizeof (prdirent_t), sizeof (prdirent_t),
1257c478bd9Sstevel@tonic-gate 		"ctl" },
1267c478bd9Sstevel@tonic-gate 	{ PR_STATUS,	 5 * sizeof (prdirent_t), sizeof (prdirent_t),
1277c478bd9Sstevel@tonic-gate 		"status" },
1287c478bd9Sstevel@tonic-gate 	{ PR_LSTATUS,	 6 * sizeof (prdirent_t), sizeof (prdirent_t),
1297c478bd9Sstevel@tonic-gate 		"lstatus" },
1307c478bd9Sstevel@tonic-gate 	{ PR_PSINFO,	 7 * sizeof (prdirent_t), sizeof (prdirent_t),
1317c478bd9Sstevel@tonic-gate 		"psinfo" },
1327c478bd9Sstevel@tonic-gate 	{ PR_LPSINFO,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
1337c478bd9Sstevel@tonic-gate 		"lpsinfo" },
1347c478bd9Sstevel@tonic-gate 	{ PR_MAP,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
1357c478bd9Sstevel@tonic-gate 		"map" },
1367c478bd9Sstevel@tonic-gate 	{ PR_RMAP,	10 * sizeof (prdirent_t), sizeof (prdirent_t),
1377c478bd9Sstevel@tonic-gate 		"rmap" },
1387c478bd9Sstevel@tonic-gate 	{ PR_XMAP,	11 * sizeof (prdirent_t), sizeof (prdirent_t),
1397c478bd9Sstevel@tonic-gate 		"xmap" },
1407c478bd9Sstevel@tonic-gate 	{ PR_CRED,	12 * sizeof (prdirent_t), sizeof (prdirent_t),
1417c478bd9Sstevel@tonic-gate 		"cred" },
1427c478bd9Sstevel@tonic-gate 	{ PR_SIGACT,	13 * sizeof (prdirent_t), sizeof (prdirent_t),
1437c478bd9Sstevel@tonic-gate 		"sigact" },
1447c478bd9Sstevel@tonic-gate 	{ PR_AUXV,	14 * sizeof (prdirent_t), sizeof (prdirent_t),
1457c478bd9Sstevel@tonic-gate 		"auxv" },
1467c478bd9Sstevel@tonic-gate 	{ PR_USAGE,	15 * sizeof (prdirent_t), sizeof (prdirent_t),
1477c478bd9Sstevel@tonic-gate 		"usage" },
1487c478bd9Sstevel@tonic-gate 	{ PR_LUSAGE,	16 * sizeof (prdirent_t), sizeof (prdirent_t),
1497c478bd9Sstevel@tonic-gate 		"lusage" },
1507c478bd9Sstevel@tonic-gate 	{ PR_PAGEDATA,	17 * sizeof (prdirent_t), sizeof (prdirent_t),
1517c478bd9Sstevel@tonic-gate 		"pagedata" },
1527c478bd9Sstevel@tonic-gate 	{ PR_WATCH,	18 * sizeof (prdirent_t), sizeof (prdirent_t),
1537c478bd9Sstevel@tonic-gate 		"watch" },
1547c478bd9Sstevel@tonic-gate 	{ PR_CURDIR,	19 * sizeof (prdirent_t), sizeof (prdirent_t),
1557c478bd9Sstevel@tonic-gate 		"cwd" },
1567c478bd9Sstevel@tonic-gate 	{ PR_ROOTDIR,	20 * sizeof (prdirent_t), sizeof (prdirent_t),
1577c478bd9Sstevel@tonic-gate 		"root" },
1587c478bd9Sstevel@tonic-gate 	{ PR_FDDIR,	21 * sizeof (prdirent_t), sizeof (prdirent_t),
1597c478bd9Sstevel@tonic-gate 		"fd" },
160a02120c4SAndy Fiddaman 	{ PR_FDINFODIR,	22 * sizeof (prdirent_t), sizeof (prdirent_t),
161a02120c4SAndy Fiddaman 		"fdinfo" },
162a02120c4SAndy Fiddaman 	{ PR_OBJECTDIR,	23 * sizeof (prdirent_t), sizeof (prdirent_t),
1637c478bd9Sstevel@tonic-gate 		"object" },
164a02120c4SAndy Fiddaman 	{ PR_LWPDIR,	24 * sizeof (prdirent_t), sizeof (prdirent_t),
1657c478bd9Sstevel@tonic-gate 		"lwp" },
166a02120c4SAndy Fiddaman 	{ PR_PRIV,	25 * sizeof (prdirent_t), sizeof (prdirent_t),
1677c478bd9Sstevel@tonic-gate 		"priv" },
168a02120c4SAndy Fiddaman 	{ PR_PATHDIR,	26 * sizeof (prdirent_t), sizeof (prdirent_t),
1697c478bd9Sstevel@tonic-gate 		"path" },
170a02120c4SAndy Fiddaman 	{ PR_CTDIR,	27 * sizeof (prdirent_t), sizeof (prdirent_t),
1717c478bd9Sstevel@tonic-gate 		"contracts" },
172a02120c4SAndy Fiddaman 	{ PR_SECFLAGS,	28 * sizeof (prdirent_t), sizeof (prdirent_t),
173d2a70789SRichard Lowe 		"secflags" },
1747c478bd9Sstevel@tonic-gate #if defined(__x86)
175a02120c4SAndy Fiddaman 	{ PR_LDT,	29 * sizeof (prdirent_t), sizeof (prdirent_t),
1767c478bd9Sstevel@tonic-gate 		"ldt" },
1777c478bd9Sstevel@tonic-gate #endif
1787c478bd9Sstevel@tonic-gate };
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate #define	NPIDDIRFILES	(sizeof (piddir) / sizeof (piddir[0]) - 2)
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /*
1837c478bd9Sstevel@tonic-gate  * Contents of a /proc/<pid>/lwp/<lwpid> directory.
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate static prdirent_t lwpiddir[] = {
1867c478bd9Sstevel@tonic-gate 	{ PR_LWPIDDIR,	 1 * sizeof (prdirent_t), sizeof (prdirent_t),
1877c478bd9Sstevel@tonic-gate 		"." },
1887c478bd9Sstevel@tonic-gate 	{ PR_LWPDIR,	 2 * sizeof (prdirent_t), sizeof (prdirent_t),
1897c478bd9Sstevel@tonic-gate 		".." },
1907c478bd9Sstevel@tonic-gate 	{ PR_LWPCTL,	 3 * sizeof (prdirent_t), sizeof (prdirent_t),
1917c478bd9Sstevel@tonic-gate 		"lwpctl" },
192ab618543SJohn Levon 	{ PR_LWPNAME,	 4 * sizeof (prdirent_t), sizeof (prdirent_t),
193ab618543SJohn Levon 		"lwpname" },
194ab618543SJohn Levon 	{ PR_LWPSTATUS,	 5 * sizeof (prdirent_t), sizeof (prdirent_t),
1957c478bd9Sstevel@tonic-gate 		"lwpstatus" },
196ab618543SJohn Levon 	{ PR_LWPSINFO,	 6 * sizeof (prdirent_t), sizeof (prdirent_t),
1977c478bd9Sstevel@tonic-gate 		"lwpsinfo" },
198ab618543SJohn Levon 	{ PR_LWPUSAGE,	 7 * sizeof (prdirent_t), sizeof (prdirent_t),
1997c478bd9Sstevel@tonic-gate 		"lwpusage" },
200ab618543SJohn Levon 	{ PR_XREGS,	 8 * sizeof (prdirent_t), sizeof (prdirent_t),
2017c478bd9Sstevel@tonic-gate 		"xregs" },
202ab618543SJohn Levon 	{ PR_TMPLDIR,	 9 * sizeof (prdirent_t), sizeof (prdirent_t),
2037c478bd9Sstevel@tonic-gate 		"templates" },
204ab618543SJohn Levon 	{ PR_SPYMASTER,	 10 * sizeof (prdirent_t), sizeof (prdirent_t),
205f971a346SBryan Cantrill 		"spymaster" },
2067c478bd9Sstevel@tonic-gate #if defined(__sparc)
207ab618543SJohn Levon 	{ PR_GWINDOWS,	11 * sizeof (prdirent_t), sizeof (prdirent_t),
2087c478bd9Sstevel@tonic-gate 		"gwindows" },
209ab618543SJohn Levon 	{ PR_ASRS,	12 * sizeof (prdirent_t), sizeof (prdirent_t),
2107c478bd9Sstevel@tonic-gate 		"asrs" },
2117c478bd9Sstevel@tonic-gate #endif
2127c478bd9Sstevel@tonic-gate };
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate #define	NLWPIDDIRFILES	(sizeof (lwpiddir) / sizeof (lwpiddir[0]) - 2)
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /*
2177c478bd9Sstevel@tonic-gate  * Span of entries in the array files (lstatus, lpsinfo, lusage).
2187c478bd9Sstevel@tonic-gate  * We make the span larger than the size of the structure on purpose,
2197c478bd9Sstevel@tonic-gate  * to make sure that programs cannot use the structure size by mistake.
2207c478bd9Sstevel@tonic-gate  * Align _ILP32 structures at 8 bytes, _LP64 structures at 16 bytes.
2217c478bd9Sstevel@tonic-gate  */
2227c478bd9Sstevel@tonic-gate #ifdef _LP64
2237c478bd9Sstevel@tonic-gate #define	LSPAN(type)	(round16(sizeof (type)) + 16)
2247c478bd9Sstevel@tonic-gate #define	LSPAN32(type)	(round8(sizeof (type)) + 8)
2257c478bd9Sstevel@tonic-gate #else
2267c478bd9Sstevel@tonic-gate #define	LSPAN(type)	(round8(sizeof (type)) + 8)
2277c478bd9Sstevel@tonic-gate #endif
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate static void rebuild_objdir(struct as *);
2307c478bd9Sstevel@tonic-gate static void prfreecommon(prcommon_t *);
231da6c28aaSamw static int praccess(vnode_t *, int, int, cred_t *, caller_context_t *);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate static int
propen(vnode_t ** vpp,int flag,cred_t * cr,caller_context_t * ct)234da6c28aaSamw propen(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct)
2357c478bd9Sstevel@tonic-gate {
2367c478bd9Sstevel@tonic-gate 	vnode_t *vp = *vpp;
2377c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
2387c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_pcommon;
2397c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
2407c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
2417c478bd9Sstevel@tonic-gate 	vtype_t vtype;
2427c478bd9Sstevel@tonic-gate 	proc_t *p;
2437c478bd9Sstevel@tonic-gate 	int error = 0;
2447c478bd9Sstevel@tonic-gate 	prnode_t *npnp = NULL;
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	/*
2477c478bd9Sstevel@tonic-gate 	 * Nothing to do for the /proc directory itself.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR)
2507c478bd9Sstevel@tonic-gate 		return (0);
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	/*
2537c478bd9Sstevel@tonic-gate 	 * If we are opening an underlying mapped object, reject opens
2547c478bd9Sstevel@tonic-gate 	 * for writing regardless of the objects's access modes.
2557c478bd9Sstevel@tonic-gate 	 * If we are opening a file in the /proc/pid/fd directory,
2567c478bd9Sstevel@tonic-gate 	 * reject the open for any but a regular file or directory.
2577c478bd9Sstevel@tonic-gate 	 * Just do it if we are opening the current or root directory.
2587c478bd9Sstevel@tonic-gate 	 */
2597c478bd9Sstevel@tonic-gate 	switch (type) {
2607c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
2617c478bd9Sstevel@tonic-gate 	case PR_FD:
2627c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
2637c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
2647c478bd9Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
2657c478bd9Sstevel@tonic-gate 		vtype = rvp->v_type;
2667c478bd9Sstevel@tonic-gate 		if ((type == PR_OBJECT && (flag & FWRITE)) ||
2677c478bd9Sstevel@tonic-gate 		    (type == PR_FD && vtype != VREG && vtype != VDIR))
2687c478bd9Sstevel@tonic-gate 			error = EACCES;
2697c478bd9Sstevel@tonic-gate 		else {
2707c478bd9Sstevel@tonic-gate 			/*
2717c478bd9Sstevel@tonic-gate 			 * Need to hold rvp since VOP_OPEN() may release it.
2727c478bd9Sstevel@tonic-gate 			 */
2737c478bd9Sstevel@tonic-gate 			VN_HOLD(rvp);
274da6c28aaSamw 			error = VOP_OPEN(&rvp, flag, cr, ct);
2757c478bd9Sstevel@tonic-gate 			if (error) {
2767c478bd9Sstevel@tonic-gate 				VN_RELE(rvp);
2777c478bd9Sstevel@tonic-gate 			} else {
2787c478bd9Sstevel@tonic-gate 				*vpp = rvp;
2797c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
2807c478bd9Sstevel@tonic-gate 			}
2817c478bd9Sstevel@tonic-gate 		}
2827c478bd9Sstevel@tonic-gate 		return (error);
2837c478bd9Sstevel@tonic-gate 	default:
2847c478bd9Sstevel@tonic-gate 		break;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/*
2887c478bd9Sstevel@tonic-gate 	 * If we are opening the pagedata file, allocate a prnode now
2897c478bd9Sstevel@tonic-gate 	 * to avoid calling kmem_alloc() while holding p->p_lock.
2907c478bd9Sstevel@tonic-gate 	 */
2917c478bd9Sstevel@tonic-gate 	if (type == PR_PAGEDATA || type == PR_OPAGEDATA)
2927c478bd9Sstevel@tonic-gate 		npnp = prgetnode(vp, type);
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 	/*
2957c478bd9Sstevel@tonic-gate 	 * If the process exists, lock it now.
2967c478bd9Sstevel@tonic-gate 	 * Otherwise we have a race condition with prclose().
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
2997c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
3007c478bd9Sstevel@tonic-gate 	if (p == NULL) {
3017c478bd9Sstevel@tonic-gate 		if (npnp != NULL)
3027c478bd9Sstevel@tonic-gate 			prfreenode(npnp);
3037c478bd9Sstevel@tonic-gate 		return (ENOENT);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc);
3067c478bd9Sstevel@tonic-gate 	ASSERT(p->p_proc_flag & P_PR_LOCK);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	/*
3097c478bd9Sstevel@tonic-gate 	 * Maintain a count of opens for write.  Allow exactly one
3107c478bd9Sstevel@tonic-gate 	 * O_WRITE|O_EXCL request and fail subsequent ones.
3117c478bd9Sstevel@tonic-gate 	 * Don't fail opens of old (bletch!) /proc lwp files.
3127c478bd9Sstevel@tonic-gate 	 * Special case for open by the process itself:
3137c478bd9Sstevel@tonic-gate 	 * Always allow the open by self and discount this
3147c478bd9Sstevel@tonic-gate 	 * open for other opens for writing.
3157c478bd9Sstevel@tonic-gate 	 */
3167c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
3177c478bd9Sstevel@tonic-gate 		if (p == curproc) {
3187c478bd9Sstevel@tonic-gate 			pcp->prc_selfopens++;
3197c478bd9Sstevel@tonic-gate 			pnp->pr_flags |= PR_ISSELF;
3207c478bd9Sstevel@tonic-gate 		} else if (type == PR_LWPIDFILE) {
3217c478bd9Sstevel@tonic-gate 			/* EMPTY */;
3227c478bd9Sstevel@tonic-gate 		} else if (flag & FEXCL) {
3237c478bd9Sstevel@tonic-gate 			if (pcp->prc_writers > pcp->prc_selfopens) {
3247c478bd9Sstevel@tonic-gate 				error = EBUSY;
3257c478bd9Sstevel@tonic-gate 				goto out;
3267c478bd9Sstevel@tonic-gate 			}
3277c478bd9Sstevel@tonic-gate 			/* semantic for old /proc interface */
3287c478bd9Sstevel@tonic-gate 			if (type == PR_PIDDIR)
3297c478bd9Sstevel@tonic-gate 				pcp->prc_flags |= PRC_EXCL;
3307c478bd9Sstevel@tonic-gate 		} else if (pcp->prc_flags & PRC_EXCL) {
3317c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_writers > pcp->prc_selfopens);
3327c478bd9Sstevel@tonic-gate 			error = secpolicy_proc_excl_open(cr);
3337c478bd9Sstevel@tonic-gate 			if (error)
3347c478bd9Sstevel@tonic-gate 				goto out;
3357c478bd9Sstevel@tonic-gate 		}
3367c478bd9Sstevel@tonic-gate 		pcp->prc_writers++;
3377c478bd9Sstevel@tonic-gate 		/*
3387c478bd9Sstevel@tonic-gate 		 * The vnode may have become invalid between the
3397c478bd9Sstevel@tonic-gate 		 * VOP_LOOKUP() of the /proc vnode and the VOP_OPEN().
3407c478bd9Sstevel@tonic-gate 		 * If so, do now what prinvalidate() should have done.
3417c478bd9Sstevel@tonic-gate 		 */
3427c478bd9Sstevel@tonic-gate 		if ((pnp->pr_flags & PR_INVAL) ||
3437c478bd9Sstevel@tonic-gate 		    (type == PR_PIDDIR &&
3447c478bd9Sstevel@tonic-gate 		    (VTOP(pnp->pr_pidfile)->pr_flags & PR_INVAL))) {
3457c478bd9Sstevel@tonic-gate 			if (p != curproc)
3467c478bd9Sstevel@tonic-gate 				pcp->prc_selfopens++;
3477c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens <= pcp->prc_writers);
3487c478bd9Sstevel@tonic-gate 			if (pcp->prc_selfopens == pcp->prc_writers)
3497c478bd9Sstevel@tonic-gate 				pcp->prc_flags &= ~PRC_EXCL;
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/*
354d1b18d1aSBryan Cantrill 	 * If this is a large file open, indicate that in our flags -- some
355d1b18d1aSBryan Cantrill 	 * procfs structures are not off_t-neutral (e.g., priovec_t), and
356d1b18d1aSBryan Cantrill 	 * the open will need to be differentiated where 32-bit processes
357d1b18d1aSBryan Cantrill 	 * pass these structures across the user/kernel boundary.
358d1b18d1aSBryan Cantrill 	 */
359d1b18d1aSBryan Cantrill 	if (flag & FOFFMAX)
360d1b18d1aSBryan Cantrill 		pnp->pr_flags |= PR_OFFMAX;
361d1b18d1aSBryan Cantrill 
362d1b18d1aSBryan Cantrill 	/*
3637c478bd9Sstevel@tonic-gate 	 * Do file-specific things.
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 	switch (type) {
3667c478bd9Sstevel@tonic-gate 	default:
3677c478bd9Sstevel@tonic-gate 		break;
3687c478bd9Sstevel@tonic-gate 	case PR_PAGEDATA:
3697c478bd9Sstevel@tonic-gate 	case PR_OPAGEDATA:
3707c478bd9Sstevel@tonic-gate 		/*
3717c478bd9Sstevel@tonic-gate 		 * Enable data collection for page data file;
3727c478bd9Sstevel@tonic-gate 		 * get unique id from the hat layer.
3737c478bd9Sstevel@tonic-gate 		 */
3747c478bd9Sstevel@tonic-gate 		{
3757c478bd9Sstevel@tonic-gate 			int id;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 			/*
3787c478bd9Sstevel@tonic-gate 			 * Drop p->p_lock to call hat_startstat()
3797c478bd9Sstevel@tonic-gate 			 */
3807c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3817c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SSYS) || p->p_as == &kas ||
3827c478bd9Sstevel@tonic-gate 			    (id = hat_startstat(p->p_as)) == -1) {
3837c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3847c478bd9Sstevel@tonic-gate 				error = ENOMEM;
3857c478bd9Sstevel@tonic-gate 			} else if (pnp->pr_hatid == 0) {
3867c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3877c478bd9Sstevel@tonic-gate 				pnp->pr_hatid = (uint_t)id;
3887c478bd9Sstevel@tonic-gate 			} else {
3897c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
3907c478bd9Sstevel@tonic-gate 				/*
3917c478bd9Sstevel@tonic-gate 				 * Use our newly allocated prnode.
3927c478bd9Sstevel@tonic-gate 				 */
3937c478bd9Sstevel@tonic-gate 				npnp->pr_hatid = (uint_t)id;
3947c478bd9Sstevel@tonic-gate 				/*
3957c478bd9Sstevel@tonic-gate 				 * prgetnode() initialized most of the prnode.
3967c478bd9Sstevel@tonic-gate 				 * Duplicate the remainder.
3977c478bd9Sstevel@tonic-gate 				 */
3987c478bd9Sstevel@tonic-gate 				npnp->pr_ino = pnp->pr_ino;
3997c478bd9Sstevel@tonic-gate 				npnp->pr_common = pnp->pr_common;
4007c478bd9Sstevel@tonic-gate 				npnp->pr_pcommon = pnp->pr_pcommon;
4017c478bd9Sstevel@tonic-gate 				npnp->pr_parent = pnp->pr_parent;
4027c478bd9Sstevel@tonic-gate 				VN_HOLD(npnp->pr_parent);
4037c478bd9Sstevel@tonic-gate 				npnp->pr_index = pnp->pr_index;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 				npnp->pr_next = p->p_plist;
4067c478bd9Sstevel@tonic-gate 				p->p_plist = PTOV(npnp);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 				VN_RELE(PTOV(pnp));
4097c478bd9Sstevel@tonic-gate 				pnp = npnp;
4107c478bd9Sstevel@tonic-gate 				npnp = NULL;
4117c478bd9Sstevel@tonic-gate 				*vpp = PTOV(pnp);
4127c478bd9Sstevel@tonic-gate 			}
4137c478bd9Sstevel@tonic-gate 		}
4147c478bd9Sstevel@tonic-gate 		break;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate out:
4187c478bd9Sstevel@tonic-gate 	prunlock(pnp);
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	if (npnp != NULL)
4217c478bd9Sstevel@tonic-gate 		prfreenode(npnp);
4227c478bd9Sstevel@tonic-gate 	return (error);
4237c478bd9Sstevel@tonic-gate }
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate /* ARGSUSED */
4267c478bd9Sstevel@tonic-gate static int
prclose(vnode_t * vp,int flag,int count,offset_t offset,cred_t * cr,caller_context_t * ct)427da6c28aaSamw prclose(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr,
428da6c28aaSamw     caller_context_t *ct)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
4317c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_pcommon;
4327c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
4337c478bd9Sstevel@tonic-gate 	proc_t *p;
4347c478bd9Sstevel@tonic-gate 	kthread_t *t;
4357c478bd9Sstevel@tonic-gate 	user_t *up;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	/*
4387c478bd9Sstevel@tonic-gate 	 * Nothing to do for the /proc directory itself.
4397c478bd9Sstevel@tonic-gate 	 */
4407c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR)
4417c478bd9Sstevel@tonic-gate 		return (0);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	ASSERT(type != PR_OBJECT && type != PR_FD &&
4447c478bd9Sstevel@tonic-gate 	    type != PR_CURDIR && type != PR_ROOTDIR);
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	/*
4477c478bd9Sstevel@tonic-gate 	 * If the process exists, lock it now.
4487c478bd9Sstevel@tonic-gate 	 * Otherwise we have a race condition with propen().
4497c478bd9Sstevel@tonic-gate 	 * Hold pr_pidlock across the reference to prc_selfopens,
4507c478bd9Sstevel@tonic-gate 	 * and prc_writers in case there is no process anymore,
4517c478bd9Sstevel@tonic-gate 	 * to cover the case of concurrent calls to prclose()
4527c478bd9Sstevel@tonic-gate 	 * after the process has been reaped by freeproc().
4537c478bd9Sstevel@tonic-gate 	 */
4547c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate 	/*
4577c478bd9Sstevel@tonic-gate 	 * There is nothing more to do until the last close of
4587c478bd9Sstevel@tonic-gate 	 * the file table entry except to clear the pr_owner
4597c478bd9Sstevel@tonic-gate 	 * field of the prnode and notify any waiters
4607c478bd9Sstevel@tonic-gate 	 * (their file descriptor may have just been closed).
4617c478bd9Sstevel@tonic-gate 	 */
4627c478bd9Sstevel@tonic-gate 	if (count > 1) {
4637c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
4647c478bd9Sstevel@tonic-gate 		if (pnp->pr_owner == curproc && !fisopen(vp))
4657c478bd9Sstevel@tonic-gate 			pnp->pr_owner = NULL;
4667c478bd9Sstevel@tonic-gate 		if (p != NULL) {
4677c478bd9Sstevel@tonic-gate 			prnotify(vp);
4687c478bd9Sstevel@tonic-gate 			prunlock(pnp);
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 		return (0);
4717c478bd9Sstevel@tonic-gate 	}
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	/*
4747c478bd9Sstevel@tonic-gate 	 * Decrement the count of self-opens for writing.
4757c478bd9Sstevel@tonic-gate 	 * Decrement the total count of opens for writing.
4767c478bd9Sstevel@tonic-gate 	 * Cancel exclusive opens when only self-opens remain.
4777c478bd9Sstevel@tonic-gate 	 */
4787c478bd9Sstevel@tonic-gate 	if (flag & FWRITE) {
4797c478bd9Sstevel@tonic-gate 		/*
4807c478bd9Sstevel@tonic-gate 		 * prc_selfopens also contains the count of
4817c478bd9Sstevel@tonic-gate 		 * invalid writers.  See prinvalidate().
4827c478bd9Sstevel@tonic-gate 		 */
4837c478bd9Sstevel@tonic-gate 		if ((pnp->pr_flags & (PR_ISSELF|PR_INVAL)) ||
4847c478bd9Sstevel@tonic-gate 		    (type == PR_PIDDIR &&
4857c478bd9Sstevel@tonic-gate 		    (VTOP(pnp->pr_pidfile)->pr_flags & PR_INVAL))) {
4867c478bd9Sstevel@tonic-gate 			ASSERT(pcp->prc_selfopens != 0);
4877c478bd9Sstevel@tonic-gate 			--pcp->prc_selfopens;
4887c478bd9Sstevel@tonic-gate 		}
4897c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_writers != 0);
4907c478bd9Sstevel@tonic-gate 		if (--pcp->prc_writers == pcp->prc_selfopens)
4917c478bd9Sstevel@tonic-gate 			pcp->prc_flags &= ~PRC_EXCL;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 	ASSERT(pcp->prc_writers >= pcp->prc_selfopens);
4947c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
4957c478bd9Sstevel@tonic-gate 	if (pnp->pr_owner == curproc && !fisopen(vp))
4967c478bd9Sstevel@tonic-gate 		pnp->pr_owner = NULL;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 	/*
4997c478bd9Sstevel@tonic-gate 	 * If there is no process, there is nothing more to do.
5007c478bd9Sstevel@tonic-gate 	 */
5017c478bd9Sstevel@tonic-gate 	if (p == NULL)
5027c478bd9Sstevel@tonic-gate 		return (0);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	ASSERT(p == pcp->prc_proc);
5057c478bd9Sstevel@tonic-gate 	prnotify(vp);	/* notify waiters */
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate 	/*
5087c478bd9Sstevel@tonic-gate 	 * Do file-specific things.
5097c478bd9Sstevel@tonic-gate 	 */
5107c478bd9Sstevel@tonic-gate 	switch (type) {
5117c478bd9Sstevel@tonic-gate 	default:
5127c478bd9Sstevel@tonic-gate 		break;
5137c478bd9Sstevel@tonic-gate 	case PR_PAGEDATA:
5147c478bd9Sstevel@tonic-gate 	case PR_OPAGEDATA:
5157c478bd9Sstevel@tonic-gate 		/*
5167c478bd9Sstevel@tonic-gate 		 * This is a page data file.
5177c478bd9Sstevel@tonic-gate 		 * Free the hat level statistics.
5187c478bd9Sstevel@tonic-gate 		 * Drop p->p_lock before calling hat_freestat().
5197c478bd9Sstevel@tonic-gate 		 */
5207c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
5217c478bd9Sstevel@tonic-gate 		if (p->p_as != &kas && pnp->pr_hatid != 0)
5227c478bd9Sstevel@tonic-gate 			hat_freestat(p->p_as, pnp->pr_hatid);
5237c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
5247c478bd9Sstevel@tonic-gate 		pnp->pr_hatid = 0;
5257c478bd9Sstevel@tonic-gate 		break;
5267c478bd9Sstevel@tonic-gate 	}
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	/*
5297c478bd9Sstevel@tonic-gate 	 * On last close of all writable file descriptors,
5307c478bd9Sstevel@tonic-gate 	 * perform run-on-last-close and/or kill-on-last-close logic.
5317c478bd9Sstevel@tonic-gate 	 * Can't do this is the /proc agent lwp still exists.
5327c478bd9Sstevel@tonic-gate 	 */
5337c478bd9Sstevel@tonic-gate 	if (pcp->prc_writers == 0 &&
5347c478bd9Sstevel@tonic-gate 	    p->p_agenttp == NULL &&
5357c478bd9Sstevel@tonic-gate 	    !(pcp->prc_flags & PRC_DESTROY) &&
5367c478bd9Sstevel@tonic-gate 	    p->p_stat != SZOMB &&
5377c478bd9Sstevel@tonic-gate 	    (p->p_proc_flag & (P_PR_RUNLCL|P_PR_KILLCL))) {
5387c478bd9Sstevel@tonic-gate 		int killproc;
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 		/*
5417c478bd9Sstevel@tonic-gate 		 * Cancel any watchpoints currently in effect.
5427c478bd9Sstevel@tonic-gate 		 * The process might disappear during this operation.
5437c478bd9Sstevel@tonic-gate 		 */
5447c478bd9Sstevel@tonic-gate 		if (pr_cancel_watch(pnp) == NULL)
5457c478bd9Sstevel@tonic-gate 			return (0);
5467c478bd9Sstevel@tonic-gate 		/*
5477c478bd9Sstevel@tonic-gate 		 * If any tracing flags are set, clear them.
5487c478bd9Sstevel@tonic-gate 		 */
5497c478bd9Sstevel@tonic-gate 		if (p->p_proc_flag & P_PR_TRACE) {
5507c478bd9Sstevel@tonic-gate 			up = PTOU(p);
5517c478bd9Sstevel@tonic-gate 			premptyset(&up->u_entrymask);
5527c478bd9Sstevel@tonic-gate 			premptyset(&up->u_exitmask);
5537c478bd9Sstevel@tonic-gate 			up->u_systrap = 0;
5547c478bd9Sstevel@tonic-gate 		}
5557c478bd9Sstevel@tonic-gate 		premptyset(&p->p_sigmask);
5567c478bd9Sstevel@tonic-gate 		premptyset(&p->p_fltmask);
5577c478bd9Sstevel@tonic-gate 		killproc = (p->p_proc_flag & P_PR_KILLCL);
5587c478bd9Sstevel@tonic-gate 		p->p_proc_flag &= ~(P_PR_RUNLCL|P_PR_KILLCL|P_PR_TRACE);
5597c478bd9Sstevel@tonic-gate 		/*
5607c478bd9Sstevel@tonic-gate 		 * Cancel any outstanding single-step requests.
5617c478bd9Sstevel@tonic-gate 		 */
5627c478bd9Sstevel@tonic-gate 		if ((t = p->p_tlist) != NULL) {
5637c478bd9Sstevel@tonic-gate 			/*
5647c478bd9Sstevel@tonic-gate 			 * Drop p_lock because prnostep() touches the stack.
5657c478bd9Sstevel@tonic-gate 			 * The loop is safe because the process is P_PR_LOCK'd.
5667c478bd9Sstevel@tonic-gate 			 */
5677c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
5687c478bd9Sstevel@tonic-gate 			do {
5697c478bd9Sstevel@tonic-gate 				prnostep(ttolwp(t));
5707c478bd9Sstevel@tonic-gate 			} while ((t = t->t_forw) != p->p_tlist);
5717c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
5727c478bd9Sstevel@tonic-gate 		}
5737c478bd9Sstevel@tonic-gate 		/*
5747c478bd9Sstevel@tonic-gate 		 * Set runnable all lwps stopped by /proc.
5757c478bd9Sstevel@tonic-gate 		 */
5767c478bd9Sstevel@tonic-gate 		if (killproc)
5777c478bd9Sstevel@tonic-gate 			sigtoproc(p, NULL, SIGKILL);
5787c478bd9Sstevel@tonic-gate 		else
5797c478bd9Sstevel@tonic-gate 			allsetrun(p);
5807c478bd9Sstevel@tonic-gate 	}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	prunlock(pnp);
5837c478bd9Sstevel@tonic-gate 	return (0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * Array of read functions, indexed by /proc file type.
5887c478bd9Sstevel@tonic-gate  */
5897c478bd9Sstevel@tonic-gate static int pr_read_inval(), pr_read_as(), pr_read_status(),
5907c478bd9Sstevel@tonic-gate 	pr_read_lstatus(), pr_read_psinfo(), pr_read_lpsinfo(),
5917c478bd9Sstevel@tonic-gate 	pr_read_map(), pr_read_rmap(), pr_read_xmap(),
5927c478bd9Sstevel@tonic-gate 	pr_read_cred(), pr_read_sigact(), pr_read_auxv(),
5937c478bd9Sstevel@tonic-gate #if defined(__x86)
5947c478bd9Sstevel@tonic-gate 	pr_read_ldt(),
5957c478bd9Sstevel@tonic-gate #endif
5967c478bd9Sstevel@tonic-gate 	pr_read_usage(), pr_read_lusage(), pr_read_pagedata(),
5977c478bd9Sstevel@tonic-gate 	pr_read_watch(), pr_read_lwpstatus(), pr_read_lwpsinfo(),
598ab618543SJohn Levon 	pr_read_lwpusage(), pr_read_lwpname(),
599ab618543SJohn Levon 	pr_read_xregs(), pr_read_priv(),
600d2a70789SRichard Lowe 	pr_read_spymaster(), pr_read_secflags(),
6017c478bd9Sstevel@tonic-gate #if defined(__sparc)
6027c478bd9Sstevel@tonic-gate 	pr_read_gwindows(), pr_read_asrs(),
6037c478bd9Sstevel@tonic-gate #endif
604a02120c4SAndy Fiddaman 	pr_read_piddir(), pr_read_pidfile(), pr_read_opagedata(),
605a02120c4SAndy Fiddaman 	pr_read_fdinfo();
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate static int (*pr_read_function[PR_NFILES])() = {
6087c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc				*/
6097c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/self				*/
6107c478bd9Sstevel@tonic-gate 	pr_read_piddir,		/* /proc/<pid> (old /proc read())	*/
6117c478bd9Sstevel@tonic-gate 	pr_read_as,		/* /proc/<pid>/as			*/
6127c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/ctl			*/
6137c478bd9Sstevel@tonic-gate 	pr_read_status,		/* /proc/<pid>/status			*/
6147c478bd9Sstevel@tonic-gate 	pr_read_lstatus,	/* /proc/<pid>/lstatus			*/
6157c478bd9Sstevel@tonic-gate 	pr_read_psinfo,		/* /proc/<pid>/psinfo			*/
6167c478bd9Sstevel@tonic-gate 	pr_read_lpsinfo,	/* /proc/<pid>/lpsinfo			*/
6177c478bd9Sstevel@tonic-gate 	pr_read_map,		/* /proc/<pid>/map			*/
6187c478bd9Sstevel@tonic-gate 	pr_read_rmap,		/* /proc/<pid>/rmap			*/
6197c478bd9Sstevel@tonic-gate 	pr_read_xmap,		/* /proc/<pid>/xmap			*/
6207c478bd9Sstevel@tonic-gate 	pr_read_cred,		/* /proc/<pid>/cred			*/
6217c478bd9Sstevel@tonic-gate 	pr_read_sigact,		/* /proc/<pid>/sigact			*/
6227c478bd9Sstevel@tonic-gate 	pr_read_auxv,		/* /proc/<pid>/auxv			*/
6237c478bd9Sstevel@tonic-gate #if defined(__x86)
6247c478bd9Sstevel@tonic-gate 	pr_read_ldt,		/* /proc/<pid>/ldt			*/
6257c478bd9Sstevel@tonic-gate #endif
6267c478bd9Sstevel@tonic-gate 	pr_read_usage,		/* /proc/<pid>/usage			*/
6277c478bd9Sstevel@tonic-gate 	pr_read_lusage,		/* /proc/<pid>/lusage			*/
6287c478bd9Sstevel@tonic-gate 	pr_read_pagedata,	/* /proc/<pid>/pagedata			*/
6297c478bd9Sstevel@tonic-gate 	pr_read_watch,		/* /proc/<pid>/watch			*/
6307c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/cwd			*/
6317c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/root			*/
6327c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd			*/
6337c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd/nn			*/
634a02120c4SAndy Fiddaman 	pr_read_inval,		/* /proc/<pid>/fdinfo			*/
635a02120c4SAndy Fiddaman 	pr_read_fdinfo,		/* /proc/<pid>/fdinfo/nn		*/
6367c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object			*/
6377c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object/xxx		*/
6387c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp			*/
6397c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>		*/
6407c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
641ab618543SJohn Levon 	pr_read_lwpname,	/* /proc/<pid>/lwp/<lwpid>/lwpname	*/
6427c478bd9Sstevel@tonic-gate 	pr_read_lwpstatus,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
6437c478bd9Sstevel@tonic-gate 	pr_read_lwpsinfo,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
6447c478bd9Sstevel@tonic-gate 	pr_read_lwpusage,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
6457c478bd9Sstevel@tonic-gate 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
6467c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
6477c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
648f971a346SBryan Cantrill 	pr_read_spymaster,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
6497c478bd9Sstevel@tonic-gate #if defined(__sparc)
6507c478bd9Sstevel@tonic-gate 	pr_read_gwindows,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
6517c478bd9Sstevel@tonic-gate 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
6527c478bd9Sstevel@tonic-gate #endif
6537c478bd9Sstevel@tonic-gate 	pr_read_priv,		/* /proc/<pid>/priv			*/
6547c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path			*/
6557c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path/xxx			*/
6567c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts		*/
6577c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts/<ctid>		*/
658d2a70789SRichard Lowe 	pr_read_secflags,	/* /proc/<pid>/secflags			*/
6597c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old process file			*/
6607c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old lwp file				*/
6617c478bd9Sstevel@tonic-gate 	pr_read_opagedata,	/* old pagedata file			*/
6627c478bd9Sstevel@tonic-gate };
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate /* ARGSUSED */
6657c478bd9Sstevel@tonic-gate static int
pr_read_inval(prnode_t * pnp,uio_t * uiop,cred_t * cr)66619ee9cd1SAndy Fiddaman pr_read_inval(prnode_t *pnp, uio_t *uiop, cred_t *cr)
6677c478bd9Sstevel@tonic-gate {
6687c478bd9Sstevel@tonic-gate 	/*
6697c478bd9Sstevel@tonic-gate 	 * No read() on any /proc directory, use getdents(2) instead.
6707c478bd9Sstevel@tonic-gate 	 * Cannot read a control file either.
6717c478bd9Sstevel@tonic-gate 	 * An underlying mapped object file cannot get here.
6727c478bd9Sstevel@tonic-gate 	 */
6737c478bd9Sstevel@tonic-gate 	return (EINVAL);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate static int
pr_uioread(void * base,long count,uio_t * uiop)6777c478bd9Sstevel@tonic-gate pr_uioread(void *base, long count, uio_t *uiop)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	int error = 0;
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	ASSERT(count >= 0);
6827c478bd9Sstevel@tonic-gate 	count -= uiop->uio_offset;
6837c478bd9Sstevel@tonic-gate 	if (count > 0 && uiop->uio_offset >= 0) {
6847c478bd9Sstevel@tonic-gate 		error = uiomove((char *)base + uiop->uio_offset,
6857c478bd9Sstevel@tonic-gate 		    count, UIO_READ, uiop);
6867c478bd9Sstevel@tonic-gate 	}
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	return (error);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate static int
pr_read_as(prnode_t * pnp,uio_t * uiop)6927c478bd9Sstevel@tonic-gate pr_read_as(prnode_t *pnp, uio_t *uiop)
6937c478bd9Sstevel@tonic-gate {
6947c478bd9Sstevel@tonic-gate 	int error;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AS);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
6997c478bd9Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
7007c478bd9Sstevel@tonic-gate 		struct as *as = p->p_as;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		/*
7037c478bd9Sstevel@tonic-gate 		 * /proc I/O cannot be done to a system process.
7047c478bd9Sstevel@tonic-gate 		 * A 32-bit process cannot read a 64-bit process.
7057c478bd9Sstevel@tonic-gate 		 */
7067c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || as == &kas) {
7077c478bd9Sstevel@tonic-gate 			error = 0;
7087c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
7097c478bd9Sstevel@tonic-gate 		} else if (curproc->p_model == DATAMODEL_ILP32 &&
7107c478bd9Sstevel@tonic-gate 		    PROCESS_NOT_32BIT(p)) {
7117c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
7127c478bd9Sstevel@tonic-gate #endif
7137c478bd9Sstevel@tonic-gate 		} else {
7147c478bd9Sstevel@tonic-gate 			/*
7157c478bd9Sstevel@tonic-gate 			 * We don't hold p_lock over an i/o operation because
7167c478bd9Sstevel@tonic-gate 			 * that could lead to deadlock with the clock thread.
7177c478bd9Sstevel@tonic-gate 			 */
7187c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
7197c478bd9Sstevel@tonic-gate 			error = prusrio(p, UIO_READ, uiop, 0);
7207c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
7217c478bd9Sstevel@tonic-gate 		}
7227c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7237c478bd9Sstevel@tonic-gate 	}
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	return (error);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate static int
pr_read_status(prnode_t * pnp,uio_t * uiop,cred_t * cr)72919ee9cd1SAndy Fiddaman pr_read_status(prnode_t *pnp, uio_t *uiop, cred_t *cr)
7307c478bd9Sstevel@tonic-gate {
7317c478bd9Sstevel@tonic-gate 	pstatus_t *sp;
7327c478bd9Sstevel@tonic-gate 	int error;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_STATUS);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	/*
7377c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the pstatus structure because
7387c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
7397c478bd9Sstevel@tonic-gate 	 */
7407c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
7417c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
742fa9e4066Sahrens 		prgetstatus(pnp->pr_common->prc_proc, sp, VTOZONE(PTOV(pnp)));
7437c478bd9Sstevel@tonic-gate 		prunlock(pnp);
7447c478bd9Sstevel@tonic-gate 		error = pr_uioread(sp, sizeof (*sp), uiop);
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
7477c478bd9Sstevel@tonic-gate 	return (error);
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate static int
pr_read_lstatus(prnode_t * pnp,uio_t * uiop,cred_t * cr)75119ee9cd1SAndy Fiddaman pr_read_lstatus(prnode_t *pnp, uio_t *uiop, cred_t *cr)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate 	proc_t *p;
7547c478bd9Sstevel@tonic-gate 	kthread_t *t;
7557c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
7567c478bd9Sstevel@tonic-gate 	size_t size;
7577c478bd9Sstevel@tonic-gate 	prheader_t *php;
7587c478bd9Sstevel@tonic-gate 	lwpstatus_t *sp;
7597c478bd9Sstevel@tonic-gate 	int error;
7607c478bd9Sstevel@tonic-gate 	int nlwp;
7617c478bd9Sstevel@tonic-gate 	int i;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LSTATUS);
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
7667c478bd9Sstevel@tonic-gate 		return (error);
7677c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
7687c478bd9Sstevel@tonic-gate 	nlwp = p->p_lwpcnt;
7697c478bd9Sstevel@tonic-gate 	size = sizeof (prheader_t) + nlwp * LSPAN(lwpstatus_t);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
7727c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
7737c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
7747c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
7757c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
7767c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
7797c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN(lwpstatus_t);
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	sp = (lwpstatus_t *)(php + 1);
7827c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
7837c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
7847c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
7857c478bd9Sstevel@tonic-gate 			continue;
786fa9e4066Sahrens 		prgetlwpstatus(t, sp, VTOZONE(PTOV(pnp)));
7877c478bd9Sstevel@tonic-gate 		sp = (lwpstatus_t *)((caddr_t)sp + LSPAN(lwpstatus_t));
7887c478bd9Sstevel@tonic-gate 	}
7897c478bd9Sstevel@tonic-gate 	prunlock(pnp);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
7927c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
7937c478bd9Sstevel@tonic-gate 	return (error);
7947c478bd9Sstevel@tonic-gate }
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate static int
pr_read_psinfo(prnode_t * pnp,uio_t * uiop,cred_t * cr)79719ee9cd1SAndy Fiddaman pr_read_psinfo(prnode_t *pnp, uio_t *uiop, cred_t *cr)
7987c478bd9Sstevel@tonic-gate {
7997c478bd9Sstevel@tonic-gate 	psinfo_t psinfo;
8007c478bd9Sstevel@tonic-gate 	proc_t *p;
8017c478bd9Sstevel@tonic-gate 	int error = 0;
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PSINFO);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	/*
8067c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
8077c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
8087c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
8097c478bd9Sstevel@tonic-gate 	 */
8107c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
8117c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
8127c478bd9Sstevel@tonic-gate 	if (p == NULL)
8137c478bd9Sstevel@tonic-gate 		error = ENOENT;
8147c478bd9Sstevel@tonic-gate 	else {
8157c478bd9Sstevel@tonic-gate 		ASSERT(p == pnp->pr_common->prc_proc);
8167c478bd9Sstevel@tonic-gate 		prgetpsinfo(p, &psinfo);
8177c478bd9Sstevel@tonic-gate 		prunlock(pnp);
8187c478bd9Sstevel@tonic-gate 		error = pr_uioread(&psinfo, sizeof (psinfo), uiop);
8197c478bd9Sstevel@tonic-gate 	}
8207c478bd9Sstevel@tonic-gate 	return (error);
8217c478bd9Sstevel@tonic-gate }
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate static int
pr_read_fdinfo(prnode_t * pnp,uio_t * uiop,cred_t * cr)82419ee9cd1SAndy Fiddaman pr_read_fdinfo(prnode_t *pnp, uio_t *uiop, cred_t *cr)
825a02120c4SAndy Fiddaman {
826a02120c4SAndy Fiddaman 	prfdinfo_t *fdinfo;
827a02120c4SAndy Fiddaman 	list_t data;
828a02120c4SAndy Fiddaman 	proc_t *p;
829a02120c4SAndy Fiddaman 	uint_t fd;
830a02120c4SAndy Fiddaman 	file_t *fp;
831a02120c4SAndy Fiddaman 	short ufp_flag;
832a02120c4SAndy Fiddaman 	int error = 0;
833a02120c4SAndy Fiddaman 
834a02120c4SAndy Fiddaman 	ASSERT(pnp->pr_type == PR_FDINFO);
835a02120c4SAndy Fiddaman 
836a02120c4SAndy Fiddaman 	/*
837a02120c4SAndy Fiddaman 	 * This is a guess at the size of the structure that needs to
838a02120c4SAndy Fiddaman 	 * be returned. It's a balance between not allocating too much more
839a02120c4SAndy Fiddaman 	 * space than is required and not requiring too many subsequent
840a02120c4SAndy Fiddaman 	 * reallocations. Allocate it before acquiring the process lock.
841a02120c4SAndy Fiddaman 	 */
842a02120c4SAndy Fiddaman 	pr_iol_initlist(&data, sizeof (prfdinfo_t) + MAXPATHLEN + 2, 1);
843a02120c4SAndy Fiddaman 
844a02120c4SAndy Fiddaman 	if ((error = prlock(pnp, ZNO)) != 0) {
845a02120c4SAndy Fiddaman 		pr_iol_freelist(&data);
846a02120c4SAndy Fiddaman 		return (error);
847a02120c4SAndy Fiddaman 	}
848a02120c4SAndy Fiddaman 
849a02120c4SAndy Fiddaman 	p = pnp->pr_common->prc_proc;
850a02120c4SAndy Fiddaman 
851a02120c4SAndy Fiddaman 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
852a02120c4SAndy Fiddaman 		prunlock(pnp);
853a02120c4SAndy Fiddaman 		pr_iol_freelist(&data);
854a02120c4SAndy Fiddaman 		return (0);
855a02120c4SAndy Fiddaman 	}
856a02120c4SAndy Fiddaman 
857a02120c4SAndy Fiddaman 	fd = pnp->pr_index;
858a02120c4SAndy Fiddaman 
859a02120c4SAndy Fiddaman 	/* Fetch and lock the file_t for this descriptor */
860a02120c4SAndy Fiddaman 	fp = pr_getf(p, fd, &ufp_flag);
861a02120c4SAndy Fiddaman 
862a02120c4SAndy Fiddaman 	if (fp == NULL) {
863a02120c4SAndy Fiddaman 		error = ENOENT;
864a02120c4SAndy Fiddaman 		prunlock(pnp);
865a02120c4SAndy Fiddaman 		goto out;
866a02120c4SAndy Fiddaman 	}
867a02120c4SAndy Fiddaman 
868a02120c4SAndy Fiddaman 	/*
869a02120c4SAndy Fiddaman 	 * For fdinfo, we don't want to include the placeholder pr_misc at the
870a02120c4SAndy Fiddaman 	 * end of the struct. We'll terminate the data with an empty pr_misc
871a02120c4SAndy Fiddaman 	 * header before returning.
872a02120c4SAndy Fiddaman 	 */
873a02120c4SAndy Fiddaman 
874a02120c4SAndy Fiddaman 	fdinfo = pr_iol_newbuf(&data, offsetof(prfdinfo_t, pr_misc));
875a02120c4SAndy Fiddaman 	fdinfo->pr_fd = fd;
876a02120c4SAndy Fiddaman 	fdinfo->pr_fdflags = ufp_flag;
877086d9687SPatrick Mooney 	fdinfo->pr_fileflags = fp->f_flag2 << 16 | fp->f_flag;
878a02120c4SAndy Fiddaman 	if ((fdinfo->pr_fileflags & (FSEARCH | FEXEC)) == 0)
879a02120c4SAndy Fiddaman 		fdinfo->pr_fileflags += FOPEN;
880a02120c4SAndy Fiddaman 	fdinfo->pr_offset = fp->f_offset;
881a02120c4SAndy Fiddaman 	/*
882a02120c4SAndy Fiddaman 	 * Information from the vnode (rather than the file_t) is retrieved
883a02120c4SAndy Fiddaman 	 * later, in prgetfdinfo() - for example sock_getfasync()
884a02120c4SAndy Fiddaman 	 */
885a02120c4SAndy Fiddaman 
886a02120c4SAndy Fiddaman 	prunlock(pnp);
887a02120c4SAndy Fiddaman 
888da29c6a3SDan McDonald 	error = prgetfdinfo(p, fp->f_vnode, fdinfo, cr, fp->f_cred, &data);
889a02120c4SAndy Fiddaman 
89037e2cd25SPatrick Mooney 	pr_releasef(fp);
891a02120c4SAndy Fiddaman 
892a02120c4SAndy Fiddaman out:
893a02120c4SAndy Fiddaman 	if (error == 0)
894a02120c4SAndy Fiddaman 		error = pr_iol_uiomove_and_free(&data, uiop, error);
895a02120c4SAndy Fiddaman 	else
896a02120c4SAndy Fiddaman 		pr_iol_freelist(&data);
897a02120c4SAndy Fiddaman 
898a02120c4SAndy Fiddaman 	return (error);
899a02120c4SAndy Fiddaman }
900a02120c4SAndy Fiddaman 
901a02120c4SAndy Fiddaman static int
pr_read_lpsinfo(prnode_t * pnp,uio_t * uiop,cred_t * cr)90219ee9cd1SAndy Fiddaman pr_read_lpsinfo(prnode_t *pnp, uio_t *uiop, cred_t *cr)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	proc_t *p;
9057c478bd9Sstevel@tonic-gate 	kthread_t *t;
9067c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
9077c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
9087c478bd9Sstevel@tonic-gate 	size_t size;
9097c478bd9Sstevel@tonic-gate 	prheader_t *php;
9107c478bd9Sstevel@tonic-gate 	lwpsinfo_t *sp;
9117c478bd9Sstevel@tonic-gate 	int error;
9127c478bd9Sstevel@tonic-gate 	int nlwp;
9137c478bd9Sstevel@tonic-gate 	int i;
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LPSINFO);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/*
9187c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
9197c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
9207c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
9217c478bd9Sstevel@tonic-gate 	 */
9227c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
9237c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
9247c478bd9Sstevel@tonic-gate 	if (p == NULL)
9257c478bd9Sstevel@tonic-gate 		return (ENOENT);
9267c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
9277c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt + p->p_zombcnt) == 0) {
9287c478bd9Sstevel@tonic-gate 		prunlock(pnp);
9297c478bd9Sstevel@tonic-gate 		return (ENOENT);
9307c478bd9Sstevel@tonic-gate 	}
9317c478bd9Sstevel@tonic-gate 	size = sizeof (prheader_t) + nlwp * LSPAN(lwpsinfo_t);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
9347c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
9357c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
9367c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
9377c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
9387c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt + p->p_zombcnt);
9397c478bd9Sstevel@tonic-gate 
9407c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
9417c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN(lwpsinfo_t);
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 	sp = (lwpsinfo_t *)(php + 1);
9447c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
9457c478bd9Sstevel@tonic-gate 		if ((lep = ldp->ld_entry) == NULL)
9467c478bd9Sstevel@tonic-gate 			continue;
9477c478bd9Sstevel@tonic-gate 		if ((t = lep->le_thread) != NULL)
9487c478bd9Sstevel@tonic-gate 			prgetlwpsinfo(t, sp);
9497c478bd9Sstevel@tonic-gate 		else {
9507c478bd9Sstevel@tonic-gate 			bzero(sp, sizeof (*sp));
9517c478bd9Sstevel@tonic-gate 			sp->pr_lwpid = lep->le_lwpid;
9527c478bd9Sstevel@tonic-gate 			sp->pr_state = SZOMB;
9537c478bd9Sstevel@tonic-gate 			sp->pr_sname = 'Z';
9547c478bd9Sstevel@tonic-gate 			sp->pr_start.tv_sec = lep->le_start;
9557c478bd9Sstevel@tonic-gate 			sp->pr_bindpro = PBIND_NONE;
9567c478bd9Sstevel@tonic-gate 			sp->pr_bindpset = PS_NONE;
9577c478bd9Sstevel@tonic-gate 		}
9587c478bd9Sstevel@tonic-gate 		sp = (lwpsinfo_t *)((caddr_t)sp + LSPAN(lwpsinfo_t));
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 	prunlock(pnp);
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
9637c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
9647c478bd9Sstevel@tonic-gate 	return (error);
9657c478bd9Sstevel@tonic-gate }
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate static int
pr_read_map_common(prnode_t * pnp,uio_t * uiop,prnodetype_t type)968870619e9Sfrankho pr_read_map_common(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
9697c478bd9Sstevel@tonic-gate {
9707c478bd9Sstevel@tonic-gate 	proc_t *p;
9717c478bd9Sstevel@tonic-gate 	struct as *as;
972870619e9Sfrankho 	list_t iolhead;
9737c478bd9Sstevel@tonic-gate 	int error;
9747c478bd9Sstevel@tonic-gate 
975e24ad047SChristopher Baumbauer - Oracle America - San Diego United States readmap_common:
9767c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
9777c478bd9Sstevel@tonic-gate 		return (error);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
9807c478bd9Sstevel@tonic-gate 	as = p->p_as;
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
9837c478bd9Sstevel@tonic-gate 		prunlock(pnp);
9847c478bd9Sstevel@tonic-gate 		return (0);
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
987dc32d872SJosef 'Jeff' Sipek 	if (!AS_LOCK_TRYENTER(as, RW_WRITER)) {
988e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		prunlock(pnp);
989e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		delay(1);
990e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		goto readmap_common;
991e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 	}
9927c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
993e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 
994870619e9Sfrankho 	switch (type) {
995870619e9Sfrankho 	case PR_XMAP:
996870619e9Sfrankho 		error = prgetxmap(p, &iolhead);
997870619e9Sfrankho 		break;
998870619e9Sfrankho 	case PR_RMAP:
999870619e9Sfrankho 		error = prgetmap(p, 1, &iolhead);
1000870619e9Sfrankho 		break;
1001870619e9Sfrankho 	case PR_MAP:
1002870619e9Sfrankho 		error = prgetmap(p, 0, &iolhead);
1003870619e9Sfrankho 		break;
1004870619e9Sfrankho 	}
1005e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 
1006dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
10077c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
10087c478bd9Sstevel@tonic-gate 	prunlock(pnp);
10097c478bd9Sstevel@tonic-gate 
1010870619e9Sfrankho 	error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
1011870619e9Sfrankho 
10127c478bd9Sstevel@tonic-gate 	return (error);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate static int
pr_read_map(prnode_t * pnp,uio_t * uiop,cred_t * cr)101619ee9cd1SAndy Fiddaman pr_read_map(prnode_t *pnp, uio_t *uiop, cred_t *cr)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_MAP);
1019870619e9Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate static int
pr_read_rmap(prnode_t * pnp,uio_t * uiop,cred_t * cr)102319ee9cd1SAndy Fiddaman pr_read_rmap(prnode_t *pnp, uio_t *uiop, cred_t *cr)
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_RMAP);
1026870619e9Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
10277c478bd9Sstevel@tonic-gate }
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate static int
pr_read_xmap(prnode_t * pnp,uio_t * uiop,cred_t * cr)103019ee9cd1SAndy Fiddaman pr_read_xmap(prnode_t *pnp, uio_t *uiop, cred_t *cr)
10317c478bd9Sstevel@tonic-gate {
10327c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XMAP);
1033870619e9Sfrankho 	return (pr_read_map_common(pnp, uiop, pnp->pr_type));
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate static int
pr_read_cred(prnode_t * pnp,uio_t * uiop,cred_t * cr)103719ee9cd1SAndy Fiddaman pr_read_cred(prnode_t *pnp, uio_t *uiop, cred_t *cr)
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	proc_t *p;
10407c478bd9Sstevel@tonic-gate 	prcred_t *pcrp;
10417c478bd9Sstevel@tonic-gate 	int error;
10427c478bd9Sstevel@tonic-gate 	size_t count;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_CRED);
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	/*
10477c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the prcred_t structure because
10487c478bd9Sstevel@tonic-gate 	 * the number of supplementary groups is variable.
10497c478bd9Sstevel@tonic-gate 	 */
10507c478bd9Sstevel@tonic-gate 	pcrp =
1051*552c19f2SRobert Mustacchi 	    kmem_zalloc(sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1),
10527c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10557c478bd9Sstevel@tonic-gate 		goto out;
10567c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10577c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	prgetcred(p, pcrp);
10607c478bd9Sstevel@tonic-gate 	prunlock(pnp);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	count = sizeof (prcred_t);
10637c478bd9Sstevel@tonic-gate 	if (pcrp->pr_ngroups > 1)
10647c478bd9Sstevel@tonic-gate 		count += sizeof (gid_t) * (pcrp->pr_ngroups - 1);
10657c478bd9Sstevel@tonic-gate 	error = pr_uioread(pcrp, count, uiop);
10667c478bd9Sstevel@tonic-gate out:
10677c478bd9Sstevel@tonic-gate 	kmem_free(pcrp, sizeof (prcred_t) + sizeof (gid_t) * (ngroups_max - 1));
10687c478bd9Sstevel@tonic-gate 	return (error);
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate static int
pr_read_priv(prnode_t * pnp,uio_t * uiop,cred_t * cr)107219ee9cd1SAndy Fiddaman pr_read_priv(prnode_t *pnp, uio_t *uiop, cred_t *cr)
10737c478bd9Sstevel@tonic-gate {
10747c478bd9Sstevel@tonic-gate 	proc_t *p;
10757c478bd9Sstevel@tonic-gate 	size_t psize = prgetprivsize();
1076*552c19f2SRobert Mustacchi 	prpriv_t *ppriv = kmem_zalloc(psize, KM_SLEEP);
10777c478bd9Sstevel@tonic-gate 	int error;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PRIV);
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
10827c478bd9Sstevel@tonic-gate 		goto out;
10837c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
10847c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	prgetpriv(p, ppriv);
10877c478bd9Sstevel@tonic-gate 	prunlock(pnp);
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	error = pr_uioread(ppriv, psize, uiop);
10907c478bd9Sstevel@tonic-gate out:
10917c478bd9Sstevel@tonic-gate 	kmem_free(ppriv, psize);
10927c478bd9Sstevel@tonic-gate 	return (error);
10937c478bd9Sstevel@tonic-gate }
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate static int
pr_read_sigact(prnode_t * pnp,uio_t * uiop,cred_t * cr)109619ee9cd1SAndy Fiddaman pr_read_sigact(prnode_t *pnp, uio_t *uiop, cred_t *cr)
10977c478bd9Sstevel@tonic-gate {
1098eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
10997c478bd9Sstevel@tonic-gate 	proc_t *p;
11007c478bd9Sstevel@tonic-gate 	struct sigaction *sap;
11017c478bd9Sstevel@tonic-gate 	int sig;
11027c478bd9Sstevel@tonic-gate 	int error;
11037c478bd9Sstevel@tonic-gate 	user_t *up;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_SIGACT);
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	/*
11087c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the sigaction array because
11097c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
11107c478bd9Sstevel@tonic-gate 	 */
1111eb9dbf0cSRoger A. Faulkner 	sap = kmem_alloc((nsig-1) * sizeof (struct sigaction), KM_SLEEP);
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
11147c478bd9Sstevel@tonic-gate 		goto out;
11157c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
11167c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
11177c478bd9Sstevel@tonic-gate 
1118eb9dbf0cSRoger A. Faulkner 	if (uiop->uio_offset >= (nsig-1)*sizeof (struct sigaction)) {
11197c478bd9Sstevel@tonic-gate 		prunlock(pnp);
11207c478bd9Sstevel@tonic-gate 		goto out;
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	up = PTOU(p);
1124eb9dbf0cSRoger A. Faulkner 	for (sig = 1; sig < nsig; sig++)
11257c478bd9Sstevel@tonic-gate 		prgetaction(p, up, sig, &sap[sig-1]);
11267c478bd9Sstevel@tonic-gate 	prunlock(pnp);
11277c478bd9Sstevel@tonic-gate 
1128eb9dbf0cSRoger A. Faulkner 	error = pr_uioread(sap, (nsig - 1) * sizeof (struct sigaction), uiop);
11297c478bd9Sstevel@tonic-gate out:
1130eb9dbf0cSRoger A. Faulkner 	kmem_free(sap, (nsig-1) * sizeof (struct sigaction));
11317c478bd9Sstevel@tonic-gate 	return (error);
11327c478bd9Sstevel@tonic-gate }
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate static int
pr_read_auxv(prnode_t * pnp,uio_t * uiop,cred_t * cr)113519ee9cd1SAndy Fiddaman pr_read_auxv(prnode_t *pnp, uio_t *uiop, cred_t *cr)
11367c478bd9Sstevel@tonic-gate {
11377c478bd9Sstevel@tonic-gate 	auxv_t auxv[__KERN_NAUXV_IMPL];
11387c478bd9Sstevel@tonic-gate 	proc_t *p;
11397c478bd9Sstevel@tonic-gate 	user_t *up;
11407c478bd9Sstevel@tonic-gate 	int error;
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AUXV);
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
11457c478bd9Sstevel@tonic-gate 		return (error);
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (auxv)) {
11487c478bd9Sstevel@tonic-gate 		prunlock(pnp);
11497c478bd9Sstevel@tonic-gate 		return (0);
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
11537c478bd9Sstevel@tonic-gate 	up = PTOU(p);
11547c478bd9Sstevel@tonic-gate 	bcopy(up->u_auxv, auxv, sizeof (auxv));
11557c478bd9Sstevel@tonic-gate 	prunlock(pnp);
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	return (pr_uioread(auxv, sizeof (auxv), uiop));
11587c478bd9Sstevel@tonic-gate }
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate #if defined(__x86)
11617c478bd9Sstevel@tonic-gate /*
11627c478bd9Sstevel@tonic-gate  * XX64
11637c478bd9Sstevel@tonic-gate  *	This is almost certainly broken for the amd64 kernel, because
11647c478bd9Sstevel@tonic-gate  *	we have two kinds of LDT structures to export -- one for compatibility
11657c478bd9Sstevel@tonic-gate  *	mode, and one for long mode, sigh.
11667c478bd9Sstevel@tonic-gate  *
1167ab618543SJohn Levon  *	For now let's just have a ldt of size 0 for 64-bit processes.
11687c478bd9Sstevel@tonic-gate  */
11697c478bd9Sstevel@tonic-gate static int
pr_read_ldt(prnode_t * pnp,uio_t * uiop,cred_t * cr)117019ee9cd1SAndy Fiddaman pr_read_ldt(prnode_t *pnp, uio_t *uiop, cred_t *cr)
11717c478bd9Sstevel@tonic-gate {
11727c478bd9Sstevel@tonic-gate 	proc_t *p;
11737c478bd9Sstevel@tonic-gate 	struct ssd *ssd;
11747c478bd9Sstevel@tonic-gate 	size_t size;
11757c478bd9Sstevel@tonic-gate 	int error;
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LDT);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
11807c478bd9Sstevel@tonic-gate 		return (error);
11817c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
11847c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_ldtlock);
11857c478bd9Sstevel@tonic-gate 	size = prnldt(p) * sizeof (struct ssd);
11867c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
11877c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_ldtlock);
11887c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
11897c478bd9Sstevel@tonic-gate 		prunlock(pnp);
11907c478bd9Sstevel@tonic-gate 		return (0);
11917c478bd9Sstevel@tonic-gate 	}
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	ssd = kmem_alloc(size, KM_SLEEP);
11947c478bd9Sstevel@tonic-gate 	prgetldt(p, ssd);
11957c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_ldtlock);
11967c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
11977c478bd9Sstevel@tonic-gate 	prunlock(pnp);
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	error = pr_uioread(ssd, size, uiop);
12007c478bd9Sstevel@tonic-gate 	kmem_free(ssd, size);
12017c478bd9Sstevel@tonic-gate 	return (error);
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate #endif	/* __x86 */
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate static int
pr_read_usage(prnode_t * pnp,uio_t * uiop,cred_t * cr)120619ee9cd1SAndy Fiddaman pr_read_usage(prnode_t *pnp, uio_t *uiop, cred_t *cr)
12077c478bd9Sstevel@tonic-gate {
12087c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
12097c478bd9Sstevel@tonic-gate 	prusage_t *upup;
12107c478bd9Sstevel@tonic-gate 	proc_t *p;
12117c478bd9Sstevel@tonic-gate 	kthread_t *t;
12127c478bd9Sstevel@tonic-gate 	int error;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_USAGE);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
12177c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
12187c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	/*
12217c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
12227c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
12237c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
12247c478bd9Sstevel@tonic-gate 	 */
12257c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
12267c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
12277c478bd9Sstevel@tonic-gate 	if (p == NULL) {
12287c478bd9Sstevel@tonic-gate 		error = ENOENT;
12297c478bd9Sstevel@tonic-gate 		goto out;
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage_t)) {
12347c478bd9Sstevel@tonic-gate 		prunlock(pnp);
12357c478bd9Sstevel@tonic-gate 		error = 0;
12367c478bd9Sstevel@tonic-gate 		goto out;
12377c478bd9Sstevel@tonic-gate 	}
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
12427c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
12437c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
12467c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
12477c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
12487c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
12497c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
12507c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
12517c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
12527c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
12537c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
12547c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
12557c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
12587c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
12597c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
12607c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
12617c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
12627c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
12637c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
12647c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
12657c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
12667c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
12677c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
12687c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	/*
12717c478bd9Sstevel@tonic-gate 	 * Add the usage information for each active lwp.
12727c478bd9Sstevel@tonic-gate 	 */
12737c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL &&
12747c478bd9Sstevel@tonic-gate 	    !(pnp->pr_pcommon->prc_flags & PRC_DESTROY)) {
12757c478bd9Sstevel@tonic-gate 		do {
12767c478bd9Sstevel@tonic-gate 			if (t->t_proc_flag & TP_LWPEXIT)
12777c478bd9Sstevel@tonic-gate 				continue;
12787c478bd9Sstevel@tonic-gate 			pup->pr_count++;
12797c478bd9Sstevel@tonic-gate 			praddusage(t, pup);
12807c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	prunlock(pnp);
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	prcvtusage(pup, upup);
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage_t), uiop);
12887c478bd9Sstevel@tonic-gate out:
12897c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
12907c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
12917c478bd9Sstevel@tonic-gate 	return (error);
12927c478bd9Sstevel@tonic-gate }
12937c478bd9Sstevel@tonic-gate 
12947c478bd9Sstevel@tonic-gate static int
pr_read_lusage(prnode_t * pnp,uio_t * uiop,cred_t * cr)129519ee9cd1SAndy Fiddaman pr_read_lusage(prnode_t *pnp, uio_t *uiop, cred_t *cr)
12967c478bd9Sstevel@tonic-gate {
12977c478bd9Sstevel@tonic-gate 	int nlwp;
12987c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
12997c478bd9Sstevel@tonic-gate 	prheader_t *php;
13007c478bd9Sstevel@tonic-gate 	prusage_t *upup;
13017c478bd9Sstevel@tonic-gate 	size_t size;
13027c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
13037c478bd9Sstevel@tonic-gate 	proc_t *p;
13047c478bd9Sstevel@tonic-gate 	kthread_t *t;
13057c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
13067c478bd9Sstevel@tonic-gate 	int error;
13077c478bd9Sstevel@tonic-gate 	int i;
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LUSAGE);
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	/*
13127c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
13137c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
13147c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
13157c478bd9Sstevel@tonic-gate 	 */
13167c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
13177c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
13187c478bd9Sstevel@tonic-gate 	if (p == NULL)
13197c478bd9Sstevel@tonic-gate 		return (ENOENT);
13207c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
13217c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt) == 0) {
13227c478bd9Sstevel@tonic-gate 		prunlock(pnp);
13237c478bd9Sstevel@tonic-gate 		return (ENOENT);
13247c478bd9Sstevel@tonic-gate 	}
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	size = sizeof (prheader_t) + (nlwp + 1) * LSPAN(prusage_t);
13277c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
13287c478bd9Sstevel@tonic-gate 		prunlock(pnp);
13297c478bd9Sstevel@tonic-gate 		return (0);
13307c478bd9Sstevel@tonic-gate 	}
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
13337c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
13347c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(size + sizeof (prhusage_t), KM_SLEEP);
13357c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
13367c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
13377c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	php = (prheader_t *)(pup + 1);
13407c478bd9Sstevel@tonic-gate 	upup = (prusage_t *)(php + 1);
13417c478bd9Sstevel@tonic-gate 
13427c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp + 1;
13437c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN(prusage_t);
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	curtime = gethrtime();
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	/*
13487c478bd9Sstevel@tonic-gate 	 * First the summation over defunct lwps.
13497c478bd9Sstevel@tonic-gate 	 */
13507c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
13517c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
13527c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
13537c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
13567c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
13577c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
13587c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
13597c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
13607c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
13617c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
13627c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
13637c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
13647c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
13657c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
13687c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
13697c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
13707c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
13717c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
13727c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
13737c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
13747c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
13757c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
13767c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
13777c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
13787c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 	prcvtusage(pup, upup);
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	/*
13837c478bd9Sstevel@tonic-gate 	 * Fill one prusage struct for each active lwp.
13847c478bd9Sstevel@tonic-gate 	 */
13857c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
13867c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
13877c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
13887c478bd9Sstevel@tonic-gate 			continue;
13897c478bd9Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
13907c478bd9Sstevel@tonic-gate 		ASSERT(nlwp > 0);
13917c478bd9Sstevel@tonic-gate 		--nlwp;
13927c478bd9Sstevel@tonic-gate 		upup = (prusage_t *)((caddr_t)upup + LSPAN(prusage_t));
13937c478bd9Sstevel@tonic-gate 		prgetusage(t, pup);
13947c478bd9Sstevel@tonic-gate 		prcvtusage(pup, upup);
13957c478bd9Sstevel@tonic-gate 	}
13967c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == 0);
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 	prunlock(pnp);
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
14017c478bd9Sstevel@tonic-gate 	kmem_free(pup, size + sizeof (prhusage_t));
14027c478bd9Sstevel@tonic-gate 	return (error);
14037c478bd9Sstevel@tonic-gate }
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate static int
pr_read_pagedata(prnode_t * pnp,uio_t * uiop,cred_t * cr)140619ee9cd1SAndy Fiddaman pr_read_pagedata(prnode_t *pnp, uio_t *uiop, cred_t *cr)
14077c478bd9Sstevel@tonic-gate {
14087c478bd9Sstevel@tonic-gate 	proc_t *p;
14097c478bd9Sstevel@tonic-gate 	int error;
14107c478bd9Sstevel@tonic-gate 
14117c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PAGEDATA);
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
14147c478bd9Sstevel@tonic-gate 		return (error);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
14177c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
14187c478bd9Sstevel@tonic-gate 		prunlock(pnp);
14197c478bd9Sstevel@tonic-gate 		return (0);
14207c478bd9Sstevel@tonic-gate 	}
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
14237c478bd9Sstevel@tonic-gate 	error = prpdread(p, pnp->pr_hatid, uiop);
14247c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	prunlock(pnp);
14277c478bd9Sstevel@tonic-gate 	return (error);
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate static int
pr_read_opagedata(prnode_t * pnp,uio_t * uiop,cred_t * cr)143119ee9cd1SAndy Fiddaman pr_read_opagedata(prnode_t *pnp, uio_t *uiop, cred_t *cr)
14327c478bd9Sstevel@tonic-gate {
14337c478bd9Sstevel@tonic-gate 	proc_t *p;
14347c478bd9Sstevel@tonic-gate 	struct as *as;
14357c478bd9Sstevel@tonic-gate 	int error;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OPAGEDATA);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
14407c478bd9Sstevel@tonic-gate 		return (error);
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
14437c478bd9Sstevel@tonic-gate 	as = p->p_as;
14447c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
14457c478bd9Sstevel@tonic-gate 		prunlock(pnp);
14467c478bd9Sstevel@tonic-gate 		return (0);
14477c478bd9Sstevel@tonic-gate 	}
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
14507c478bd9Sstevel@tonic-gate 	error = oprpdread(as, pnp->pr_hatid, uiop);
14517c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	prunlock(pnp);
14547c478bd9Sstevel@tonic-gate 	return (error);
14557c478bd9Sstevel@tonic-gate }
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate static int
pr_read_watch(prnode_t * pnp,uio_t * uiop,cred_t * cr)145819ee9cd1SAndy Fiddaman pr_read_watch(prnode_t *pnp, uio_t *uiop, cred_t *cr)
14597c478bd9Sstevel@tonic-gate {
14607c478bd9Sstevel@tonic-gate 	proc_t *p;
14617c478bd9Sstevel@tonic-gate 	int error;
14627c478bd9Sstevel@tonic-gate 	prwatch_t *Bpwp;
14637c478bd9Sstevel@tonic-gate 	size_t size;
14647c478bd9Sstevel@tonic-gate 	prwatch_t *pwp;
14657c478bd9Sstevel@tonic-gate 	int nwarea;
14667c478bd9Sstevel@tonic-gate 	struct watched_area *pwarea;
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_WATCH);
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
14717c478bd9Sstevel@tonic-gate 		return (error);
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
14747c478bd9Sstevel@tonic-gate 	nwarea = avl_numnodes(&p->p_warea);
14757c478bd9Sstevel@tonic-gate 	size = nwarea * sizeof (prwatch_t);
14767c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
14777c478bd9Sstevel@tonic-gate 		prunlock(pnp);
14787c478bd9Sstevel@tonic-gate 		return (0);
14797c478bd9Sstevel@tonic-gate 	}
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
14827c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
14837c478bd9Sstevel@tonic-gate 	Bpwp = pwp = kmem_zalloc(size, KM_SLEEP);
14847c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
14857c478bd9Sstevel@tonic-gate 	/* p->p_nwarea can't change while process is locked */
14867c478bd9Sstevel@tonic-gate 	ASSERT(nwarea == avl_numnodes(&p->p_warea));
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	/* gather the watched areas */
14897c478bd9Sstevel@tonic-gate 	for (pwarea = avl_first(&p->p_warea); pwarea != NULL;
14907c478bd9Sstevel@tonic-gate 	    pwarea = AVL_NEXT(&p->p_warea, pwarea), pwp++) {
14917c478bd9Sstevel@tonic-gate 		pwp->pr_vaddr = (uintptr_t)pwarea->wa_vaddr;
14927c478bd9Sstevel@tonic-gate 		pwp->pr_size = pwarea->wa_eaddr - pwarea->wa_vaddr;
14937c478bd9Sstevel@tonic-gate 		pwp->pr_wflags = (int)pwarea->wa_flags;
14947c478bd9Sstevel@tonic-gate 	}
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate 	prunlock(pnp);
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	error = pr_uioread(Bpwp, size, uiop);
14997c478bd9Sstevel@tonic-gate 	kmem_free(Bpwp, size);
15007c478bd9Sstevel@tonic-gate 	return (error);
15017c478bd9Sstevel@tonic-gate }
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate static int
pr_read_lwpstatus(prnode_t * pnp,uio_t * uiop,cred_t * cr)150419ee9cd1SAndy Fiddaman pr_read_lwpstatus(prnode_t *pnp, uio_t *uiop, cred_t *cr)
15057c478bd9Sstevel@tonic-gate {
15067c478bd9Sstevel@tonic-gate 	lwpstatus_t *sp;
15077c478bd9Sstevel@tonic-gate 	int error;
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSTATUS);
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 	/*
15127c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the lwpstatus structure because
15137c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
15147c478bd9Sstevel@tonic-gate 	 */
15157c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
15187c478bd9Sstevel@tonic-gate 		goto out;
15197c478bd9Sstevel@tonic-gate 
15207c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (*sp)) {
15217c478bd9Sstevel@tonic-gate 		prunlock(pnp);
15227c478bd9Sstevel@tonic-gate 		goto out;
15237c478bd9Sstevel@tonic-gate 	}
15247c478bd9Sstevel@tonic-gate 
1525fa9e4066Sahrens 	prgetlwpstatus(pnp->pr_common->prc_thread, sp, VTOZONE(PTOV(pnp)));
15267c478bd9Sstevel@tonic-gate 	prunlock(pnp);
15277c478bd9Sstevel@tonic-gate 
15287c478bd9Sstevel@tonic-gate 	error = pr_uioread(sp, sizeof (*sp), uiop);
15297c478bd9Sstevel@tonic-gate out:
15307c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
15317c478bd9Sstevel@tonic-gate 	return (error);
15327c478bd9Sstevel@tonic-gate }
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate static int
pr_read_lwpsinfo(prnode_t * pnp,uio_t * uiop,cred_t * cr)153519ee9cd1SAndy Fiddaman pr_read_lwpsinfo(prnode_t *pnp, uio_t *uiop, cred_t *cr)
15367c478bd9Sstevel@tonic-gate {
15377c478bd9Sstevel@tonic-gate 	lwpsinfo_t lwpsinfo;
15387c478bd9Sstevel@tonic-gate 	proc_t *p;
15397c478bd9Sstevel@tonic-gate 	kthread_t *t;
15407c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSINFO);
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	/*
15457c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
15467c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
15477c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
15487c478bd9Sstevel@tonic-gate 	 */
15497c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
15507c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
15517c478bd9Sstevel@tonic-gate 	if (p == NULL)
15527c478bd9Sstevel@tonic-gate 		return (ENOENT);
15537c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
15547c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_tslot == -1) {
15557c478bd9Sstevel@tonic-gate 		prunlock(pnp);
15567c478bd9Sstevel@tonic-gate 		return (ENOENT);
15577c478bd9Sstevel@tonic-gate 	}
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpsinfo)) {
15607c478bd9Sstevel@tonic-gate 		prunlock(pnp);
15617c478bd9Sstevel@tonic-gate 		return (0);
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	if ((t = pnp->pr_common->prc_thread) != NULL)
15657c478bd9Sstevel@tonic-gate 		prgetlwpsinfo(t, &lwpsinfo);
15667c478bd9Sstevel@tonic-gate 	else {
15677c478bd9Sstevel@tonic-gate 		lep = p->p_lwpdir[pnp->pr_common->prc_tslot].ld_entry;
15687c478bd9Sstevel@tonic-gate 		bzero(&lwpsinfo, sizeof (lwpsinfo));
15697c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_lwpid = lep->le_lwpid;
15707c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_state = SZOMB;
15717c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_sname = 'Z';
15727c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_start.tv_sec = lep->le_start;
15737c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_bindpro = PBIND_NONE;
15747c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_bindpset = PS_NONE;
15757c478bd9Sstevel@tonic-gate 	}
15767c478bd9Sstevel@tonic-gate 	prunlock(pnp);
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	return (pr_uioread(&lwpsinfo, sizeof (lwpsinfo), uiop));
15797c478bd9Sstevel@tonic-gate }
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate static int
pr_read_lwpusage(prnode_t * pnp,uio_t * uiop,cred_t * cr)158219ee9cd1SAndy Fiddaman pr_read_lwpusage(prnode_t *pnp, uio_t *uiop, cred_t *cr)
15837c478bd9Sstevel@tonic-gate {
15847c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
15857c478bd9Sstevel@tonic-gate 	prusage_t *upup;
15867c478bd9Sstevel@tonic-gate 	proc_t *p;
15877c478bd9Sstevel@tonic-gate 	int error;
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPUSAGE);
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
15927c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
15937c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	/*
15967c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
15977c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
15987c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
15997c478bd9Sstevel@tonic-gate 	 */
16007c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
16017c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
16027c478bd9Sstevel@tonic-gate 	if (p == NULL) {
16037c478bd9Sstevel@tonic-gate 		error = ENOENT;
16047c478bd9Sstevel@tonic-gate 		goto out;
16057c478bd9Sstevel@tonic-gate 	}
16067c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
16077c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_thread == NULL) {
16087c478bd9Sstevel@tonic-gate 		prunlock(pnp);
16097c478bd9Sstevel@tonic-gate 		error = ENOENT;
16107c478bd9Sstevel@tonic-gate 		goto out;
16117c478bd9Sstevel@tonic-gate 	}
16127c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage_t)) {
16137c478bd9Sstevel@tonic-gate 		prunlock(pnp);
16147c478bd9Sstevel@tonic-gate 		error = 0;
16157c478bd9Sstevel@tonic-gate 		goto out;
16167c478bd9Sstevel@tonic-gate 	}
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
16197c478bd9Sstevel@tonic-gate 	prgetusage(pnp->pr_common->prc_thread, pup);
16207c478bd9Sstevel@tonic-gate 
16217c478bd9Sstevel@tonic-gate 	prunlock(pnp);
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	prcvtusage(pup, upup);
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage_t), uiop);
16267c478bd9Sstevel@tonic-gate out:
16277c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
16287c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
16297c478bd9Sstevel@tonic-gate 	return (error);
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate 
1632ab618543SJohn Levon static int
pr_read_lwpname(prnode_t * pnp,uio_t * uiop,cred_t * cr)163319ee9cd1SAndy Fiddaman pr_read_lwpname(prnode_t *pnp, uio_t *uiop, cred_t *cr)
1634ab618543SJohn Levon {
1635ab618543SJohn Levon 	char lwpname[THREAD_NAME_MAX];
1636ab618543SJohn Levon 	kthread_t *t;
1637ab618543SJohn Levon 	int error;
1638ab618543SJohn Levon 
1639ab618543SJohn Levon 	ASSERT(pnp->pr_type == PR_LWPNAME);
1640ab618543SJohn Levon 
1641ab618543SJohn Levon 	if (uiop->uio_offset >= THREAD_NAME_MAX)
1642ab618543SJohn Levon 		return (0);
1643ab618543SJohn Levon 
1644ab618543SJohn Levon 	if ((error = prlock(pnp, ZNO)) != 0)
1645ab618543SJohn Levon 		return (error);
1646ab618543SJohn Levon 
1647ab618543SJohn Levon 	bzero(lwpname, sizeof (lwpname));
1648ab618543SJohn Levon 
1649ab618543SJohn Levon 	t = pnp->pr_common->prc_thread;
1650ab618543SJohn Levon 
1651ab618543SJohn Levon 	if (t->t_name != NULL)
1652ab618543SJohn Levon 		(void) strlcpy(lwpname, t->t_name, sizeof (lwpname));
1653ab618543SJohn Levon 
1654ab618543SJohn Levon 	prunlock(pnp);
1655ab618543SJohn Levon 
1656ab618543SJohn Levon 	return (pr_uioread(lwpname, sizeof (lwpname), uiop));
1657ab618543SJohn Levon }
1658ab618543SJohn Levon 
16597c478bd9Sstevel@tonic-gate /* ARGSUSED */
16607c478bd9Sstevel@tonic-gate static int
pr_read_xregs(prnode_t * pnp,uio_t * uiop,cred_t * cr)166119ee9cd1SAndy Fiddaman pr_read_xregs(prnode_t *pnp, uio_t *uiop, cred_t *cr)
16627c478bd9Sstevel@tonic-gate {
16637c478bd9Sstevel@tonic-gate 	proc_t *p;
16647c478bd9Sstevel@tonic-gate 	kthread_t *t;
16657c478bd9Sstevel@tonic-gate 	int error;
1666ed093b41SRobert Mustacchi 	void *xreg;
16677c478bd9Sstevel@tonic-gate 	size_t size;
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XREGS);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
1672ed093b41SRobert Mustacchi 		return (error);
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
16757c478bd9Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
16767c478bd9Sstevel@tonic-gate 
1677ed093b41SRobert Mustacchi 	/*
1678ed093b41SRobert Mustacchi 	 * While we would prefer to do the allocation without holding the
1679ed093b41SRobert Mustacchi 	 * process under a prlock(), we can only determine this size while
1680ed093b41SRobert Mustacchi 	 * holding the process as the hold guarantees us:
1681ed093b41SRobert Mustacchi 	 *
1682ed093b41SRobert Mustacchi 	 *  o That the process in question actualy exists.
1683ed093b41SRobert Mustacchi 	 *  o That the process in question cannot change the set of FPU features
1684ed093b41SRobert Mustacchi 	 *    it has enabled.
1685ed093b41SRobert Mustacchi 	 *
1686ed093b41SRobert Mustacchi 	 * We will drop p_lock across the allocation call itself. This should be
1687ed093b41SRobert Mustacchi 	 * safe as the enabled feature set should not change while the process
1688ed093b41SRobert Mustacchi 	 * is locked (e.g. enabling extending FPU state like AMX on x86 should
1689ed093b41SRobert Mustacchi 	 * require the process to be locked).
1690ed093b41SRobert Mustacchi 	 */
16917c478bd9Sstevel@tonic-gate 	size = prhasx(p) ? prgetprxregsize(p) : 0;
1692ed093b41SRobert Mustacchi 	if (size == 0) {
1693ed093b41SRobert Mustacchi 		prunlock(pnp);
1694ed093b41SRobert Mustacchi 		return (0);
1695ed093b41SRobert Mustacchi 	}
1696a14132dbSRobert Mustacchi 
1697a14132dbSRobert Mustacchi 	/*
1698a14132dbSRobert Mustacchi 	 * To read the extended register set we require that the thread be
1699a14132dbSRobert Mustacchi 	 * stopped as this state is only valid in the kernel when it is. An
1700a14132dbSRobert Mustacchi 	 * exception made if the target thread and the current thread are one
1701a14132dbSRobert Mustacchi 	 * and the same. We won't stop you from doing something... weird.
1702a14132dbSRobert Mustacchi 	 */
1703a14132dbSRobert Mustacchi 	thread_lock(t);
1704a14132dbSRobert Mustacchi 	if (t != curthread && !ISTOPPED(t) && !VSTOPPED(t) && !DSTOPPED(t)) {
1705a14132dbSRobert Mustacchi 		thread_unlock(t);
1706a14132dbSRobert Mustacchi 		prunlock(pnp);
1707a14132dbSRobert Mustacchi 		return (EBUSY);
1708a14132dbSRobert Mustacchi 	}
1709a14132dbSRobert Mustacchi 	thread_unlock(t);
1710a14132dbSRobert Mustacchi 
1711ed093b41SRobert Mustacchi 	mutex_exit(&p->p_lock);
1712ed093b41SRobert Mustacchi 	xreg = kmem_zalloc(size, KM_SLEEP);
1713ed093b41SRobert Mustacchi 	mutex_enter(&p->p_lock);
1714ed093b41SRobert Mustacchi 	ASSERT3U(size, ==, prgetprxregsize(p));
1715ed093b41SRobert Mustacchi 
17167c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
17177c478bd9Sstevel@tonic-gate 		prunlock(pnp);
17187c478bd9Sstevel@tonic-gate 		goto out;
17197c478bd9Sstevel@tonic-gate 	}
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	/* drop p->p_lock while (possibly) touching the stack */
17227c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
17237c478bd9Sstevel@tonic-gate 	prgetprxregs(ttolwp(t), xreg);
17247c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
17257c478bd9Sstevel@tonic-gate 	prunlock(pnp);
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate 	error = pr_uioread(xreg, size, uiop);
17287c478bd9Sstevel@tonic-gate out:
1729ed093b41SRobert Mustacchi 	kmem_free(xreg, size);
17307c478bd9Sstevel@tonic-gate 	return (error);
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate 
1733f971a346SBryan Cantrill static int
pr_read_spymaster(prnode_t * pnp,uio_t * uiop,cred_t * cr)173419ee9cd1SAndy Fiddaman pr_read_spymaster(prnode_t *pnp, uio_t *uiop, cred_t *cr)
1735f971a346SBryan Cantrill {
1736f971a346SBryan Cantrill 	psinfo_t psinfo;
1737f971a346SBryan Cantrill 	int error;
1738f971a346SBryan Cantrill 	klwp_t *lwp;
1739f971a346SBryan Cantrill 
1740f971a346SBryan Cantrill 	ASSERT(pnp->pr_type == PR_SPYMASTER);
1741f971a346SBryan Cantrill 
1742f971a346SBryan Cantrill 	if ((error = prlock(pnp, ZNO)) != 0)
1743f971a346SBryan Cantrill 		return (error);
1744f971a346SBryan Cantrill 
1745614f1d63SJerry Jelinek 	if (pnp->pr_common->prc_thread == NULL) {
1746614f1d63SJerry Jelinek 		prunlock(pnp);
1747614f1d63SJerry Jelinek 		return (0);
1748614f1d63SJerry Jelinek 	}
1749614f1d63SJerry Jelinek 
1750f971a346SBryan Cantrill 	lwp = pnp->pr_common->prc_thread->t_lwp;
1751f971a346SBryan Cantrill 
1752f971a346SBryan Cantrill 	if (lwp->lwp_spymaster == NULL) {
1753f971a346SBryan Cantrill 		prunlock(pnp);
1754f971a346SBryan Cantrill 		return (0);
1755f971a346SBryan Cantrill 	}
1756f971a346SBryan Cantrill 
1757f971a346SBryan Cantrill 	bcopy(lwp->lwp_spymaster, &psinfo, sizeof (psinfo_t));
1758f971a346SBryan Cantrill 	prunlock(pnp);
1759f971a346SBryan Cantrill 
1760f971a346SBryan Cantrill 	return (pr_uioread(&psinfo, sizeof (psinfo), uiop));
1761f971a346SBryan Cantrill }
1762f971a346SBryan Cantrill 
1763d2a70789SRichard Lowe static int
pr_read_secflags(prnode_t * pnp,uio_t * uiop,cred_t * cr)176419ee9cd1SAndy Fiddaman pr_read_secflags(prnode_t *pnp, uio_t *uiop, cred_t *cr)
1765d2a70789SRichard Lowe {
1766d2a70789SRichard Lowe 	prsecflags_t ret;
1767d2a70789SRichard Lowe 	int error;
1768d2a70789SRichard Lowe 	proc_t *p;
1769d2a70789SRichard Lowe 
1770d2a70789SRichard Lowe 	ASSERT(pnp->pr_type == PR_SECFLAGS);
1771d2a70789SRichard Lowe 
1772d2a70789SRichard Lowe 	if ((error = prlock(pnp, ZNO)) != 0)
1773d2a70789SRichard Lowe 		return (error);
1774d2a70789SRichard Lowe 
1775d2a70789SRichard Lowe 	p = pnp->pr_common->prc_proc;
1776d2a70789SRichard Lowe 	prgetsecflags(p, &ret);
1777d2a70789SRichard Lowe 	prunlock(pnp);
1778d2a70789SRichard Lowe 
1779d2a70789SRichard Lowe 	return (pr_uioread(&ret, sizeof (ret), uiop));
1780d2a70789SRichard Lowe }
1781d2a70789SRichard Lowe 
17827c478bd9Sstevel@tonic-gate #if defined(__sparc)
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate static int
pr_read_gwindows(prnode_t * pnp,uio_t * uiop,cred_t * cr)178519ee9cd1SAndy Fiddaman pr_read_gwindows(prnode_t *pnp, uio_t *uiop, cred_t *cr)
17867c478bd9Sstevel@tonic-gate {
17877c478bd9Sstevel@tonic-gate 	proc_t *p;
17887c478bd9Sstevel@tonic-gate 	kthread_t *t;
17897c478bd9Sstevel@tonic-gate 	gwindows_t *gwp;
17907c478bd9Sstevel@tonic-gate 	int error;
17917c478bd9Sstevel@tonic-gate 	size_t size;
17927c478bd9Sstevel@tonic-gate 
17937c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_GWINDOWS);
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	gwp = kmem_zalloc(sizeof (gwindows_t), KM_SLEEP);
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
17987c478bd9Sstevel@tonic-gate 		goto out;
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
18017c478bd9Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	/*
18047c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock while touching the stack.
18057c478bd9Sstevel@tonic-gate 	 * The P_PR_LOCK flag prevents the lwp from
18067c478bd9Sstevel@tonic-gate 	 * disappearing while we do this.
18077c478bd9Sstevel@tonic-gate 	 */
18087c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
18097c478bd9Sstevel@tonic-gate 	if ((size = prnwindows(ttolwp(t))) != 0)
18107c478bd9Sstevel@tonic-gate 		size = sizeof (gwindows_t) -
18117c478bd9Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW - size) * sizeof (struct rwindow);
18127c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
18137c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
18147c478bd9Sstevel@tonic-gate 		prunlock(pnp);
18157c478bd9Sstevel@tonic-gate 		goto out;
18167c478bd9Sstevel@tonic-gate 	}
18177c478bd9Sstevel@tonic-gate 	prgetwindows(ttolwp(t), gwp);
18187c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
18197c478bd9Sstevel@tonic-gate 	prunlock(pnp);
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	error = pr_uioread(gwp, size, uiop);
18227c478bd9Sstevel@tonic-gate out:
18237c478bd9Sstevel@tonic-gate 	kmem_free(gwp, sizeof (gwindows_t));
18247c478bd9Sstevel@tonic-gate 	return (error);
18257c478bd9Sstevel@tonic-gate }
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate /* ARGSUSED */
18287c478bd9Sstevel@tonic-gate static int
pr_read_asrs(prnode_t * pnp,uio_t * uiop,cred_t * cr)182919ee9cd1SAndy Fiddaman pr_read_asrs(prnode_t *pnp, uio_t *uiop, cred_t *cr)
18307c478bd9Sstevel@tonic-gate {
18317c478bd9Sstevel@tonic-gate 	int error;
18327c478bd9Sstevel@tonic-gate 
18337c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_ASRS);
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	/* the asrs file exists only for sparc v9 _LP64 processes */
18367c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
18377c478bd9Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
18387c478bd9Sstevel@tonic-gate 		kthread_t *t = pnp->pr_common->prc_thread;
18397c478bd9Sstevel@tonic-gate 		asrset_t asrset;
18407c478bd9Sstevel@tonic-gate 
18417c478bd9Sstevel@tonic-gate 		if (p->p_model != DATAMODEL_LP64 ||
18427c478bd9Sstevel@tonic-gate 		    uiop->uio_offset >= sizeof (asrset_t)) {
18437c478bd9Sstevel@tonic-gate 			prunlock(pnp);
18447c478bd9Sstevel@tonic-gate 			return (0);
18457c478bd9Sstevel@tonic-gate 		}
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 		/*
18487c478bd9Sstevel@tonic-gate 		 * Drop p->p_lock while touching the stack.
18497c478bd9Sstevel@tonic-gate 		 * The P_PR_LOCK flag prevents the lwp from
18507c478bd9Sstevel@tonic-gate 		 * disappearing while we do this.
18517c478bd9Sstevel@tonic-gate 		 */
18527c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
18537c478bd9Sstevel@tonic-gate 		prgetasregs(ttolwp(t), asrset);
18547c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
18557c478bd9Sstevel@tonic-gate 		prunlock(pnp);
18567c478bd9Sstevel@tonic-gate 
18577c478bd9Sstevel@tonic-gate 		error = pr_uioread(&asrset[0], sizeof (asrset_t), uiop);
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	return (error);
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate #endif	/* __sparc */
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate static int
pr_read_piddir(prnode_t * pnp,uio_t * uiop,cred_t * cr)186619ee9cd1SAndy Fiddaman pr_read_piddir(prnode_t *pnp, uio_t *uiop, cred_t *cr)
18677c478bd9Sstevel@tonic-gate {
18687c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDDIR);
18697c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_pidfile != NULL);
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 	/* use the underlying PR_PIDFILE to read the process */
18727c478bd9Sstevel@tonic-gate 	pnp = VTOP(pnp->pr_pidfile);
18737c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDFILE);
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	return (pr_read_pidfile(pnp, uiop));
18767c478bd9Sstevel@tonic-gate }
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate static int
pr_read_pidfile(prnode_t * pnp,uio_t * uiop,cred_t * cr)187919ee9cd1SAndy Fiddaman pr_read_pidfile(prnode_t *pnp, uio_t *uiop, cred_t *cr)
18807c478bd9Sstevel@tonic-gate {
18817c478bd9Sstevel@tonic-gate 	int error;
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDFILE || pnp->pr_type == PR_LWPIDFILE);
18847c478bd9Sstevel@tonic-gate 
18857c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
18867c478bd9Sstevel@tonic-gate 		proc_t *p = pnp->pr_common->prc_proc;
18877c478bd9Sstevel@tonic-gate 		struct as *as = p->p_as;
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || as == &kas) {
18907c478bd9Sstevel@tonic-gate 			/*
18917c478bd9Sstevel@tonic-gate 			 * /proc I/O cannot be done to a system process.
18927c478bd9Sstevel@tonic-gate 			 */
18937c478bd9Sstevel@tonic-gate 			error = EIO;	/* old /proc semantics */
18947c478bd9Sstevel@tonic-gate 		} else {
18957c478bd9Sstevel@tonic-gate 			/*
18967c478bd9Sstevel@tonic-gate 			 * We drop p_lock because we don't want to hold
18977c478bd9Sstevel@tonic-gate 			 * it over an I/O operation because that could
18987c478bd9Sstevel@tonic-gate 			 * lead to deadlock with the clock thread.
18997c478bd9Sstevel@tonic-gate 			 * The process will not disappear and its address
19007c478bd9Sstevel@tonic-gate 			 * space will not change because it is marked P_PR_LOCK.
19017c478bd9Sstevel@tonic-gate 			 */
19027c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
19037c478bd9Sstevel@tonic-gate 			error = prusrio(p, UIO_READ, uiop, 1);
19047c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
19057c478bd9Sstevel@tonic-gate 		}
19067c478bd9Sstevel@tonic-gate 		prunlock(pnp);
19077c478bd9Sstevel@tonic-gate 	}
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate 	return (error);
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate /*
19157c478bd9Sstevel@tonic-gate  * Array of ILP32 read functions, indexed by /proc file type.
19167c478bd9Sstevel@tonic-gate  */
19177c478bd9Sstevel@tonic-gate static int pr_read_status_32(),
19187c478bd9Sstevel@tonic-gate 	pr_read_lstatus_32(), pr_read_psinfo_32(), pr_read_lpsinfo_32(),
19197c478bd9Sstevel@tonic-gate 	pr_read_map_32(), pr_read_rmap_32(), pr_read_xmap_32(),
19207c478bd9Sstevel@tonic-gate 	pr_read_sigact_32(), pr_read_auxv_32(),
19217c478bd9Sstevel@tonic-gate 	pr_read_usage_32(), pr_read_lusage_32(), pr_read_pagedata_32(),
19227c478bd9Sstevel@tonic-gate 	pr_read_watch_32(), pr_read_lwpstatus_32(), pr_read_lwpsinfo_32(),
1923f971a346SBryan Cantrill 	pr_read_lwpusage_32(), pr_read_spymaster_32(),
19247c478bd9Sstevel@tonic-gate #if defined(__sparc)
19257c478bd9Sstevel@tonic-gate 	pr_read_gwindows_32(),
19267c478bd9Sstevel@tonic-gate #endif
19277c478bd9Sstevel@tonic-gate 	pr_read_opagedata_32();
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate static int (*pr_read_function_32[PR_NFILES])() = {
19307c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc				*/
19317c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/self				*/
19327c478bd9Sstevel@tonic-gate 	pr_read_piddir,		/* /proc/<pid> (old /proc read())	*/
19337c478bd9Sstevel@tonic-gate 	pr_read_as,		/* /proc/<pid>/as			*/
19347c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/ctl			*/
19357c478bd9Sstevel@tonic-gate 	pr_read_status_32,	/* /proc/<pid>/status			*/
19367c478bd9Sstevel@tonic-gate 	pr_read_lstatus_32,	/* /proc/<pid>/lstatus			*/
19377c478bd9Sstevel@tonic-gate 	pr_read_psinfo_32,	/* /proc/<pid>/psinfo			*/
19387c478bd9Sstevel@tonic-gate 	pr_read_lpsinfo_32,	/* /proc/<pid>/lpsinfo			*/
19397c478bd9Sstevel@tonic-gate 	pr_read_map_32,		/* /proc/<pid>/map			*/
19407c478bd9Sstevel@tonic-gate 	pr_read_rmap_32,	/* /proc/<pid>/rmap			*/
19417c478bd9Sstevel@tonic-gate 	pr_read_xmap_32,	/* /proc/<pid>/xmap			*/
19427c478bd9Sstevel@tonic-gate 	pr_read_cred,		/* /proc/<pid>/cred			*/
19437c478bd9Sstevel@tonic-gate 	pr_read_sigact_32,	/* /proc/<pid>/sigact			*/
19447c478bd9Sstevel@tonic-gate 	pr_read_auxv_32,	/* /proc/<pid>/auxv			*/
19457c478bd9Sstevel@tonic-gate #if defined(__x86)
19467c478bd9Sstevel@tonic-gate 	pr_read_ldt,		/* /proc/<pid>/ldt			*/
19477c478bd9Sstevel@tonic-gate #endif
19487c478bd9Sstevel@tonic-gate 	pr_read_usage_32,	/* /proc/<pid>/usage			*/
19497c478bd9Sstevel@tonic-gate 	pr_read_lusage_32,	/* /proc/<pid>/lusage			*/
19507c478bd9Sstevel@tonic-gate 	pr_read_pagedata_32,	/* /proc/<pid>/pagedata			*/
19517c478bd9Sstevel@tonic-gate 	pr_read_watch_32,	/* /proc/<pid>/watch			*/
19527c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/cwd			*/
19537c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/root			*/
19547c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd			*/
19557c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/fd/nn			*/
1956a02120c4SAndy Fiddaman 	pr_read_inval,		/* /proc/<pid>/fdinfo			*/
1957a02120c4SAndy Fiddaman 	pr_read_fdinfo,		/* /proc/<pid>/fdinfo/nn		*/
19587c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object			*/
19597c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/object/xxx		*/
19607c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp			*/
19617c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>		*/
19627c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
1963ab618543SJohn Levon 	pr_read_lwpname,	/* /proc/<pid>/lwp/<lwpid>/lwpname	*/
19647c478bd9Sstevel@tonic-gate 	pr_read_lwpstatus_32,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
19657c478bd9Sstevel@tonic-gate 	pr_read_lwpsinfo_32,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
19667c478bd9Sstevel@tonic-gate 	pr_read_lwpusage_32,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
19677c478bd9Sstevel@tonic-gate 	pr_read_xregs,		/* /proc/<pid>/lwp/<lwpid>/xregs	*/
19687c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates	*/
19697c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
1970f971a346SBryan Cantrill 	pr_read_spymaster_32,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
19717c478bd9Sstevel@tonic-gate #if defined(__sparc)
19727c478bd9Sstevel@tonic-gate 	pr_read_gwindows_32,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
19737c478bd9Sstevel@tonic-gate 	pr_read_asrs,		/* /proc/<pid>/lwp/<lwpid>/asrs		*/
19747c478bd9Sstevel@tonic-gate #endif
19757c478bd9Sstevel@tonic-gate 	pr_read_priv,		/* /proc/<pid>/priv			*/
19767c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path			*/
19777c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/path/xxx			*/
19787c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts		*/
19797c478bd9Sstevel@tonic-gate 	pr_read_inval,		/* /proc/<pid>/contracts/<ctid>		*/
1980d2a70789SRichard Lowe 	pr_read_secflags,	/* /proc/<pid>/secflags			*/
19817c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old process file			*/
19827c478bd9Sstevel@tonic-gate 	pr_read_pidfile,	/* old lwp file				*/
19837c478bd9Sstevel@tonic-gate 	pr_read_opagedata_32,	/* old pagedata file			*/
19847c478bd9Sstevel@tonic-gate };
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate static int
pr_read_status_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)198719ee9cd1SAndy Fiddaman pr_read_status_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
19887c478bd9Sstevel@tonic-gate {
19897c478bd9Sstevel@tonic-gate 	pstatus32_t *sp;
19907c478bd9Sstevel@tonic-gate 	proc_t *p;
19917c478bd9Sstevel@tonic-gate 	int error;
19927c478bd9Sstevel@tonic-gate 
19937c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_STATUS);
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	/*
19967c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the pstatus structure because
19977c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
19987c478bd9Sstevel@tonic-gate 	 */
19997c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
20007c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) == 0) {
20017c478bd9Sstevel@tonic-gate 		/*
20027c478bd9Sstevel@tonic-gate 		 * A 32-bit process cannot get the status of a 64-bit process.
20037c478bd9Sstevel@tonic-gate 		 * The fields for the 64-bit quantities are not large enough.
20047c478bd9Sstevel@tonic-gate 		 */
20057c478bd9Sstevel@tonic-gate 		p = pnp->pr_common->prc_proc;
20067c478bd9Sstevel@tonic-gate 		if (PROCESS_NOT_32BIT(p)) {
20077c478bd9Sstevel@tonic-gate 			prunlock(pnp);
20087c478bd9Sstevel@tonic-gate 			error = EOVERFLOW;
20097c478bd9Sstevel@tonic-gate 		} else {
20107c478bd9Sstevel@tonic-gate 			prgetstatus32(pnp->pr_common->prc_proc, sp,
2011fa9e4066Sahrens 			    VTOZONE(PTOV(pnp)));
20127c478bd9Sstevel@tonic-gate 			prunlock(pnp);
20137c478bd9Sstevel@tonic-gate 			error = pr_uioread(sp, sizeof (*sp), uiop);
20147c478bd9Sstevel@tonic-gate 		}
20157c478bd9Sstevel@tonic-gate 	}
20167c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)sp, sizeof (*sp));
20177c478bd9Sstevel@tonic-gate 	return (error);
20187c478bd9Sstevel@tonic-gate }
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate static int
pr_read_lstatus_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)202119ee9cd1SAndy Fiddaman pr_read_lstatus_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
20227c478bd9Sstevel@tonic-gate {
20237c478bd9Sstevel@tonic-gate 	proc_t *p;
20247c478bd9Sstevel@tonic-gate 	kthread_t *t;
20257c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
20267c478bd9Sstevel@tonic-gate 	size_t size;
20277c478bd9Sstevel@tonic-gate 	prheader32_t *php;
20287c478bd9Sstevel@tonic-gate 	lwpstatus32_t *sp;
20297c478bd9Sstevel@tonic-gate 	int error;
20307c478bd9Sstevel@tonic-gate 	int nlwp;
20317c478bd9Sstevel@tonic-gate 	int i;
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LSTATUS);
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
20367c478bd9Sstevel@tonic-gate 		return (error);
20377c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
20387c478bd9Sstevel@tonic-gate 	/*
20397c478bd9Sstevel@tonic-gate 	 * A 32-bit process cannot get the status of a 64-bit process.
20407c478bd9Sstevel@tonic-gate 	 * The fields for the 64-bit quantities are not large enough.
20417c478bd9Sstevel@tonic-gate 	 */
20427c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
20437c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20447c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
20457c478bd9Sstevel@tonic-gate 	}
20467c478bd9Sstevel@tonic-gate 	nlwp = p->p_lwpcnt;
20477c478bd9Sstevel@tonic-gate 	size = sizeof (prheader32_t) + nlwp * LSPAN32(lwpstatus32_t);
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
20507c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
20517c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
20527c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
20537c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
20547c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
20577c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(lwpstatus32_t);
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	sp = (lwpstatus32_t *)(php + 1);
20607c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
20617c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
20627c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
20637c478bd9Sstevel@tonic-gate 			continue;
2064fa9e4066Sahrens 		prgetlwpstatus32(t, sp, VTOZONE(PTOV(pnp)));
20657c478bd9Sstevel@tonic-gate 		sp = (lwpstatus32_t *)((caddr_t)sp + LSPAN32(lwpstatus32_t));
20667c478bd9Sstevel@tonic-gate 	}
20677c478bd9Sstevel@tonic-gate 	prunlock(pnp);
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
20707c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
20717c478bd9Sstevel@tonic-gate 	return (error);
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate static int
pr_read_psinfo_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)207519ee9cd1SAndy Fiddaman pr_read_psinfo_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
20767c478bd9Sstevel@tonic-gate {
20777c478bd9Sstevel@tonic-gate 	psinfo32_t psinfo;
20787c478bd9Sstevel@tonic-gate 	proc_t *p;
20797c478bd9Sstevel@tonic-gate 	int error = 0;
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PSINFO);
20827c478bd9Sstevel@tonic-gate 
20837c478bd9Sstevel@tonic-gate 	/*
20847c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
20857c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
20867c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
20877c478bd9Sstevel@tonic-gate 	 */
20887c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
20897c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
20907c478bd9Sstevel@tonic-gate 	if (p == NULL)
20917c478bd9Sstevel@tonic-gate 		error = ENOENT;
20927c478bd9Sstevel@tonic-gate 	else {
20937c478bd9Sstevel@tonic-gate 		ASSERT(p == pnp->pr_common->prc_proc);
20947c478bd9Sstevel@tonic-gate 		prgetpsinfo32(p, &psinfo);
20957c478bd9Sstevel@tonic-gate 		prunlock(pnp);
20967c478bd9Sstevel@tonic-gate 		error = pr_uioread(&psinfo, sizeof (psinfo), uiop);
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 	return (error);
20997c478bd9Sstevel@tonic-gate }
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate static int
pr_read_lpsinfo_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)210219ee9cd1SAndy Fiddaman pr_read_lpsinfo_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
21037c478bd9Sstevel@tonic-gate {
21047c478bd9Sstevel@tonic-gate 	proc_t *p;
21057c478bd9Sstevel@tonic-gate 	kthread_t *t;
21067c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
21077c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
21087c478bd9Sstevel@tonic-gate 	size_t size;
21097c478bd9Sstevel@tonic-gate 	prheader32_t *php;
21107c478bd9Sstevel@tonic-gate 	lwpsinfo32_t *sp;
21117c478bd9Sstevel@tonic-gate 	int error;
21127c478bd9Sstevel@tonic-gate 	int nlwp;
21137c478bd9Sstevel@tonic-gate 	int i;
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LPSINFO);
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 	/*
21187c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
21197c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
21207c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
21217c478bd9Sstevel@tonic-gate 	 */
21227c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
21237c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
21247c478bd9Sstevel@tonic-gate 	if (p == NULL)
21257c478bd9Sstevel@tonic-gate 		return (ENOENT);
21267c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
21277c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt + p->p_zombcnt) == 0) {
21287c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21297c478bd9Sstevel@tonic-gate 		return (ENOENT);
21307c478bd9Sstevel@tonic-gate 	}
21317c478bd9Sstevel@tonic-gate 	size = sizeof (prheader32_t) + nlwp * LSPAN32(lwpsinfo32_t);
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
21347c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
21357c478bd9Sstevel@tonic-gate 	php = kmem_zalloc(size, KM_SLEEP);
21367c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
21377c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
21387c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt + p->p_zombcnt);
21397c478bd9Sstevel@tonic-gate 
21407c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp;
21417c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(lwpsinfo32_t);
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	sp = (lwpsinfo32_t *)(php + 1);
21447c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
21457c478bd9Sstevel@tonic-gate 		if ((lep = ldp->ld_entry) == NULL)
21467c478bd9Sstevel@tonic-gate 			continue;
21477c478bd9Sstevel@tonic-gate 		if ((t = lep->le_thread) != NULL)
21487c478bd9Sstevel@tonic-gate 			prgetlwpsinfo32(t, sp);
21497c478bd9Sstevel@tonic-gate 		else {
21507c478bd9Sstevel@tonic-gate 			bzero(sp, sizeof (*sp));
21517c478bd9Sstevel@tonic-gate 			sp->pr_lwpid = lep->le_lwpid;
21527c478bd9Sstevel@tonic-gate 			sp->pr_state = SZOMB;
21537c478bd9Sstevel@tonic-gate 			sp->pr_sname = 'Z';
21547c478bd9Sstevel@tonic-gate 			sp->pr_start.tv_sec = (time32_t)lep->le_start;
21557c478bd9Sstevel@tonic-gate 		}
21567c478bd9Sstevel@tonic-gate 		sp = (lwpsinfo32_t *)((caddr_t)sp + LSPAN32(lwpsinfo32_t));
21577c478bd9Sstevel@tonic-gate 	}
21587c478bd9Sstevel@tonic-gate 	prunlock(pnp);
21597c478bd9Sstevel@tonic-gate 
21607c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
21617c478bd9Sstevel@tonic-gate 	kmem_free(php, size);
21627c478bd9Sstevel@tonic-gate 	return (error);
21637c478bd9Sstevel@tonic-gate }
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate static int
pr_read_map_common_32(prnode_t * pnp,uio_t * uiop,prnodetype_t type)2166870619e9Sfrankho pr_read_map_common_32(prnode_t *pnp, uio_t *uiop, prnodetype_t type)
21677c478bd9Sstevel@tonic-gate {
21687c478bd9Sstevel@tonic-gate 	proc_t *p;
21697c478bd9Sstevel@tonic-gate 	struct as *as;
2170870619e9Sfrankho 	list_t	iolhead;
21717c478bd9Sstevel@tonic-gate 	int error;
21727c478bd9Sstevel@tonic-gate 
2173e24ad047SChristopher Baumbauer - Oracle America - San Diego United States readmap32_common:
21747c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
21757c478bd9Sstevel@tonic-gate 		return (error);
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
21787c478bd9Sstevel@tonic-gate 	as = p->p_as;
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
21817c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21827c478bd9Sstevel@tonic-gate 		return (0);
21837c478bd9Sstevel@tonic-gate 	}
21847c478bd9Sstevel@tonic-gate 
21857c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
21867c478bd9Sstevel@tonic-gate 		prunlock(pnp);
21877c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
21887c478bd9Sstevel@tonic-gate 	}
21897c478bd9Sstevel@tonic-gate 
2190dc32d872SJosef 'Jeff' Sipek 	if (!AS_LOCK_TRYENTER(as, RW_WRITER)) {
2191e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		prunlock(pnp);
2192e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		delay(1);
2193e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 		goto readmap32_common;
2194e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 	}
21957c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
2196e24ad047SChristopher Baumbauer - Oracle America - San Diego United States 
2197870619e9Sfrankho 	switch (type) {
2198870619e9Sfrankho 	case PR_XMAP:
2199870619e9Sfrankho 		error = prgetxmap32(p, &iolhead);
2200870619e9Sfrankho 		break;
2201870619e9Sfrankho 	case PR_RMAP:
2202870619e9Sfrankho 		error = prgetmap32(p, 1, &iolhead);
2203870619e9Sfrankho 		break;
2204870619e9Sfrankho 	case PR_MAP:
2205870619e9Sfrankho 		error = prgetmap32(p, 0, &iolhead);
2206870619e9Sfrankho 		break;
2207870619e9Sfrankho 	}
2208dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
22097c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
22107c478bd9Sstevel@tonic-gate 	prunlock(pnp);
22117c478bd9Sstevel@tonic-gate 
2212870619e9Sfrankho 	error = pr_iol_uiomove_and_free(&iolhead, uiop, error);
2213870619e9Sfrankho 
22147c478bd9Sstevel@tonic-gate 	return (error);
22157c478bd9Sstevel@tonic-gate }
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate static int
pr_read_map_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)221819ee9cd1SAndy Fiddaman pr_read_map_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
22197c478bd9Sstevel@tonic-gate {
22207c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_MAP);
2221870619e9Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
22227c478bd9Sstevel@tonic-gate }
22237c478bd9Sstevel@tonic-gate 
22247c478bd9Sstevel@tonic-gate static int
pr_read_rmap_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)222519ee9cd1SAndy Fiddaman pr_read_rmap_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
22267c478bd9Sstevel@tonic-gate {
22277c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_RMAP);
2228870619e9Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
22297c478bd9Sstevel@tonic-gate }
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate static int
pr_read_xmap_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)223219ee9cd1SAndy Fiddaman pr_read_xmap_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
22337c478bd9Sstevel@tonic-gate {
22347c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_XMAP);
2235870619e9Sfrankho 	return (pr_read_map_common_32(pnp, uiop, pnp->pr_type));
22367c478bd9Sstevel@tonic-gate }
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate static int
pr_read_sigact_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)223919ee9cd1SAndy Fiddaman pr_read_sigact_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
22407c478bd9Sstevel@tonic-gate {
2241eb9dbf0cSRoger A. Faulkner 	int nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
22427c478bd9Sstevel@tonic-gate 	proc_t *p;
22437c478bd9Sstevel@tonic-gate 	struct sigaction32 *sap;
22447c478bd9Sstevel@tonic-gate 	int sig;
22457c478bd9Sstevel@tonic-gate 	int error;
22467c478bd9Sstevel@tonic-gate 	user_t *up;
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_SIGACT);
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	/*
22517c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the sigaction32 array because
22527c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
22537c478bd9Sstevel@tonic-gate 	 */
2254eb9dbf0cSRoger A. Faulkner 	sap = kmem_alloc((nsig-1) * sizeof (struct sigaction32), KM_SLEEP);
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
22577c478bd9Sstevel@tonic-gate 		goto out;
22587c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
22617c478bd9Sstevel@tonic-gate 		prunlock(pnp);
22627c478bd9Sstevel@tonic-gate 		error = EOVERFLOW;
22637c478bd9Sstevel@tonic-gate 		goto out;
22647c478bd9Sstevel@tonic-gate 	}
22657c478bd9Sstevel@tonic-gate 
2266eb9dbf0cSRoger A. Faulkner 	if (uiop->uio_offset >= (nsig-1) * sizeof (struct sigaction32)) {
22677c478bd9Sstevel@tonic-gate 		prunlock(pnp);
22687c478bd9Sstevel@tonic-gate 		goto out;
22697c478bd9Sstevel@tonic-gate 	}
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	up = PTOU(p);
2272eb9dbf0cSRoger A. Faulkner 	for (sig = 1; sig < nsig; sig++)
22737c478bd9Sstevel@tonic-gate 		prgetaction32(p, up, sig, &sap[sig-1]);
22747c478bd9Sstevel@tonic-gate 	prunlock(pnp);
22757c478bd9Sstevel@tonic-gate 
2276eb9dbf0cSRoger A. Faulkner 	error = pr_uioread(sap, (nsig - 1) * sizeof (struct sigaction32), uiop);
22777c478bd9Sstevel@tonic-gate out:
2278eb9dbf0cSRoger A. Faulkner 	kmem_free(sap, (nsig-1) * sizeof (struct sigaction32));
22797c478bd9Sstevel@tonic-gate 	return (error);
22807c478bd9Sstevel@tonic-gate }
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate static int
pr_read_auxv_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)228319ee9cd1SAndy Fiddaman pr_read_auxv_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
22847c478bd9Sstevel@tonic-gate {
22857c478bd9Sstevel@tonic-gate 	auxv32_t auxv[__KERN_NAUXV_IMPL];
22867c478bd9Sstevel@tonic-gate 	proc_t *p;
22877c478bd9Sstevel@tonic-gate 	user_t *up;
22887c478bd9Sstevel@tonic-gate 	int error;
22897c478bd9Sstevel@tonic-gate 	int i;
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_AUXV);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
22947c478bd9Sstevel@tonic-gate 		return (error);
22957c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
22987c478bd9Sstevel@tonic-gate 		prunlock(pnp);
22997c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
23007c478bd9Sstevel@tonic-gate 	}
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (auxv)) {
23037c478bd9Sstevel@tonic-gate 		prunlock(pnp);
23047c478bd9Sstevel@tonic-gate 		return (0);
23057c478bd9Sstevel@tonic-gate 	}
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	up = PTOU(p);
23087c478bd9Sstevel@tonic-gate 	for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
23097c478bd9Sstevel@tonic-gate 		auxv[i].a_type = (int32_t)up->u_auxv[i].a_type;
23107c478bd9Sstevel@tonic-gate 		auxv[i].a_un.a_val = (int32_t)up->u_auxv[i].a_un.a_val;
23117c478bd9Sstevel@tonic-gate 	}
23127c478bd9Sstevel@tonic-gate 	prunlock(pnp);
23137c478bd9Sstevel@tonic-gate 
23147c478bd9Sstevel@tonic-gate 	return (pr_uioread(auxv, sizeof (auxv), uiop));
23157c478bd9Sstevel@tonic-gate }
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate static int
pr_read_usage_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)231819ee9cd1SAndy Fiddaman pr_read_usage_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
23197c478bd9Sstevel@tonic-gate {
23207c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
23217c478bd9Sstevel@tonic-gate 	prusage32_t *upup;
23227c478bd9Sstevel@tonic-gate 	proc_t *p;
23237c478bd9Sstevel@tonic-gate 	kthread_t *t;
23247c478bd9Sstevel@tonic-gate 	int error;
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_USAGE);
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
23297c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
23307c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	/*
23337c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
23347c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
23357c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
23367c478bd9Sstevel@tonic-gate 	 */
23377c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
23387c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
23397c478bd9Sstevel@tonic-gate 	if (p == NULL) {
23407c478bd9Sstevel@tonic-gate 		error = ENOENT;
23417c478bd9Sstevel@tonic-gate 		goto out;
23427c478bd9Sstevel@tonic-gate 	}
23437c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage32_t)) {
23467c478bd9Sstevel@tonic-gate 		prunlock(pnp);
23477c478bd9Sstevel@tonic-gate 		error = 0;
23487c478bd9Sstevel@tonic-gate 		goto out;
23497c478bd9Sstevel@tonic-gate 	}
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
23547c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
23557c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
23587c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
23597c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
23607c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
23617c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
23627c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
23637c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
23647c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
23657c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
23667c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
23677c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
23687c478bd9Sstevel@tonic-gate 
23697c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
23707c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
23717c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
23727c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
23737c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
23747c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
23757c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
23767c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
23777c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
23787c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
23797c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
23807c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	/*
23837c478bd9Sstevel@tonic-gate 	 * Add the usage information for each active lwp.
23847c478bd9Sstevel@tonic-gate 	 */
23857c478bd9Sstevel@tonic-gate 	if ((t = p->p_tlist) != NULL &&
23867c478bd9Sstevel@tonic-gate 	    !(pnp->pr_pcommon->prc_flags & PRC_DESTROY)) {
23877c478bd9Sstevel@tonic-gate 		do {
23887c478bd9Sstevel@tonic-gate 			if (t->t_proc_flag & TP_LWPEXIT)
23897c478bd9Sstevel@tonic-gate 				continue;
23907c478bd9Sstevel@tonic-gate 			pup->pr_count++;
23917c478bd9Sstevel@tonic-gate 			praddusage(t, pup);
23927c478bd9Sstevel@tonic-gate 		} while ((t = t->t_forw) != p->p_tlist);
23937c478bd9Sstevel@tonic-gate 	}
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 	prunlock(pnp);
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	prcvtusage32(pup, upup);
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage32_t), uiop);
24007c478bd9Sstevel@tonic-gate out:
24017c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
24027c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
24037c478bd9Sstevel@tonic-gate 	return (error);
24047c478bd9Sstevel@tonic-gate }
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate static int
pr_read_lusage_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)240719ee9cd1SAndy Fiddaman pr_read_lusage_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
24087c478bd9Sstevel@tonic-gate {
24097c478bd9Sstevel@tonic-gate 	int nlwp;
24107c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
24117c478bd9Sstevel@tonic-gate 	prheader32_t *php;
24127c478bd9Sstevel@tonic-gate 	prusage32_t *upup;
24137c478bd9Sstevel@tonic-gate 	size_t size;
24147c478bd9Sstevel@tonic-gate 	hrtime_t curtime;
24157c478bd9Sstevel@tonic-gate 	proc_t *p;
24167c478bd9Sstevel@tonic-gate 	kthread_t *t;
24177c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
24187c478bd9Sstevel@tonic-gate 	int error;
24197c478bd9Sstevel@tonic-gate 	int i;
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LUSAGE);
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 	/*
24247c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
24257c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
24267c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
24277c478bd9Sstevel@tonic-gate 	 */
24287c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
24297c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
24307c478bd9Sstevel@tonic-gate 	if (p == NULL)
24317c478bd9Sstevel@tonic-gate 		return (ENOENT);
24327c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
24337c478bd9Sstevel@tonic-gate 	if ((nlwp = p->p_lwpcnt) == 0) {
24347c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24357c478bd9Sstevel@tonic-gate 		return (ENOENT);
24367c478bd9Sstevel@tonic-gate 	}
24377c478bd9Sstevel@tonic-gate 
24387c478bd9Sstevel@tonic-gate 	size = sizeof (prheader32_t) + (nlwp + 1) * LSPAN32(prusage32_t);
24397c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
24407c478bd9Sstevel@tonic-gate 		prunlock(pnp);
24417c478bd9Sstevel@tonic-gate 		return (0);
24427c478bd9Sstevel@tonic-gate 	}
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
24457c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
24467c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(size + sizeof (prhusage_t), KM_SLEEP);
24477c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
24487c478bd9Sstevel@tonic-gate 	/* p->p_lwpcnt can't change while process is locked */
24497c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == p->p_lwpcnt);
24507c478bd9Sstevel@tonic-gate 
24517c478bd9Sstevel@tonic-gate 	php = (prheader32_t *)(pup + 1);
24527c478bd9Sstevel@tonic-gate 	upup = (prusage32_t *)(php + 1);
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	php->pr_nent = nlwp + 1;
24557c478bd9Sstevel@tonic-gate 	php->pr_entsize = LSPAN32(prusage32_t);
24567c478bd9Sstevel@tonic-gate 
24577c478bd9Sstevel@tonic-gate 	curtime = gethrtime();
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 	/*
24607c478bd9Sstevel@tonic-gate 	 * First the summation over defunct lwps.
24617c478bd9Sstevel@tonic-gate 	 */
24627c478bd9Sstevel@tonic-gate 	pup->pr_count  = p->p_defunct;
24637c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = curtime;
24647c478bd9Sstevel@tonic-gate 	pup->pr_create = p->p_mstart;
24657c478bd9Sstevel@tonic-gate 	pup->pr_term   = p->p_mterm;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	pup->pr_rtime    = p->p_mlreal;
24687c478bd9Sstevel@tonic-gate 	pup->pr_utime    = p->p_acct[LMS_USER];
24697c478bd9Sstevel@tonic-gate 	pup->pr_stime    = p->p_acct[LMS_SYSTEM];
24707c478bd9Sstevel@tonic-gate 	pup->pr_ttime    = p->p_acct[LMS_TRAP];
24717c478bd9Sstevel@tonic-gate 	pup->pr_tftime   = p->p_acct[LMS_TFAULT];
24727c478bd9Sstevel@tonic-gate 	pup->pr_dftime   = p->p_acct[LMS_DFAULT];
24737c478bd9Sstevel@tonic-gate 	pup->pr_kftime   = p->p_acct[LMS_KFAULT];
24747c478bd9Sstevel@tonic-gate 	pup->pr_ltime    = p->p_acct[LMS_USER_LOCK];
24757c478bd9Sstevel@tonic-gate 	pup->pr_slptime  = p->p_acct[LMS_SLEEP];
24767c478bd9Sstevel@tonic-gate 	pup->pr_wtime    = p->p_acct[LMS_WAIT_CPU];
24777c478bd9Sstevel@tonic-gate 	pup->pr_stoptime = p->p_acct[LMS_STOPPED];
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	pup->pr_minf  = p->p_ru.minflt;
24807c478bd9Sstevel@tonic-gate 	pup->pr_majf  = p->p_ru.majflt;
24817c478bd9Sstevel@tonic-gate 	pup->pr_nswap = p->p_ru.nswap;
24827c478bd9Sstevel@tonic-gate 	pup->pr_inblk = p->p_ru.inblock;
24837c478bd9Sstevel@tonic-gate 	pup->pr_oublk = p->p_ru.oublock;
24847c478bd9Sstevel@tonic-gate 	pup->pr_msnd  = p->p_ru.msgsnd;
24857c478bd9Sstevel@tonic-gate 	pup->pr_mrcv  = p->p_ru.msgrcv;
24867c478bd9Sstevel@tonic-gate 	pup->pr_sigs  = p->p_ru.nsignals;
24877c478bd9Sstevel@tonic-gate 	pup->pr_vctx  = p->p_ru.nvcsw;
24887c478bd9Sstevel@tonic-gate 	pup->pr_ictx  = p->p_ru.nivcsw;
24897c478bd9Sstevel@tonic-gate 	pup->pr_sysc  = p->p_ru.sysc;
24907c478bd9Sstevel@tonic-gate 	pup->pr_ioch  = p->p_ru.ioch;
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	prcvtusage32(pup, upup);
24937c478bd9Sstevel@tonic-gate 
24947c478bd9Sstevel@tonic-gate 	/*
24957c478bd9Sstevel@tonic-gate 	 * Fill one prusage struct for each active lwp.
24967c478bd9Sstevel@tonic-gate 	 */
24977c478bd9Sstevel@tonic-gate 	for (ldp = p->p_lwpdir, i = 0; i < p->p_lwpdir_sz; i++, ldp++) {
24987c478bd9Sstevel@tonic-gate 		if (ldp->ld_entry == NULL ||
24997c478bd9Sstevel@tonic-gate 		    (t = ldp->ld_entry->le_thread) == NULL)
25007c478bd9Sstevel@tonic-gate 			continue;
25017c478bd9Sstevel@tonic-gate 		ASSERT(!(t->t_proc_flag & TP_LWPEXIT));
25027c478bd9Sstevel@tonic-gate 		ASSERT(nlwp > 0);
25037c478bd9Sstevel@tonic-gate 		--nlwp;
25047c478bd9Sstevel@tonic-gate 		upup = (prusage32_t *)
25057c478bd9Sstevel@tonic-gate 		    ((caddr_t)upup + LSPAN32(prusage32_t));
25067c478bd9Sstevel@tonic-gate 		prgetusage(t, pup);
25077c478bd9Sstevel@tonic-gate 		prcvtusage32(pup, upup);
25087c478bd9Sstevel@tonic-gate 	}
25097c478bd9Sstevel@tonic-gate 	ASSERT(nlwp == 0);
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate 	prunlock(pnp);
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	error = pr_uioread(php, size, uiop);
25147c478bd9Sstevel@tonic-gate 	kmem_free(pup, size + sizeof (prhusage_t));
25157c478bd9Sstevel@tonic-gate 	return (error);
25167c478bd9Sstevel@tonic-gate }
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate static int
pr_read_pagedata_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)251919ee9cd1SAndy Fiddaman pr_read_pagedata_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
25207c478bd9Sstevel@tonic-gate {
25217c478bd9Sstevel@tonic-gate 	proc_t *p;
25227c478bd9Sstevel@tonic-gate 	int error;
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PAGEDATA);
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
25277c478bd9Sstevel@tonic-gate 		return (error);
25287c478bd9Sstevel@tonic-gate 
25297c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
25307c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
25317c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25327c478bd9Sstevel@tonic-gate 		return (0);
25337c478bd9Sstevel@tonic-gate 	}
25347c478bd9Sstevel@tonic-gate 
25357c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
25367c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25377c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
25387c478bd9Sstevel@tonic-gate 	}
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
25417c478bd9Sstevel@tonic-gate 	error = prpdread32(p, pnp->pr_hatid, uiop);
25427c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	prunlock(pnp);
25457c478bd9Sstevel@tonic-gate 	return (error);
25467c478bd9Sstevel@tonic-gate }
25477c478bd9Sstevel@tonic-gate 
25487c478bd9Sstevel@tonic-gate static int
pr_read_opagedata_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)254919ee9cd1SAndy Fiddaman pr_read_opagedata_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
25507c478bd9Sstevel@tonic-gate {
25517c478bd9Sstevel@tonic-gate 	proc_t *p;
25527c478bd9Sstevel@tonic-gate 	struct as *as;
25537c478bd9Sstevel@tonic-gate 	int error;
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OPAGEDATA);
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
25587c478bd9Sstevel@tonic-gate 		return (error);
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
25617c478bd9Sstevel@tonic-gate 	as = p->p_as;
25627c478bd9Sstevel@tonic-gate 
25637c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || as == &kas) {
25647c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25657c478bd9Sstevel@tonic-gate 		return (0);
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 
25687c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
25697c478bd9Sstevel@tonic-gate 		prunlock(pnp);
25707c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
25717c478bd9Sstevel@tonic-gate 	}
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
25747c478bd9Sstevel@tonic-gate 	error = oprpdread32(as, pnp->pr_hatid, uiop);
25757c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 	prunlock(pnp);
25787c478bd9Sstevel@tonic-gate 	return (error);
25797c478bd9Sstevel@tonic-gate }
25807c478bd9Sstevel@tonic-gate 
25817c478bd9Sstevel@tonic-gate static int
pr_read_watch_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)258219ee9cd1SAndy Fiddaman pr_read_watch_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
25837c478bd9Sstevel@tonic-gate {
25847c478bd9Sstevel@tonic-gate 	proc_t *p;
25857c478bd9Sstevel@tonic-gate 	int error;
25867c478bd9Sstevel@tonic-gate 	prwatch32_t *Bpwp;
25877c478bd9Sstevel@tonic-gate 	size_t size;
25887c478bd9Sstevel@tonic-gate 	prwatch32_t *pwp;
25897c478bd9Sstevel@tonic-gate 	int nwarea;
25907c478bd9Sstevel@tonic-gate 	struct watched_area *pwarea;
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_WATCH);
25937c478bd9Sstevel@tonic-gate 
25947c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
25957c478bd9Sstevel@tonic-gate 		return (error);
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
25987c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
25997c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26007c478bd9Sstevel@tonic-gate 		return (EOVERFLOW);
26017c478bd9Sstevel@tonic-gate 	}
26027c478bd9Sstevel@tonic-gate 	nwarea = avl_numnodes(&p->p_warea);
26037c478bd9Sstevel@tonic-gate 	size = nwarea * sizeof (prwatch32_t);
26047c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
26057c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26067c478bd9Sstevel@tonic-gate 		return (0);
26077c478bd9Sstevel@tonic-gate 	}
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 	/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
26107c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
26117c478bd9Sstevel@tonic-gate 	Bpwp = pwp = kmem_zalloc(size, KM_SLEEP);
26127c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
26137c478bd9Sstevel@tonic-gate 	/* p->p_nwarea can't change while process is locked */
26147c478bd9Sstevel@tonic-gate 	ASSERT(nwarea == avl_numnodes(&p->p_warea));
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate 	/* gather the watched areas */
26177c478bd9Sstevel@tonic-gate 	for (pwarea = avl_first(&p->p_warea); pwarea != NULL;
26187c478bd9Sstevel@tonic-gate 	    pwarea = AVL_NEXT(&p->p_warea, pwarea), pwp++) {
26197c478bd9Sstevel@tonic-gate 		pwp->pr_vaddr = (caddr32_t)(uintptr_t)pwarea->wa_vaddr;
26207c478bd9Sstevel@tonic-gate 		pwp->pr_size = (size32_t)(pwarea->wa_eaddr - pwarea->wa_vaddr);
26217c478bd9Sstevel@tonic-gate 		pwp->pr_wflags = (int)pwarea->wa_flags;
26227c478bd9Sstevel@tonic-gate 	}
26237c478bd9Sstevel@tonic-gate 
26247c478bd9Sstevel@tonic-gate 	prunlock(pnp);
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	error = pr_uioread(Bpwp, size, uiop);
26277c478bd9Sstevel@tonic-gate 	kmem_free(Bpwp, size);
26287c478bd9Sstevel@tonic-gate 	return (error);
26297c478bd9Sstevel@tonic-gate }
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate static int
pr_read_lwpstatus_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)263219ee9cd1SAndy Fiddaman pr_read_lwpstatus_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
26337c478bd9Sstevel@tonic-gate {
26347c478bd9Sstevel@tonic-gate 	lwpstatus32_t *sp;
26357c478bd9Sstevel@tonic-gate 	proc_t *p;
26367c478bd9Sstevel@tonic-gate 	int error;
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSTATUS);
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	/*
26417c478bd9Sstevel@tonic-gate 	 * We kmem_alloc() the lwpstatus structure because
26427c478bd9Sstevel@tonic-gate 	 * it is so big it might blow the kernel stack.
26437c478bd9Sstevel@tonic-gate 	 */
26447c478bd9Sstevel@tonic-gate 	sp = kmem_alloc(sizeof (*sp), KM_SLEEP);
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
26477c478bd9Sstevel@tonic-gate 		goto out;
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 	/*
26507c478bd9Sstevel@tonic-gate 	 * A 32-bit process cannot get the status of a 64-bit process.
26517c478bd9Sstevel@tonic-gate 	 * The fields for the 64-bit quantities are not large enough.
26527c478bd9Sstevel@tonic-gate 	 */
26537c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
26547c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
26557c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26567c478bd9Sstevel@tonic-gate 		error = EOVERFLOW;
26577c478bd9Sstevel@tonic-gate 		goto out;
26587c478bd9Sstevel@tonic-gate 	}
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (*sp)) {
26617c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26627c478bd9Sstevel@tonic-gate 		goto out;
26637c478bd9Sstevel@tonic-gate 	}
26647c478bd9Sstevel@tonic-gate 
2665fa9e4066Sahrens 	prgetlwpstatus32(pnp->pr_common->prc_thread, sp, VTOZONE(PTOV(pnp)));
26667c478bd9Sstevel@tonic-gate 	prunlock(pnp);
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	error = pr_uioread(sp, sizeof (*sp), uiop);
26697c478bd9Sstevel@tonic-gate out:
26707c478bd9Sstevel@tonic-gate 	kmem_free(sp, sizeof (*sp));
26717c478bd9Sstevel@tonic-gate 	return (error);
26727c478bd9Sstevel@tonic-gate }
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate static int
pr_read_lwpsinfo_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)267519ee9cd1SAndy Fiddaman pr_read_lwpsinfo_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
26767c478bd9Sstevel@tonic-gate {
26777c478bd9Sstevel@tonic-gate 	lwpsinfo32_t lwpsinfo;
26787c478bd9Sstevel@tonic-gate 	proc_t *p;
26797c478bd9Sstevel@tonic-gate 	kthread_t *t;
26807c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPSINFO);
26837c478bd9Sstevel@tonic-gate 
26847c478bd9Sstevel@tonic-gate 	/*
26857c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
26867c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
26877c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
26887c478bd9Sstevel@tonic-gate 	 */
26897c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
26907c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
26917c478bd9Sstevel@tonic-gate 	if (p == NULL)
26927c478bd9Sstevel@tonic-gate 		return (ENOENT);
26937c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
26947c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_tslot == -1) {
26957c478bd9Sstevel@tonic-gate 		prunlock(pnp);
26967c478bd9Sstevel@tonic-gate 		return (ENOENT);
26977c478bd9Sstevel@tonic-gate 	}
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpsinfo)) {
27007c478bd9Sstevel@tonic-gate 		prunlock(pnp);
27017c478bd9Sstevel@tonic-gate 		return (0);
27027c478bd9Sstevel@tonic-gate 	}
27037c478bd9Sstevel@tonic-gate 
27047c478bd9Sstevel@tonic-gate 	if ((t = pnp->pr_common->prc_thread) != NULL)
27057c478bd9Sstevel@tonic-gate 		prgetlwpsinfo32(t, &lwpsinfo);
27067c478bd9Sstevel@tonic-gate 	else {
27077c478bd9Sstevel@tonic-gate 		lep = p->p_lwpdir[pnp->pr_common->prc_tslot].ld_entry;
27087c478bd9Sstevel@tonic-gate 		bzero(&lwpsinfo, sizeof (lwpsinfo));
27097c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_lwpid = lep->le_lwpid;
27107c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_state = SZOMB;
27117c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_sname = 'Z';
27127c478bd9Sstevel@tonic-gate 		lwpsinfo.pr_start.tv_sec = (time32_t)lep->le_start;
27137c478bd9Sstevel@tonic-gate 	}
27147c478bd9Sstevel@tonic-gate 	prunlock(pnp);
27157c478bd9Sstevel@tonic-gate 
27167c478bd9Sstevel@tonic-gate 	return (pr_uioread(&lwpsinfo, sizeof (lwpsinfo), uiop));
27177c478bd9Sstevel@tonic-gate }
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate static int
pr_read_lwpusage_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)272019ee9cd1SAndy Fiddaman pr_read_lwpusage_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate 	prhusage_t *pup;
27237c478bd9Sstevel@tonic-gate 	prusage32_t *upup;
27247c478bd9Sstevel@tonic-gate 	proc_t *p;
27257c478bd9Sstevel@tonic-gate 	int error;
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPUSAGE);
27287c478bd9Sstevel@tonic-gate 
27297c478bd9Sstevel@tonic-gate 	/* allocate now, before locking the process */
27307c478bd9Sstevel@tonic-gate 	pup = kmem_zalloc(sizeof (*pup), KM_SLEEP);
27317c478bd9Sstevel@tonic-gate 	upup = kmem_alloc(sizeof (*upup), KM_SLEEP);
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate 	/*
27347c478bd9Sstevel@tonic-gate 	 * We don't want the full treatment of prlock(pnp) here.
27357c478bd9Sstevel@tonic-gate 	 * This file is world-readable and never goes invalid.
27367c478bd9Sstevel@tonic-gate 	 * It doesn't matter if we are in the middle of an exec().
27377c478bd9Sstevel@tonic-gate 	 */
27387c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
27397c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
27407c478bd9Sstevel@tonic-gate 	if (p == NULL) {
27417c478bd9Sstevel@tonic-gate 		error = ENOENT;
27427c478bd9Sstevel@tonic-gate 		goto out;
27437c478bd9Sstevel@tonic-gate 	}
27447c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
27457c478bd9Sstevel@tonic-gate 	if (pnp->pr_common->prc_thread == NULL) {
27467c478bd9Sstevel@tonic-gate 		prunlock(pnp);
27477c478bd9Sstevel@tonic-gate 		error = ENOENT;
27487c478bd9Sstevel@tonic-gate 		goto out;
27497c478bd9Sstevel@tonic-gate 	}
27507c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (prusage32_t)) {
27517c478bd9Sstevel@tonic-gate 		prunlock(pnp);
27527c478bd9Sstevel@tonic-gate 		error = 0;
27537c478bd9Sstevel@tonic-gate 		goto out;
27547c478bd9Sstevel@tonic-gate 	}
27557c478bd9Sstevel@tonic-gate 
27567c478bd9Sstevel@tonic-gate 	pup->pr_tstamp = gethrtime();
27577c478bd9Sstevel@tonic-gate 	prgetusage(pnp->pr_common->prc_thread, pup);
27587c478bd9Sstevel@tonic-gate 
27597c478bd9Sstevel@tonic-gate 	prunlock(pnp);
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate 	prcvtusage32(pup, upup);
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 	error = pr_uioread(upup, sizeof (prusage32_t), uiop);
27647c478bd9Sstevel@tonic-gate out:
27657c478bd9Sstevel@tonic-gate 	kmem_free(pup, sizeof (*pup));
27667c478bd9Sstevel@tonic-gate 	kmem_free(upup, sizeof (*upup));
27677c478bd9Sstevel@tonic-gate 	return (error);
27687c478bd9Sstevel@tonic-gate }
27697c478bd9Sstevel@tonic-gate 
2770f971a346SBryan Cantrill static int
pr_read_spymaster_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)277119ee9cd1SAndy Fiddaman pr_read_spymaster_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
2772f971a346SBryan Cantrill {
2773f971a346SBryan Cantrill 	psinfo32_t psinfo;
2774f971a346SBryan Cantrill 	int error;
2775f971a346SBryan Cantrill 	klwp_t *lwp;
2776f971a346SBryan Cantrill 
2777f971a346SBryan Cantrill 	ASSERT(pnp->pr_type == PR_SPYMASTER);
2778f971a346SBryan Cantrill 
2779f971a346SBryan Cantrill 	if ((error = prlock(pnp, ZNO)) != 0)
2780f971a346SBryan Cantrill 		return (error);
2781f971a346SBryan Cantrill 
2782614f1d63SJerry Jelinek 	if (pnp->pr_common->prc_thread == NULL) {
2783614f1d63SJerry Jelinek 		prunlock(pnp);
2784614f1d63SJerry Jelinek 		return (0);
2785614f1d63SJerry Jelinek 	}
2786614f1d63SJerry Jelinek 
2787f971a346SBryan Cantrill 	lwp = pnp->pr_common->prc_thread->t_lwp;
2788f971a346SBryan Cantrill 
2789f971a346SBryan Cantrill 	if (lwp->lwp_spymaster == NULL) {
2790f971a346SBryan Cantrill 		prunlock(pnp);
2791f971a346SBryan Cantrill 		return (0);
2792f971a346SBryan Cantrill 	}
2793f971a346SBryan Cantrill 
2794f971a346SBryan Cantrill 	psinfo_kto32(lwp->lwp_spymaster, &psinfo);
2795f971a346SBryan Cantrill 	prunlock(pnp);
2796f971a346SBryan Cantrill 
2797f971a346SBryan Cantrill 	return (pr_uioread(&psinfo, sizeof (psinfo), uiop));
2798f971a346SBryan Cantrill }
2799f971a346SBryan Cantrill 
28007c478bd9Sstevel@tonic-gate #if defined(__sparc)
28017c478bd9Sstevel@tonic-gate static int
pr_read_gwindows_32(prnode_t * pnp,uio_t * uiop,cred_t * cr)280219ee9cd1SAndy Fiddaman pr_read_gwindows_32(prnode_t *pnp, uio_t *uiop, cred_t *cr)
28037c478bd9Sstevel@tonic-gate {
28047c478bd9Sstevel@tonic-gate 	proc_t *p;
28057c478bd9Sstevel@tonic-gate 	kthread_t *t;
28067c478bd9Sstevel@tonic-gate 	gwindows32_t *gwp;
28077c478bd9Sstevel@tonic-gate 	int error;
28087c478bd9Sstevel@tonic-gate 	size_t size;
28097c478bd9Sstevel@tonic-gate 
28107c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_GWINDOWS);
28117c478bd9Sstevel@tonic-gate 
28127c478bd9Sstevel@tonic-gate 	gwp = kmem_zalloc(sizeof (gwindows32_t), KM_SLEEP);
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
28157c478bd9Sstevel@tonic-gate 		goto out;
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
28187c478bd9Sstevel@tonic-gate 	t = pnp->pr_common->prc_thread;
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	if (PROCESS_NOT_32BIT(p)) {
28217c478bd9Sstevel@tonic-gate 		prunlock(pnp);
28227c478bd9Sstevel@tonic-gate 		error = EOVERFLOW;
28237c478bd9Sstevel@tonic-gate 		goto out;
28247c478bd9Sstevel@tonic-gate 	}
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 	/*
28277c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock while touching the stack.
28287c478bd9Sstevel@tonic-gate 	 * The P_PR_LOCK flag prevents the lwp from
28297c478bd9Sstevel@tonic-gate 	 * disappearing while we do this.
28307c478bd9Sstevel@tonic-gate 	 */
28317c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
28327c478bd9Sstevel@tonic-gate 	if ((size = prnwindows(ttolwp(t))) != 0)
28337c478bd9Sstevel@tonic-gate 		size = sizeof (gwindows32_t) -
28347c478bd9Sstevel@tonic-gate 		    (SPARC_MAXREGWINDOW - size) * sizeof (struct rwindow32);
28357c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= size) {
28367c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
28377c478bd9Sstevel@tonic-gate 		prunlock(pnp);
28387c478bd9Sstevel@tonic-gate 		goto out;
28397c478bd9Sstevel@tonic-gate 	}
28407c478bd9Sstevel@tonic-gate 	prgetwindows32(ttolwp(t), gwp);
28417c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
28427c478bd9Sstevel@tonic-gate 	prunlock(pnp);
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 	error = pr_uioread(gwp, size, uiop);
28457c478bd9Sstevel@tonic-gate out:
28467c478bd9Sstevel@tonic-gate 	kmem_free(gwp, sizeof (gwindows32_t));
28477c478bd9Sstevel@tonic-gate 	return (error);
28487c478bd9Sstevel@tonic-gate }
28497c478bd9Sstevel@tonic-gate #endif	/* __sparc */
28507c478bd9Sstevel@tonic-gate 
28517c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32_IMPL */
28527c478bd9Sstevel@tonic-gate 
28537c478bd9Sstevel@tonic-gate /* ARGSUSED */
28547c478bd9Sstevel@tonic-gate static int
prread(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)28557c478bd9Sstevel@tonic-gate prread(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
28567c478bd9Sstevel@tonic-gate {
28577c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
28627c478bd9Sstevel@tonic-gate 	/*
28637c478bd9Sstevel@tonic-gate 	 * What is read from the /proc files depends on the data
28647c478bd9Sstevel@tonic-gate 	 * model of the caller.  An LP64 process will see LP64
28657c478bd9Sstevel@tonic-gate 	 * data.  An ILP32 process will see ILP32 data.
28667c478bd9Sstevel@tonic-gate 	 */
28677c478bd9Sstevel@tonic-gate 	if (curproc->p_model == DATAMODEL_LP64)
286819ee9cd1SAndy Fiddaman 		return (pr_read_function[pnp->pr_type](pnp, uiop, cr));
28697c478bd9Sstevel@tonic-gate 	else
287019ee9cd1SAndy Fiddaman 		return (pr_read_function_32[pnp->pr_type](pnp, uiop, cr));
28717c478bd9Sstevel@tonic-gate #else
287219ee9cd1SAndy Fiddaman 	return (pr_read_function[pnp->pr_type](pnp, uiop, cr));
28737c478bd9Sstevel@tonic-gate #endif
28747c478bd9Sstevel@tonic-gate }
28757c478bd9Sstevel@tonic-gate 
2876ab618543SJohn Levon /* Note we intentionally don't handle partial writes/updates. */
2877ab618543SJohn Levon static int
pr_write_lwpname(prnode_t * pnp,uio_t * uiop)2878ab618543SJohn Levon pr_write_lwpname(prnode_t *pnp, uio_t *uiop)
2879ab618543SJohn Levon {
2880ab618543SJohn Levon 	kthread_t *t = NULL;
2881ab618543SJohn Levon 	char *lwpname;
2882ab618543SJohn Levon 	int error;
2883ab618543SJohn Levon 
2884ab618543SJohn Levon 	lwpname = kmem_zalloc(THREAD_NAME_MAX, KM_SLEEP);
2885ab618543SJohn Levon 
2886ab618543SJohn Levon 	if ((error = uiomove(lwpname, THREAD_NAME_MAX, UIO_WRITE, uiop)) != 0) {
2887ab618543SJohn Levon 		kmem_free(lwpname, THREAD_NAME_MAX);
2888ab618543SJohn Levon 		return (error);
2889ab618543SJohn Levon 	}
2890ab618543SJohn Levon 
2891ab618543SJohn Levon 	/* Somebody tried to write too long a thread name... */
2892ab618543SJohn Levon 	if (lwpname[THREAD_NAME_MAX - 1] != '\0' || uiop->uio_resid > 0) {
2893ab618543SJohn Levon 		kmem_free(lwpname, THREAD_NAME_MAX);
2894ab618543SJohn Levon 		return (EIO);
2895ab618543SJohn Levon 	}
2896ab618543SJohn Levon 
2897ab618543SJohn Levon 	VERIFY3U(lwpname[THREAD_NAME_MAX - 1], ==, '\0');
2898ab618543SJohn Levon 
2899ab618543SJohn Levon 	for (size_t i = 0; lwpname[i] != '\0'; i++) {
2900ab618543SJohn Levon 		if (!ISPRINT(lwpname[i])) {
2901ab618543SJohn Levon 			kmem_free(lwpname, THREAD_NAME_MAX);
2902ab618543SJohn Levon 			return (EINVAL);
2903ab618543SJohn Levon 		}
2904ab618543SJohn Levon 	}
2905ab618543SJohn Levon 
2906ab618543SJohn Levon 	/* Equivalent of thread_setname(), but with the ZNO magic. */
2907ab618543SJohn Levon 	if ((error = prlock(pnp, ZNO)) != 0) {
2908ab618543SJohn Levon 		kmem_free(lwpname, THREAD_NAME_MAX);
2909ab618543SJohn Levon 		return (error);
2910ab618543SJohn Levon 	}
2911ab618543SJohn Levon 
2912ab618543SJohn Levon 	t = pnp->pr_common->prc_thread;
2913ab618543SJohn Levon 	if (t->t_name == NULL) {
2914ab618543SJohn Levon 		t->t_name = lwpname;
2915ab618543SJohn Levon 	} else {
2916ab618543SJohn Levon 		(void) strlcpy(t->t_name, lwpname, THREAD_NAME_MAX);
2917ab618543SJohn Levon 		kmem_free(lwpname, THREAD_NAME_MAX);
2918ab618543SJohn Levon 	}
2919ab618543SJohn Levon 
2920ab618543SJohn Levon 	prunlock(pnp);
2921ab618543SJohn Levon 	return (0);
2922ab618543SJohn Levon }
2923ab618543SJohn Levon 
29247c478bd9Sstevel@tonic-gate /* ARGSUSED */
29257c478bd9Sstevel@tonic-gate static int
prwrite(vnode_t * vp,uio_t * uiop,int ioflag,cred_t * cr,caller_context_t * ct)29267c478bd9Sstevel@tonic-gate prwrite(vnode_t *vp, uio_t *uiop, int ioflag, cred_t *cr, caller_context_t *ct)
29277c478bd9Sstevel@tonic-gate {
29287c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
29297c478bd9Sstevel@tonic-gate 	int old = 0;
29307c478bd9Sstevel@tonic-gate 	int error;
29317c478bd9Sstevel@tonic-gate 	ssize_t resid;
29327c478bd9Sstevel@tonic-gate 
29337c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate 	/*
29367c478bd9Sstevel@tonic-gate 	 * Only a handful of /proc files are writable, enumerate them here.
29377c478bd9Sstevel@tonic-gate 	 */
29387c478bd9Sstevel@tonic-gate 	switch (pnp->pr_type) {
29397c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:		/* directory write()s: visceral revulsion. */
29407c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_pidfile != NULL);
29417c478bd9Sstevel@tonic-gate 		/* use the underlying PR_PIDFILE to write the process */
29427c478bd9Sstevel@tonic-gate 		vp = pnp->pr_pidfile;
29437c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
29447c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_type == PR_PIDFILE);
29457c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
29467c478bd9Sstevel@tonic-gate 	case PR_PIDFILE:
29477c478bd9Sstevel@tonic-gate 	case PR_LWPIDFILE:
29487c478bd9Sstevel@tonic-gate 		old = 1;
29497c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
29507c478bd9Sstevel@tonic-gate 	case PR_AS:
29517c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp, ZNO)) == 0) {
29527c478bd9Sstevel@tonic-gate 			proc_t *p = pnp->pr_common->prc_proc;
29537c478bd9Sstevel@tonic-gate 			struct as *as = p->p_as;
29547c478bd9Sstevel@tonic-gate 
29557c478bd9Sstevel@tonic-gate 			if ((p->p_flag & SSYS) || as == &kas) {
29567c478bd9Sstevel@tonic-gate 				/*
29577c478bd9Sstevel@tonic-gate 				 * /proc I/O cannot be done to a system process.
29587c478bd9Sstevel@tonic-gate 				 */
29597c478bd9Sstevel@tonic-gate 				error = EIO;
29607c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
29617c478bd9Sstevel@tonic-gate 			} else if (curproc->p_model == DATAMODEL_ILP32 &&
29627c478bd9Sstevel@tonic-gate 			    PROCESS_NOT_32BIT(p)) {
29637c478bd9Sstevel@tonic-gate 				error = EOVERFLOW;
29647c478bd9Sstevel@tonic-gate #endif
29657c478bd9Sstevel@tonic-gate 			} else {
29667c478bd9Sstevel@tonic-gate 				/*
29677c478bd9Sstevel@tonic-gate 				 * See comments above (pr_read_pidfile)
29687c478bd9Sstevel@tonic-gate 				 * about this locking dance.
29697c478bd9Sstevel@tonic-gate 				 */
29707c478bd9Sstevel@tonic-gate 				mutex_exit(&p->p_lock);
29717c478bd9Sstevel@tonic-gate 				error = prusrio(p, UIO_WRITE, uiop, old);
29727c478bd9Sstevel@tonic-gate 				mutex_enter(&p->p_lock);
29737c478bd9Sstevel@tonic-gate 			}
29747c478bd9Sstevel@tonic-gate 			prunlock(pnp);
29757c478bd9Sstevel@tonic-gate 		}
29767c478bd9Sstevel@tonic-gate 		return (error);
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	case PR_CTL:
29797c478bd9Sstevel@tonic-gate 	case PR_LWPCTL:
29807c478bd9Sstevel@tonic-gate 		resid = uiop->uio_resid;
29817c478bd9Sstevel@tonic-gate 		/*
29827c478bd9Sstevel@tonic-gate 		 * Perform the action on the control file
29837c478bd9Sstevel@tonic-gate 		 * by passing curthreads credentials
29847c478bd9Sstevel@tonic-gate 		 * and not target process's credentials.
29857c478bd9Sstevel@tonic-gate 		 */
29867c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
29877c478bd9Sstevel@tonic-gate 		if (curproc->p_model == DATAMODEL_ILP32)
29887c478bd9Sstevel@tonic-gate 			error = prwritectl32(vp, uiop, CRED());
29897c478bd9Sstevel@tonic-gate 		else
29907c478bd9Sstevel@tonic-gate 			error = prwritectl(vp, uiop, CRED());
29917c478bd9Sstevel@tonic-gate #else
29927c478bd9Sstevel@tonic-gate 		error = prwritectl(vp, uiop, CRED());
29937c478bd9Sstevel@tonic-gate #endif
29947c478bd9Sstevel@tonic-gate 		/*
29957c478bd9Sstevel@tonic-gate 		 * This hack makes sure that the EINTR is passed
29967c478bd9Sstevel@tonic-gate 		 * all the way back to the caller's write() call.
29977c478bd9Sstevel@tonic-gate 		 */
29987c478bd9Sstevel@tonic-gate 		if (error == EINTR)
29997c478bd9Sstevel@tonic-gate 			uiop->uio_resid = resid;
30007c478bd9Sstevel@tonic-gate 		return (error);
30017c478bd9Sstevel@tonic-gate 
3002ab618543SJohn Levon 	case PR_LWPNAME:
3003ab618543SJohn Levon 		return (pr_write_lwpname(pnp, uiop));
3004ab618543SJohn Levon 
30057c478bd9Sstevel@tonic-gate 	default:
30067c478bd9Sstevel@tonic-gate 		return ((vp->v_type == VDIR)? EISDIR : EBADF);
30077c478bd9Sstevel@tonic-gate 	}
30087c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
30097c478bd9Sstevel@tonic-gate }
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate static int
prgetattr(vnode_t * vp,vattr_t * vap,int flags,cred_t * cr,caller_context_t * ct)3012da6c28aaSamw prgetattr(vnode_t *vp, vattr_t *vap, int flags, cred_t *cr,
3013da6c28aaSamw     caller_context_t *ct)
30147c478bd9Sstevel@tonic-gate {
30157c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
30167c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
30177c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
30187c478bd9Sstevel@tonic-gate 	proc_t *p;
30197c478bd9Sstevel@tonic-gate 	struct as *as;
30207c478bd9Sstevel@tonic-gate 	int error;
30217c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
30227c478bd9Sstevel@tonic-gate 	timestruc_t now;
30237c478bd9Sstevel@tonic-gate 	extern uint_t nproc;
30247c478bd9Sstevel@tonic-gate 	int ngroups;
3025eb9dbf0cSRoger A. Faulkner 	int nsig;
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	/*
30287c478bd9Sstevel@tonic-gate 	 * This ugly bit of code allows us to keep both versions of this
30297c478bd9Sstevel@tonic-gate 	 * function from the same source.
30307c478bd9Sstevel@tonic-gate 	 */
30317c478bd9Sstevel@tonic-gate #ifdef _LP64
30327c478bd9Sstevel@tonic-gate 	int iam32bit = (curproc->p_model == DATAMODEL_ILP32);
30337c478bd9Sstevel@tonic-gate #define	PR_OBJSIZE(obj32, obj64)	\
30347c478bd9Sstevel@tonic-gate 	(iam32bit ? sizeof (obj32) : sizeof (obj64))
30357c478bd9Sstevel@tonic-gate #define	PR_OBJSPAN(obj32, obj64)	\
30367c478bd9Sstevel@tonic-gate 	(iam32bit ? LSPAN32(obj32) : LSPAN(obj64))
30377c478bd9Sstevel@tonic-gate #else
30387c478bd9Sstevel@tonic-gate #define	PR_OBJSIZE(obj32, obj64)	\
30397c478bd9Sstevel@tonic-gate 	(sizeof (obj64))
30407c478bd9Sstevel@tonic-gate #define	PR_OBJSPAN(obj32, obj64)	\
30417c478bd9Sstevel@tonic-gate 	(LSPAN(obj64))
30427c478bd9Sstevel@tonic-gate #endif
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 	/*
30457c478bd9Sstevel@tonic-gate 	 * Return all the attributes.  Should be refined
30467c478bd9Sstevel@tonic-gate 	 * so that it returns only those asked for.
30477c478bd9Sstevel@tonic-gate 	 * Most of this is complete fakery anyway.
30487c478bd9Sstevel@tonic-gate 	 */
30497c478bd9Sstevel@tonic-gate 
30507c478bd9Sstevel@tonic-gate 	/*
30517c478bd9Sstevel@tonic-gate 	 * For files in the /proc/<pid>/object directory,
30527c478bd9Sstevel@tonic-gate 	 * return the attributes of the underlying object.
30537c478bd9Sstevel@tonic-gate 	 * For files in the /proc/<pid>/fd directory,
30547c478bd9Sstevel@tonic-gate 	 * return the attributes of the underlying file, but
30557c478bd9Sstevel@tonic-gate 	 * make it look inaccessible if it is not a regular file.
30567c478bd9Sstevel@tonic-gate 	 * Make directories look like symlinks.
30577c478bd9Sstevel@tonic-gate 	 */
30587c478bd9Sstevel@tonic-gate 	switch (type) {
30597c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
30607c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
30617c478bd9Sstevel@tonic-gate 		if (!(flags & ATTR_REAL))
30627c478bd9Sstevel@tonic-gate 			break;
30637c478bd9Sstevel@tonic-gate 		/* restrict full knowledge of the attributes to owner or root */
3064da6c28aaSamw 		if ((error = praccess(vp, 0, 0, cr, ct)) != 0)
30657c478bd9Sstevel@tonic-gate 			return (error);
30667c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
30677c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
30687c478bd9Sstevel@tonic-gate 	case PR_FD:
30697c478bd9Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
3070da6c28aaSamw 		error = VOP_GETATTR(rvp, vap, flags, cr, ct);
30717c478bd9Sstevel@tonic-gate 		if (error)
30727c478bd9Sstevel@tonic-gate 			return (error);
30737c478bd9Sstevel@tonic-gate 		if (type == PR_FD) {
30747c478bd9Sstevel@tonic-gate 			if (rvp->v_type != VREG && rvp->v_type != VDIR)
30757c478bd9Sstevel@tonic-gate 				vap->va_mode = 0;
30767c478bd9Sstevel@tonic-gate 			else
30777c478bd9Sstevel@tonic-gate 				vap->va_mode &= pnp->pr_mode;
30787c478bd9Sstevel@tonic-gate 		}
30797c478bd9Sstevel@tonic-gate 		if (type == PR_OBJECT)
30807c478bd9Sstevel@tonic-gate 			vap->va_mode &= 07555;
30817c478bd9Sstevel@tonic-gate 		if (rvp->v_type == VDIR && !(flags & ATTR_REAL)) {
30827c478bd9Sstevel@tonic-gate 			vap->va_type = VLNK;
30837c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
30847c478bd9Sstevel@tonic-gate 			vap->va_nlink = 1;
30857c478bd9Sstevel@tonic-gate 		}
30867c478bd9Sstevel@tonic-gate 		return (0);
30877c478bd9Sstevel@tonic-gate 	default:
30887c478bd9Sstevel@tonic-gate 		break;
30897c478bd9Sstevel@tonic-gate 	}
30907c478bd9Sstevel@tonic-gate 
30917c478bd9Sstevel@tonic-gate 	bzero(vap, sizeof (*vap));
30927c478bd9Sstevel@tonic-gate 	/*
30937c478bd9Sstevel@tonic-gate 	 * Large Files: Internally proc now uses VPROC to indicate
30947c478bd9Sstevel@tonic-gate 	 * a proc file. Since we have been returning VREG through
30957c478bd9Sstevel@tonic-gate 	 * VOP_GETATTR() until now, we continue to do this so as
30967c478bd9Sstevel@tonic-gate 	 * not to break apps depending on this return value.
30977c478bd9Sstevel@tonic-gate 	 */
30987c478bd9Sstevel@tonic-gate 	vap->va_type = (vp->v_type == VPROC) ? VREG : vp->v_type;
30997c478bd9Sstevel@tonic-gate 	vap->va_mode = pnp->pr_mode;
31007c478bd9Sstevel@tonic-gate 	vap->va_fsid = vp->v_vfsp->vfs_dev;
31017c478bd9Sstevel@tonic-gate 	vap->va_blksize = DEV_BSIZE;
31027c478bd9Sstevel@tonic-gate 	vap->va_rdev = 0;
31037c478bd9Sstevel@tonic-gate 	vap->va_seq = 0;
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR) {
31067c478bd9Sstevel@tonic-gate 		vap->va_uid = 0;
31077c478bd9Sstevel@tonic-gate 		vap->va_gid = 0;
31087c478bd9Sstevel@tonic-gate 		vap->va_nlink = nproc + 2;
31097c478bd9Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)PRROOTINO;
31107c478bd9Sstevel@tonic-gate 		gethrestime(&now);
31117c478bd9Sstevel@tonic-gate 		vap->va_atime = vap->va_mtime = vap->va_ctime = now;
31127c478bd9Sstevel@tonic-gate 		vap->va_size = (v.v_proc + 2) * PRSDSIZE;
31137c478bd9Sstevel@tonic-gate 		vap->va_nblocks = btod(vap->va_size);
31147c478bd9Sstevel@tonic-gate 		return (0);
31157c478bd9Sstevel@tonic-gate 	}
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	/*
31187c478bd9Sstevel@tonic-gate 	 * /proc/<pid>/self is a symbolic link, and has no prcommon member
31197c478bd9Sstevel@tonic-gate 	 */
31207c478bd9Sstevel@tonic-gate 	if (type == PR_SELF) {
31217c478bd9Sstevel@tonic-gate 		vap->va_uid = crgetruid(CRED());
31227c478bd9Sstevel@tonic-gate 		vap->va_gid = crgetrgid(CRED());
31237c478bd9Sstevel@tonic-gate 		vap->va_nodeid = (ino64_t)PR_SELF;
31247c478bd9Sstevel@tonic-gate 		gethrestime(&now);
31257c478bd9Sstevel@tonic-gate 		vap->va_atime = vap->va_mtime = vap->va_ctime = now;
31267c478bd9Sstevel@tonic-gate 		vap->va_nlink = 1;
31277c478bd9Sstevel@tonic-gate 		vap->va_type = VLNK;
31287c478bd9Sstevel@tonic-gate 		vap->va_size = 0;
31297c478bd9Sstevel@tonic-gate 		return (0);
31307c478bd9Sstevel@tonic-gate 	}
31317c478bd9Sstevel@tonic-gate 
3132da29c6a3SDan McDonald 	/* A subset of prlock(pnp...) */
31337c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
31347c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
31357c478bd9Sstevel@tonic-gate 	if (p == NULL)
31367c478bd9Sstevel@tonic-gate 		return (ENOENT);
31377c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;
31387c478bd9Sstevel@tonic-gate 
3139da29c6a3SDan McDonald 	/*
3140da29c6a3SDan McDonald 	 * Because we're performing a subset of prlock() inline here, we must
3141da29c6a3SDan McDonald 	 * follow prlock's semantics when encountering a zombie process
3142da29c6a3SDan McDonald 	 * (PRC_DESTROY flag is set) or an exiting process (SEXITING flag is
3143da29c6a3SDan McDonald 	 * set). Those semantics indicate acting as if the process is no
3144da29c6a3SDan McDonald 	 * longer there (return ENOENT).
3145da29c6a3SDan McDonald 	 *
3146da29c6a3SDan McDonald 	 * If we chose to proceed here regardless, we may encounter issues
3147da29c6a3SDan McDonald 	 * when we drop the p_lock (see PR_OBJECTDIR, PR_PATHDIR, PR_*MAP,
3148da29c6a3SDan McDonald 	 * PR_LDT, and PR_*PAGEDATA below). A process-cleanup which was
3149da29c6a3SDan McDonald 	 * blocked on p_lock may ignore the P_PR_LOCK flag we set above, since
3150da29c6a3SDan McDonald 	 * it set one of PRC_DESTROY or SEXITING. If the process then gets
3151da29c6a3SDan McDonald 	 * destroyed our "p" will be useless, as will its p_lock.
3152da29c6a3SDan McDonald 	 *
3153da29c6a3SDan McDonald 	 * It may be desirable to move this check to only places further down
3154da29c6a3SDan McDonald 	 * prior to actual droppages of p->p_lock, but for now, we're playing
3155da29c6a3SDan McDonald 	 * it safe and checking here immediately, like prlock() does..
3156da29c6a3SDan McDonald 	 */
3157da29c6a3SDan McDonald 	if (((pcp->prc_flags & PRC_DESTROY) || (p->p_flag & SEXITING))) {
3158da29c6a3SDan McDonald 		prunlock(pnp);
3159da29c6a3SDan McDonald 		return (ENOENT);
3160da29c6a3SDan McDonald 	}
3161da29c6a3SDan McDonald 
31627c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_crlock);
31637c478bd9Sstevel@tonic-gate 	vap->va_uid = crgetruid(p->p_cred);
31647c478bd9Sstevel@tonic-gate 	vap->va_gid = crgetrgid(p->p_cred);
31657c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_crlock);
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 	vap->va_nlink = 1;
31687c478bd9Sstevel@tonic-gate 	vap->va_nodeid = pnp->pr_ino? pnp->pr_ino :
31697c478bd9Sstevel@tonic-gate 	    pmkino(pcp->prc_tslot, pcp->prc_slot, pnp->pr_type);
31707c478bd9Sstevel@tonic-gate 	if ((pcp->prc_flags & PRC_LWP) && pcp->prc_tslot != -1) {
31717c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
31727c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_sec =
31737c478bd9Sstevel@tonic-gate 		    p->p_lwpdir[pcp->prc_tslot].ld_entry->le_start;
31747c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec =
31757c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_nsec = 0;
31767c478bd9Sstevel@tonic-gate 	} else {
31777c478bd9Sstevel@tonic-gate 		user_t *up = PTOU(p);
31787c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_sec = vap->va_mtime.tv_sec =
31797c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_sec = up->u_start.tv_sec;
31807c478bd9Sstevel@tonic-gate 		vap->va_atime.tv_nsec = vap->va_mtime.tv_nsec =
31817c478bd9Sstevel@tonic-gate 		    vap->va_ctime.tv_nsec = up->u_start.tv_nsec;
31827c478bd9Sstevel@tonic-gate 	}
31837c478bd9Sstevel@tonic-gate 
31847c478bd9Sstevel@tonic-gate 	switch (type) {
31857c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:
31867c478bd9Sstevel@tonic-gate 		/* va_nlink: count 'lwp', 'object' and 'fd' directory links */
31877c478bd9Sstevel@tonic-gate 		vap->va_nlink = 5;
31887c478bd9Sstevel@tonic-gate 		vap->va_size = sizeof (piddir);
31897c478bd9Sstevel@tonic-gate 		break;
31907c478bd9Sstevel@tonic-gate 	case PR_OBJECTDIR:
31917c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
31927c478bd9Sstevel@tonic-gate 			vap->va_size = 2 * PRSDSIZE;
31937c478bd9Sstevel@tonic-gate 		else {
31947c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3195dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
31967c478bd9Sstevel@tonic-gate 			if (as->a_updatedir)
31977c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
31987c478bd9Sstevel@tonic-gate 			vap->va_size = (as->a_sizedir + 2) * PRSDSIZE;
3199dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
32007c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
32017c478bd9Sstevel@tonic-gate 		}
32027c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
32037c478bd9Sstevel@tonic-gate 		break;
32047c478bd9Sstevel@tonic-gate 	case PR_PATHDIR:
32057c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
32067c478bd9Sstevel@tonic-gate 			vap->va_size = (P_FINFO(p)->fi_nfiles + 4) * PRSDSIZE;
32077c478bd9Sstevel@tonic-gate 		else {
32087c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3209dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
32107c478bd9Sstevel@tonic-gate 			if (as->a_updatedir)
32117c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
32127c478bd9Sstevel@tonic-gate 			vap->va_size = (as->a_sizedir + 4 +
32137c478bd9Sstevel@tonic-gate 			    P_FINFO(p)->fi_nfiles) * PRSDSIZE;
3214dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
32157c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
32167c478bd9Sstevel@tonic-gate 		}
32177c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
32187c478bd9Sstevel@tonic-gate 		break;
32197c478bd9Sstevel@tonic-gate 	case PR_PATH:
32207c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
32217c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
32227c478bd9Sstevel@tonic-gate 	case PR_CT:
32237c478bd9Sstevel@tonic-gate 		vap->va_type = VLNK;
32247c478bd9Sstevel@tonic-gate 		vap->va_size = 0;
32257c478bd9Sstevel@tonic-gate 		break;
32267c478bd9Sstevel@tonic-gate 	case PR_FDDIR:
3227a02120c4SAndy Fiddaman 	case PR_FDINFODIR:
32287c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
32297c478bd9Sstevel@tonic-gate 		vap->va_size = (P_FINFO(p)->fi_nfiles + 2) * PRSDSIZE;
32307c478bd9Sstevel@tonic-gate 		break;
3231a02120c4SAndy Fiddaman 	case PR_FDINFO: {
3232a02120c4SAndy Fiddaman 		file_t *fp;
3233a02120c4SAndy Fiddaman 		int fd = pnp->pr_index;
3234a02120c4SAndy Fiddaman 
3235a02120c4SAndy Fiddaman 		fp = pr_getf(p, fd, NULL);
3236a02120c4SAndy Fiddaman 		if (fp == NULL) {
3237a02120c4SAndy Fiddaman 			prunlock(pnp);
3238a02120c4SAndy Fiddaman 			return (ENOENT);
3239a02120c4SAndy Fiddaman 		}
3240a02120c4SAndy Fiddaman 		prunlock(pnp);
3241da29c6a3SDan McDonald 		vap->va_size = prgetfdinfosize(p, fp->f_vnode, cr);
3242a02120c4SAndy Fiddaman 		vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
324337e2cd25SPatrick Mooney 		pr_releasef(fp);
3244a02120c4SAndy Fiddaman 		return (0);
3245a02120c4SAndy Fiddaman 	}
32467c478bd9Sstevel@tonic-gate 	case PR_LWPDIR:
32477c478bd9Sstevel@tonic-gate 		/*
32487c478bd9Sstevel@tonic-gate 		 * va_nlink: count each lwp as a directory link.
32497c478bd9Sstevel@tonic-gate 		 * va_size: size of p_lwpdir + 2
32507c478bd9Sstevel@tonic-gate 		 */
32517c478bd9Sstevel@tonic-gate 		vap->va_nlink = p->p_lwpcnt + p->p_zombcnt + 2;
32527c478bd9Sstevel@tonic-gate 		vap->va_size = (p->p_lwpdir_sz + 2) * PRSDSIZE;
32537c478bd9Sstevel@tonic-gate 		break;
32547c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
32557c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
32567c478bd9Sstevel@tonic-gate 		vap->va_size = sizeof (lwpiddir);
32577c478bd9Sstevel@tonic-gate 		break;
32587c478bd9Sstevel@tonic-gate 	case PR_CTDIR:
32597c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
32607c478bd9Sstevel@tonic-gate 		vap->va_size = (avl_numnodes(&p->p_ct_held) + 2) * PRSDSIZE;
32617c478bd9Sstevel@tonic-gate 		break;
32627c478bd9Sstevel@tonic-gate 	case PR_TMPLDIR:
32637c478bd9Sstevel@tonic-gate 		vap->va_nlink = 2;
32647c478bd9Sstevel@tonic-gate 		vap->va_size = (ct_ntypes + 2) * PRSDSIZE;
32657c478bd9Sstevel@tonic-gate 		break;
32667c478bd9Sstevel@tonic-gate 	case PR_AS:
32677c478bd9Sstevel@tonic-gate 	case PR_PIDFILE:
32687c478bd9Sstevel@tonic-gate 	case PR_LWPIDFILE:
32697c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
32707c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
327140688216SSudheer A 		else
327240688216SSudheer A 			vap->va_size = as->a_resvsize;
32737c478bd9Sstevel@tonic-gate 		break;
32747c478bd9Sstevel@tonic-gate 	case PR_STATUS:
32757c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(pstatus32_t, pstatus_t);
32767c478bd9Sstevel@tonic-gate 		break;
32777c478bd9Sstevel@tonic-gate 	case PR_LSTATUS:
32787c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
32797c478bd9Sstevel@tonic-gate 		    p->p_lwpcnt * PR_OBJSPAN(lwpstatus32_t, lwpstatus_t);
32807c478bd9Sstevel@tonic-gate 		break;
32817c478bd9Sstevel@tonic-gate 	case PR_PSINFO:
32827c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(psinfo32_t, psinfo_t);
32837c478bd9Sstevel@tonic-gate 		break;
32847c478bd9Sstevel@tonic-gate 	case PR_LPSINFO:
32857c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
32867c478bd9Sstevel@tonic-gate 		    (p->p_lwpcnt + p->p_zombcnt) *
32877c478bd9Sstevel@tonic-gate 		    PR_OBJSPAN(lwpsinfo32_t, lwpsinfo_t);
32887c478bd9Sstevel@tonic-gate 		break;
32897c478bd9Sstevel@tonic-gate 	case PR_MAP:
32907c478bd9Sstevel@tonic-gate 	case PR_RMAP:
32917c478bd9Sstevel@tonic-gate 	case PR_XMAP:
32927c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
32937c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
32947c478bd9Sstevel@tonic-gate 		else {
32957c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3296dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
32977c478bd9Sstevel@tonic-gate 			if (type == PR_MAP)
32987c478bd9Sstevel@tonic-gate 				vap->va_mtime = as->a_updatetime;
32997c478bd9Sstevel@tonic-gate 			if (type == PR_XMAP)
33007c478bd9Sstevel@tonic-gate 				vap->va_size = prnsegs(as, 0) *
33017c478bd9Sstevel@tonic-gate 				    PR_OBJSIZE(prxmap32_t, prxmap_t);
33027c478bd9Sstevel@tonic-gate 			else
33037c478bd9Sstevel@tonic-gate 				vap->va_size = prnsegs(as, type == PR_RMAP) *
33047c478bd9Sstevel@tonic-gate 				    PR_OBJSIZE(prmap32_t, prmap_t);
3305dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
33067c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
33077c478bd9Sstevel@tonic-gate 		}
33087c478bd9Sstevel@tonic-gate 		break;
33097c478bd9Sstevel@tonic-gate 	case PR_CRED:
33107c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_crlock);
33117c478bd9Sstevel@tonic-gate 		vap->va_size = sizeof (prcred_t);
33127c478bd9Sstevel@tonic-gate 		ngroups = crgetngroups(p->p_cred);
33137c478bd9Sstevel@tonic-gate 		if (ngroups > 1)
33147c478bd9Sstevel@tonic-gate 			vap->va_size += (ngroups - 1) * sizeof (gid_t);
33157c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_crlock);
33167c478bd9Sstevel@tonic-gate 		break;
33177c478bd9Sstevel@tonic-gate 	case PR_PRIV:
33187c478bd9Sstevel@tonic-gate 		vap->va_size = prgetprivsize();
33197c478bd9Sstevel@tonic-gate 		break;
3320d2a70789SRichard Lowe 	case PR_SECFLAGS:
3321d2a70789SRichard Lowe 		vap->va_size = sizeof (prsecflags_t);
3322d2a70789SRichard Lowe 		break;
33237c478bd9Sstevel@tonic-gate 	case PR_SIGACT:
3324eb9dbf0cSRoger A. Faulkner 		nsig = PROC_IS_BRANDED(curproc)? BROP(curproc)->b_nsig : NSIG;
3325eb9dbf0cSRoger A. Faulkner 		vap->va_size = (nsig-1) *
33267c478bd9Sstevel@tonic-gate 		    PR_OBJSIZE(struct sigaction32, struct sigaction);
33277c478bd9Sstevel@tonic-gate 		break;
33287c478bd9Sstevel@tonic-gate 	case PR_AUXV:
33297c478bd9Sstevel@tonic-gate 		vap->va_size = __KERN_NAUXV_IMPL * PR_OBJSIZE(auxv32_t, auxv_t);
33307c478bd9Sstevel@tonic-gate 		break;
33317c478bd9Sstevel@tonic-gate #if defined(__x86)
33327c478bd9Sstevel@tonic-gate 	case PR_LDT:
33336e092be7SVamsi Nagineni 		mutex_exit(&p->p_lock);
33347c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_ldtlock);
33357c478bd9Sstevel@tonic-gate 		vap->va_size = prnldt(p) * sizeof (struct ssd);
33367c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_ldtlock);
33376e092be7SVamsi Nagineni 		mutex_enter(&p->p_lock);
33387c478bd9Sstevel@tonic-gate 		break;
33397c478bd9Sstevel@tonic-gate #endif
33407c478bd9Sstevel@tonic-gate 	case PR_USAGE:
33417c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prusage32_t, prusage_t);
33427c478bd9Sstevel@tonic-gate 		break;
33437c478bd9Sstevel@tonic-gate 	case PR_LUSAGE:
33447c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prheader32_t, prheader_t) +
33457c478bd9Sstevel@tonic-gate 		    (p->p_lwpcnt + 1) * PR_OBJSPAN(prusage32_t, prusage_t);
33467c478bd9Sstevel@tonic-gate 		break;
33477c478bd9Sstevel@tonic-gate 	case PR_PAGEDATA:
33487c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
33497c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
33507c478bd9Sstevel@tonic-gate 		else {
33517c478bd9Sstevel@tonic-gate 			/*
33527c478bd9Sstevel@tonic-gate 			 * We can drop p->p_lock before grabbing the
33537c478bd9Sstevel@tonic-gate 			 * address space lock because p->p_as will not
33547c478bd9Sstevel@tonic-gate 			 * change while the process is marked P_PR_LOCK.
33557c478bd9Sstevel@tonic-gate 			 */
33567c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3357dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
33587c478bd9Sstevel@tonic-gate #ifdef _LP64
33597c478bd9Sstevel@tonic-gate 			vap->va_size = iam32bit?
33607c478bd9Sstevel@tonic-gate 			    prpdsize32(as) : prpdsize(as);
33617c478bd9Sstevel@tonic-gate #else
33627c478bd9Sstevel@tonic-gate 			vap->va_size = prpdsize(as);
33637c478bd9Sstevel@tonic-gate #endif
3364dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
33657c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
33667c478bd9Sstevel@tonic-gate 		}
33677c478bd9Sstevel@tonic-gate 		break;
33687c478bd9Sstevel@tonic-gate 	case PR_OPAGEDATA:
33697c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas)
33707c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
33717c478bd9Sstevel@tonic-gate 		else {
33727c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
3373dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
33747c478bd9Sstevel@tonic-gate #ifdef _LP64
33757c478bd9Sstevel@tonic-gate 			vap->va_size = iam32bit?
33767c478bd9Sstevel@tonic-gate 			    oprpdsize32(as) : oprpdsize(as);
33777c478bd9Sstevel@tonic-gate #else
33787c478bd9Sstevel@tonic-gate 			vap->va_size = oprpdsize(as);
33797c478bd9Sstevel@tonic-gate #endif
3380dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
33817c478bd9Sstevel@tonic-gate 			mutex_enter(&p->p_lock);
33827c478bd9Sstevel@tonic-gate 		}
33837c478bd9Sstevel@tonic-gate 		break;
33847c478bd9Sstevel@tonic-gate 	case PR_WATCH:
33857c478bd9Sstevel@tonic-gate 		vap->va_size = avl_numnodes(&p->p_warea) *
33867c478bd9Sstevel@tonic-gate 		    PR_OBJSIZE(prwatch32_t, prwatch_t);
33877c478bd9Sstevel@tonic-gate 		break;
33887c478bd9Sstevel@tonic-gate 	case PR_LWPSTATUS:
33897c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(lwpstatus32_t, lwpstatus_t);
33907c478bd9Sstevel@tonic-gate 		break;
33917c478bd9Sstevel@tonic-gate 	case PR_LWPSINFO:
33927c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(lwpsinfo32_t, lwpsinfo_t);
33937c478bd9Sstevel@tonic-gate 		break;
33947c478bd9Sstevel@tonic-gate 	case PR_LWPUSAGE:
33957c478bd9Sstevel@tonic-gate 		vap->va_size = PR_OBJSIZE(prusage32_t, prusage_t);
33967c478bd9Sstevel@tonic-gate 		break;
33977c478bd9Sstevel@tonic-gate 	case PR_XREGS:
33987c478bd9Sstevel@tonic-gate 		if (prhasx(p))
33997c478bd9Sstevel@tonic-gate 			vap->va_size = prgetprxregsize(p);
34007c478bd9Sstevel@tonic-gate 		else
34017c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
34027c478bd9Sstevel@tonic-gate 		break;
3403f971a346SBryan Cantrill 	case PR_SPYMASTER:
3404614f1d63SJerry Jelinek 		if (pnp->pr_common->prc_thread != NULL &&
3405614f1d63SJerry Jelinek 		    pnp->pr_common->prc_thread->t_lwp->lwp_spymaster != NULL) {
3406f971a346SBryan Cantrill 			vap->va_size = PR_OBJSIZE(psinfo32_t, psinfo_t);
3407f971a346SBryan Cantrill 		} else {
3408f971a346SBryan Cantrill 			vap->va_size = 0;
3409f971a346SBryan Cantrill 		}
3410f971a346SBryan Cantrill 		break;
34117c478bd9Sstevel@tonic-gate #if defined(__sparc)
34127c478bd9Sstevel@tonic-gate 	case PR_GWINDOWS:
34137c478bd9Sstevel@tonic-gate 	{
34147c478bd9Sstevel@tonic-gate 		kthread_t *t;
34157c478bd9Sstevel@tonic-gate 		int n;
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate 		/*
34187c478bd9Sstevel@tonic-gate 		 * If there is no lwp then just make the size zero.
34197c478bd9Sstevel@tonic-gate 		 * This can happen if the lwp exits between the VOP_LOOKUP()
34207c478bd9Sstevel@tonic-gate 		 * of the /proc/<pid>/lwp/<lwpid>/gwindows file and the
34217c478bd9Sstevel@tonic-gate 		 * VOP_GETATTR() of the resulting vnode.
34227c478bd9Sstevel@tonic-gate 		 */
34237c478bd9Sstevel@tonic-gate 		if ((t = pcp->prc_thread) == NULL) {
34247c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
34257c478bd9Sstevel@tonic-gate 			break;
34267c478bd9Sstevel@tonic-gate 		}
34277c478bd9Sstevel@tonic-gate 		/*
34287c478bd9Sstevel@tonic-gate 		 * Drop p->p_lock while touching the stack.
34297c478bd9Sstevel@tonic-gate 		 * The P_PR_LOCK flag prevents the lwp from
34307c478bd9Sstevel@tonic-gate 		 * disappearing while we do this.
34317c478bd9Sstevel@tonic-gate 		 */
34327c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
34337c478bd9Sstevel@tonic-gate 		if ((n = prnwindows(ttolwp(t))) == 0)
34347c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
34357c478bd9Sstevel@tonic-gate 		else
34367c478bd9Sstevel@tonic-gate 			vap->va_size = PR_OBJSIZE(gwindows32_t, gwindows_t) -
34377c478bd9Sstevel@tonic-gate 			    (SPARC_MAXREGWINDOW - n) *
34387c478bd9Sstevel@tonic-gate 			    PR_OBJSIZE(struct rwindow32, struct rwindow);
34397c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
34407c478bd9Sstevel@tonic-gate 		break;
34417c478bd9Sstevel@tonic-gate 	}
34427c478bd9Sstevel@tonic-gate 	case PR_ASRS:
34437c478bd9Sstevel@tonic-gate #ifdef _LP64
34447c478bd9Sstevel@tonic-gate 		if (p->p_model == DATAMODEL_LP64)
34457c478bd9Sstevel@tonic-gate 			vap->va_size = sizeof (asrset_t);
34467c478bd9Sstevel@tonic-gate 		else
34477c478bd9Sstevel@tonic-gate #endif
34487c478bd9Sstevel@tonic-gate 			vap->va_size = 0;
34497c478bd9Sstevel@tonic-gate 		break;
34507c478bd9Sstevel@tonic-gate #endif
34517c478bd9Sstevel@tonic-gate 	case PR_CTL:
34527c478bd9Sstevel@tonic-gate 	case PR_LWPCTL:
34537c478bd9Sstevel@tonic-gate 	default:
34547c478bd9Sstevel@tonic-gate 		vap->va_size = 0;
34557c478bd9Sstevel@tonic-gate 		break;
34567c478bd9Sstevel@tonic-gate 	}
34577c478bd9Sstevel@tonic-gate 
34587c478bd9Sstevel@tonic-gate 	prunlock(pnp);
34597c478bd9Sstevel@tonic-gate 	vap->va_nblocks = (fsblkcnt64_t)btod(vap->va_size);
34607c478bd9Sstevel@tonic-gate 	return (0);
34617c478bd9Sstevel@tonic-gate }
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate static int
praccess(vnode_t * vp,int mode,int flags,cred_t * cr,caller_context_t * ct)3464da6c28aaSamw praccess(vnode_t *vp, int mode, int flags, cred_t *cr, caller_context_t *ct)
34657c478bd9Sstevel@tonic-gate {
34667c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
34677c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
34687c478bd9Sstevel@tonic-gate 	int vmode;
34697c478bd9Sstevel@tonic-gate 	vtype_t vtype;
34707c478bd9Sstevel@tonic-gate 	proc_t *p;
34717c478bd9Sstevel@tonic-gate 	int error = 0;
34727c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
34737c478bd9Sstevel@tonic-gate 	vnode_t *xvp;
34747c478bd9Sstevel@tonic-gate 
34757c478bd9Sstevel@tonic-gate 	if ((mode & VWRITE) && vn_is_readonly(vp))
34767c478bd9Sstevel@tonic-gate 		return (EROFS);
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate 	switch (type) {
34797c478bd9Sstevel@tonic-gate 	case PR_PROCDIR:
34807c478bd9Sstevel@tonic-gate 		break;
34817c478bd9Sstevel@tonic-gate 
34827c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
34837c478bd9Sstevel@tonic-gate 	case PR_FD:
34847c478bd9Sstevel@tonic-gate 		/*
34857c478bd9Sstevel@tonic-gate 		 * Disallow write access to the underlying objects.
34867c478bd9Sstevel@tonic-gate 		 * Disallow access to underlying non-regular-file fds.
34877c478bd9Sstevel@tonic-gate 		 * Disallow access to fds with other than existing open modes.
34887c478bd9Sstevel@tonic-gate 		 */
34897c478bd9Sstevel@tonic-gate 		rvp = pnp->pr_realvp;
34907c478bd9Sstevel@tonic-gate 		vtype = rvp->v_type;
34917c478bd9Sstevel@tonic-gate 		vmode = pnp->pr_mode;
34927c478bd9Sstevel@tonic-gate 		if ((type == PR_OBJECT && (mode & VWRITE)) ||
34937c478bd9Sstevel@tonic-gate 		    (type == PR_FD && vtype != VREG && vtype != VDIR) ||
34947c478bd9Sstevel@tonic-gate 		    (type == PR_FD && (vmode & mode) != mode &&
34957c478bd9Sstevel@tonic-gate 		    secpolicy_proc_access(cr) != 0))
34967c478bd9Sstevel@tonic-gate 			return (EACCES);
3497da6c28aaSamw 		return (VOP_ACCESS(rvp, mode, flags, cr, ct));
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 	case PR_PSINFO:		/* these files can be read by anyone */
35007c478bd9Sstevel@tonic-gate 	case PR_LPSINFO:
35017c478bd9Sstevel@tonic-gate 	case PR_LWPSINFO:
35027c478bd9Sstevel@tonic-gate 	case PR_LWPDIR:
35037c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
35047c478bd9Sstevel@tonic-gate 	case PR_USAGE:
35057c478bd9Sstevel@tonic-gate 	case PR_LUSAGE:
35067c478bd9Sstevel@tonic-gate 	case PR_LWPUSAGE:
35077c478bd9Sstevel@tonic-gate 		p = pr_p_lock(pnp);
35087c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
35097c478bd9Sstevel@tonic-gate 		if (p == NULL)
35107c478bd9Sstevel@tonic-gate 			return (ENOENT);
35117c478bd9Sstevel@tonic-gate 		prunlock(pnp);
35127c478bd9Sstevel@tonic-gate 		break;
35137c478bd9Sstevel@tonic-gate 
35147c478bd9Sstevel@tonic-gate 	default:
35157c478bd9Sstevel@tonic-gate 		/*
35167c478bd9Sstevel@tonic-gate 		 * Except for the world-readable files above,
35177c478bd9Sstevel@tonic-gate 		 * only /proc/pid exists if the process is a zombie.
35187c478bd9Sstevel@tonic-gate 		 */
35197c478bd9Sstevel@tonic-gate 		if ((error = prlock(pnp,
35207c478bd9Sstevel@tonic-gate 		    (type == PR_PIDDIR)? ZYES : ZNO)) != 0)
35217c478bd9Sstevel@tonic-gate 			return (error);
35227c478bd9Sstevel@tonic-gate 		p = pnp->pr_common->prc_proc;
35237c478bd9Sstevel@tonic-gate 		if (p != curproc)
35247c478bd9Sstevel@tonic-gate 			error = priv_proc_cred_perm(cr, p, NULL, mode);
35257c478bd9Sstevel@tonic-gate 
35267c478bd9Sstevel@tonic-gate 		if (error != 0 || p == curproc || (p->p_flag & SSYS) ||
3527ddf7fe95Scasper 		    p->p_as == &kas || (xvp = p->p_exec) == NULL) {
35287c478bd9Sstevel@tonic-gate 			prunlock(pnp);
35297c478bd9Sstevel@tonic-gate 		} else {
35307c478bd9Sstevel@tonic-gate 			/*
35317c478bd9Sstevel@tonic-gate 			 * Determine if the process's executable is readable.
3532ddf7fe95Scasper 			 * We have to drop p->p_lock before the secpolicy
3533ddf7fe95Scasper 			 * and VOP operation.
35347c478bd9Sstevel@tonic-gate 			 */
35357c478bd9Sstevel@tonic-gate 			VN_HOLD(xvp);
35367c478bd9Sstevel@tonic-gate 			prunlock(pnp);
3537ddf7fe95Scasper 			if (secpolicy_proc_access(cr) != 0)
3538da6c28aaSamw 				error = VOP_ACCESS(xvp, VREAD, 0, cr, ct);
35397c478bd9Sstevel@tonic-gate 			VN_RELE(xvp);
35407c478bd9Sstevel@tonic-gate 		}
35417c478bd9Sstevel@tonic-gate 		if (error)
35427c478bd9Sstevel@tonic-gate 			return (error);
35437c478bd9Sstevel@tonic-gate 		break;
35447c478bd9Sstevel@tonic-gate 	}
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate 	if (type == PR_CURDIR || type == PR_ROOTDIR) {
35477c478bd9Sstevel@tonic-gate 		/*
35487c478bd9Sstevel@tonic-gate 		 * Final access check on the underlying directory vnode.
35497c478bd9Sstevel@tonic-gate 		 */
3550da6c28aaSamw 		return (VOP_ACCESS(pnp->pr_realvp, mode, flags, cr, ct));
35517c478bd9Sstevel@tonic-gate 	}
35527c478bd9Sstevel@tonic-gate 
35537c478bd9Sstevel@tonic-gate 	/*
35547c478bd9Sstevel@tonic-gate 	 * Visceral revulsion:  For compatibility with old /proc,
35557c478bd9Sstevel@tonic-gate 	 * allow the /proc/<pid> directory to be opened for writing.
35567c478bd9Sstevel@tonic-gate 	 */
35577c478bd9Sstevel@tonic-gate 	vmode = pnp->pr_mode;
35587c478bd9Sstevel@tonic-gate 	if (type == PR_PIDDIR)
35597c478bd9Sstevel@tonic-gate 		vmode |= VWRITE;
35607c478bd9Sstevel@tonic-gate 	if ((vmode & mode) != mode)
35617c478bd9Sstevel@tonic-gate 		error = secpolicy_proc_access(cr);
35627c478bd9Sstevel@tonic-gate 	return (error);
35637c478bd9Sstevel@tonic-gate }
35647c478bd9Sstevel@tonic-gate 
35657c478bd9Sstevel@tonic-gate /*
35667c478bd9Sstevel@tonic-gate  * Array of lookup functions, indexed by /proc file type.
35677c478bd9Sstevel@tonic-gate  */
35687c478bd9Sstevel@tonic-gate static vnode_t *pr_lookup_notdir(), *pr_lookup_procdir(), *pr_lookup_piddir(),
35697c478bd9Sstevel@tonic-gate 	*pr_lookup_objectdir(), *pr_lookup_lwpdir(), *pr_lookup_lwpiddir(),
3570a02120c4SAndy Fiddaman 	*pr_lookup_fddir(), *pr_lookup_fdinfodir(), *pr_lookup_pathdir(),
3571a02120c4SAndy Fiddaman 	*pr_lookup_tmpldir(), *pr_lookup_ctdir();
35727c478bd9Sstevel@tonic-gate 
35737c478bd9Sstevel@tonic-gate static vnode_t *(*pr_lookup_function[PR_NFILES])() = {
35747c478bd9Sstevel@tonic-gate 	pr_lookup_procdir,	/* /proc				*/
35757c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/self				*/
35767c478bd9Sstevel@tonic-gate 	pr_lookup_piddir,	/* /proc/<pid>				*/
35777c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/as			*/
35787c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/ctl			*/
35797c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/status			*/
35807c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lstatus			*/
35817c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/psinfo			*/
35827c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lpsinfo			*/
35837c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/map			*/
35847c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/rmap			*/
35857c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/xmap			*/
35867c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/cred			*/
35877c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/sigact			*/
35887c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/auxv			*/
35897c478bd9Sstevel@tonic-gate #if defined(__x86)
35907c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/ldt			*/
35917c478bd9Sstevel@tonic-gate #endif
35927c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/usage			*/
35937c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lusage			*/
35947c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/pagedata			*/
35957c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/watch			*/
35967c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/cwd			*/
35977c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/root			*/
35987c478bd9Sstevel@tonic-gate 	pr_lookup_fddir,	/* /proc/<pid>/fd			*/
35997c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/fd/nn			*/
3600a02120c4SAndy Fiddaman 	pr_lookup_fdinfodir,	/* /proc/<pid>/fdinfo			*/
3601a02120c4SAndy Fiddaman 	pr_lookup_notdir,	/* /proc/<pid>/fdinfo/nn		*/
36027c478bd9Sstevel@tonic-gate 	pr_lookup_objectdir,	/* /proc/<pid>/object			*/
36037c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/object/xxx		*/
36047c478bd9Sstevel@tonic-gate 	pr_lookup_lwpdir,	/* /proc/<pid>/lwp			*/
36057c478bd9Sstevel@tonic-gate 	pr_lookup_lwpiddir,	/* /proc/<pid>/lwp/<lwpid>		*/
36067c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
3607ab618543SJohn Levon 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpname	*/
36087c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
36097c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
36107c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
36117c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
36127c478bd9Sstevel@tonic-gate 	pr_lookup_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
36137c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
3614f971a346SBryan Cantrill 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
36157c478bd9Sstevel@tonic-gate #if defined(__sparc)
36167c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
36177c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
36187c478bd9Sstevel@tonic-gate #endif
36197c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/priv			*/
36207c478bd9Sstevel@tonic-gate 	pr_lookup_pathdir,	/* /proc/<pid>/path			*/
36217c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/path/xxx			*/
36227c478bd9Sstevel@tonic-gate 	pr_lookup_ctdir,	/* /proc/<pid>/contracts		*/
36237c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* /proc/<pid>/contracts/<ctid>		*/
3624d2a70789SRichard Lowe 	pr_lookup_notdir,	/* /proc/<pid>/secflags			*/
36257c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* old process file			*/
36267c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* old lwp file				*/
36277c478bd9Sstevel@tonic-gate 	pr_lookup_notdir,	/* old pagedata file			*/
36287c478bd9Sstevel@tonic-gate };
36297c478bd9Sstevel@tonic-gate 
36307c478bd9Sstevel@tonic-gate static int
prlookup(vnode_t * dp,char * comp,vnode_t ** vpp,pathname_t * pathp,int flags,vnode_t * rdir,cred_t * cr,caller_context_t * ct,int * direntflags,pathname_t * realpnp)36317c478bd9Sstevel@tonic-gate prlookup(vnode_t *dp, char *comp, vnode_t **vpp, pathname_t *pathp,
3632da6c28aaSamw     int flags, vnode_t *rdir, cred_t *cr, caller_context_t *ct,
3633da6c28aaSamw     int *direntflags, pathname_t *realpnp)
36347c478bd9Sstevel@tonic-gate {
36357c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(dp);
36367c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
36377c478bd9Sstevel@tonic-gate 	int error;
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	ASSERT(dp->v_type == VDIR);
36407c478bd9Sstevel@tonic-gate 	ASSERT(type < PR_NFILES);
36417c478bd9Sstevel@tonic-gate 
36427c478bd9Sstevel@tonic-gate 	if (type != PR_PROCDIR && strcmp(comp, "..") == 0) {
36437c478bd9Sstevel@tonic-gate 		VN_HOLD(pnp->pr_parent);
36447c478bd9Sstevel@tonic-gate 		*vpp = pnp->pr_parent;
36457c478bd9Sstevel@tonic-gate 		return (0);
36467c478bd9Sstevel@tonic-gate 	}
36477c478bd9Sstevel@tonic-gate 
36487c478bd9Sstevel@tonic-gate 	if (*comp == '\0' ||
36497c478bd9Sstevel@tonic-gate 	    strcmp(comp, ".") == 0 || strcmp(comp, "..") == 0) {
36507c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
36517c478bd9Sstevel@tonic-gate 		*vpp = dp;
36527c478bd9Sstevel@tonic-gate 		return (0);
36537c478bd9Sstevel@tonic-gate 	}
36547c478bd9Sstevel@tonic-gate 
36557c478bd9Sstevel@tonic-gate 	switch (type) {
36567c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
36577c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
36587c478bd9Sstevel@tonic-gate 		/* restrict lookup permission to owner or root */
3659da6c28aaSamw 		if ((error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
36607c478bd9Sstevel@tonic-gate 			return (error);
36617c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
36627c478bd9Sstevel@tonic-gate 	case PR_FD:
3663e2fc3408SPatrick Mooney 		/*
3664e2fc3408SPatrick Mooney 		 * Performing a VOP_LOOKUP on the underlying vnode and emitting
3665e2fc3408SPatrick Mooney 		 * the resulting vnode, without encapsulation, as our own is a
3666e2fc3408SPatrick Mooney 		 * very special case when it comes to the assumptions built
3667e2fc3408SPatrick Mooney 		 * into VFS.
3668e2fc3408SPatrick Mooney 		 *
3669e2fc3408SPatrick Mooney 		 * Since the resulting vnode is highly likely to be at some
3670e2fc3408SPatrick Mooney 		 * abitrary position in another filesystem, we insist that the
3671e2fc3408SPatrick Mooney 		 * VTRAVERSE flag is set on the parent.  This prevents things
3672e2fc3408SPatrick Mooney 		 * such as the v_path freshness logic from mistaking the
3673e2fc3408SPatrick Mooney 		 * resulting vnode as a "real" child of the parent, rather than
3674e2fc3408SPatrick Mooney 		 * a consequence of this "procfs wormhole".
3675e2fc3408SPatrick Mooney 		 *
3676e2fc3408SPatrick Mooney 		 * Failure to establish such protections can lead to
3677e2fc3408SPatrick Mooney 		 * incorrectly calculated v_paths being set on nodes reached
3678e2fc3408SPatrick Mooney 		 * through these lookups.
3679e2fc3408SPatrick Mooney 		 */
3680e2fc3408SPatrick Mooney 		ASSERT((dp->v_flag & VTRAVERSE) != 0);
3681e2fc3408SPatrick Mooney 
36827c478bd9Sstevel@tonic-gate 		dp = pnp->pr_realvp;
3683da6c28aaSamw 		return (VOP_LOOKUP(dp, comp, vpp, pathp, flags, rdir, cr, ct,
3684da6c28aaSamw 		    direntflags, realpnp));
36857c478bd9Sstevel@tonic-gate 	default:
36867c478bd9Sstevel@tonic-gate 		break;
36877c478bd9Sstevel@tonic-gate 	}
36887c478bd9Sstevel@tonic-gate 
3689a02120c4SAndy Fiddaman 	if ((type == PR_OBJECTDIR || type == PR_FDDIR ||
3690a02120c4SAndy Fiddaman 	    type == PR_FDINFODIR || type == PR_PATHDIR) &&
3691da6c28aaSamw 	    (error = praccess(dp, VEXEC, 0, cr, ct)) != 0)
36927c478bd9Sstevel@tonic-gate 		return (error);
36937c478bd9Sstevel@tonic-gate 
3694da6c28aaSamw 	/* XXX - Do we need to pass ct, direntflags, or realpnp? */
36957c478bd9Sstevel@tonic-gate 	*vpp = (pr_lookup_function[type](dp, comp));
36967c478bd9Sstevel@tonic-gate 
36977c478bd9Sstevel@tonic-gate 	return ((*vpp == NULL) ? ENOENT : 0);
36987c478bd9Sstevel@tonic-gate }
36997c478bd9Sstevel@tonic-gate 
37007c478bd9Sstevel@tonic-gate /* ARGSUSED */
37017c478bd9Sstevel@tonic-gate static int
prcreate(vnode_t * dp,char * comp,vattr_t * vap,vcexcl_t excl,int mode,vnode_t ** vpp,cred_t * cr,int flag,caller_context_t * ct,vsecattr_t * vsecp)37027c478bd9Sstevel@tonic-gate prcreate(vnode_t *dp, char *comp, vattr_t *vap, vcexcl_t excl,
3703da6c28aaSamw     int mode, vnode_t **vpp, cred_t *cr, int flag, caller_context_t *ct,
3704da6c28aaSamw     vsecattr_t *vsecp)
37057c478bd9Sstevel@tonic-gate {
37067c478bd9Sstevel@tonic-gate 	int error;
37077c478bd9Sstevel@tonic-gate 
3708da6c28aaSamw 	if ((error = prlookup(dp, comp, vpp, NULL, 0, NULL, cr,
3709da6c28aaSamw 	    ct, NULL, NULL)) != 0) {
3710fee52838SPatrick Mooney 		if (error == ENOENT) {
3711fee52838SPatrick Mooney 			/* One can't O_CREAT nonexistent files in /proc. */
3712fee52838SPatrick Mooney 			error = EACCES;
3713fee52838SPatrick Mooney 		}
3714fee52838SPatrick Mooney 		return (error);
3715fee52838SPatrick Mooney 	}
3716fee52838SPatrick Mooney 
3717fee52838SPatrick Mooney 	if (excl == EXCL) {
3718fee52838SPatrick Mooney 		/* Disallow the O_EXCL case */
37197c478bd9Sstevel@tonic-gate 		error = EEXIST;
3720fee52838SPatrick Mooney 	} else if ((error = praccess(*vpp, mode, 0, cr, ct)) == 0) {
3721fee52838SPatrick Mooney 		/* Before proceeding, handle O_TRUNC if necessary. */
3722fee52838SPatrick Mooney 		if (vap->va_mask & AT_SIZE) {
37237c478bd9Sstevel@tonic-gate 			vnode_t *vp = *vpp;
3724fee52838SPatrick Mooney 
3725fee52838SPatrick Mooney 			if (vp->v_type == VDIR) {
3726fee52838SPatrick Mooney 				/* Only allow O_TRUNC on files */
3727fee52838SPatrick Mooney 				error = EISDIR;
3728fee52838SPatrick Mooney 			} else if (vp->v_type != VPROC ||
3729fee52838SPatrick Mooney 			    VTOP(vp)->pr_type != PR_FD) {
3730fee52838SPatrick Mooney 				/*
3731fee52838SPatrick Mooney 				 * Disallow for files outside of the
3732fee52838SPatrick Mooney 				 * /proc/<pid>/fd/<n> entries
3733fee52838SPatrick Mooney 				 */
3734fee52838SPatrick Mooney 				error = EACCES;
3735fee52838SPatrick Mooney 			} else {
37367c478bd9Sstevel@tonic-gate 				uint_t mask;
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 				vp = VTOP(vp)->pr_realvp;
37397c478bd9Sstevel@tonic-gate 				mask = vap->va_mask;
37407c478bd9Sstevel@tonic-gate 				vap->va_mask = AT_SIZE;
3741da6c28aaSamw 				error = VOP_SETATTR(vp, vap, 0, cr, ct);
37427c478bd9Sstevel@tonic-gate 				vap->va_mask = mask;
37437c478bd9Sstevel@tonic-gate 			}
37447c478bd9Sstevel@tonic-gate 		}
3745fee52838SPatrick Mooney 	}
3746fee52838SPatrick Mooney 
37477c478bd9Sstevel@tonic-gate 	if (error) {
37487c478bd9Sstevel@tonic-gate 		VN_RELE(*vpp);
37497c478bd9Sstevel@tonic-gate 		*vpp = NULL;
37507c478bd9Sstevel@tonic-gate 	}
37517c478bd9Sstevel@tonic-gate 	return (error);
37527c478bd9Sstevel@tonic-gate }
37537c478bd9Sstevel@tonic-gate 
37547c478bd9Sstevel@tonic-gate /* ARGSUSED */
37557c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_notdir(vnode_t * dp,char * comp)37567c478bd9Sstevel@tonic-gate pr_lookup_notdir(vnode_t *dp, char *comp)
37577c478bd9Sstevel@tonic-gate {
37587c478bd9Sstevel@tonic-gate 	return (NULL);
37597c478bd9Sstevel@tonic-gate }
37607c478bd9Sstevel@tonic-gate 
37617c478bd9Sstevel@tonic-gate /*
37627c478bd9Sstevel@tonic-gate  * Find or construct a process vnode for the given pid.
37637c478bd9Sstevel@tonic-gate  */
37647c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_procdir(vnode_t * dp,char * comp)37657c478bd9Sstevel@tonic-gate pr_lookup_procdir(vnode_t *dp, char *comp)
37667c478bd9Sstevel@tonic-gate {
37677c478bd9Sstevel@tonic-gate 	pid_t pid;
37687c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
37697c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
37707c478bd9Sstevel@tonic-gate 	vnode_t *vp;
37717c478bd9Sstevel@tonic-gate 	proc_t *p;
37727c478bd9Sstevel@tonic-gate 	int c;
37737c478bd9Sstevel@tonic-gate 
37747c478bd9Sstevel@tonic-gate 	ASSERT(VTOP(dp)->pr_type == PR_PROCDIR);
37757c478bd9Sstevel@tonic-gate 
37767c478bd9Sstevel@tonic-gate 	if (strcmp(comp, "self") == 0) {
37777c478bd9Sstevel@tonic-gate 		pnp = prgetnode(dp, PR_SELF);
37787c478bd9Sstevel@tonic-gate 		return (PTOV(pnp));
37797c478bd9Sstevel@tonic-gate 	} else {
37807c478bd9Sstevel@tonic-gate 		pid = 0;
37817c478bd9Sstevel@tonic-gate 		while ((c = *comp++) != '\0') {
37827c478bd9Sstevel@tonic-gate 			if (c < '0' || c > '9')
37837c478bd9Sstevel@tonic-gate 				return (NULL);
37847c478bd9Sstevel@tonic-gate 			pid = 10*pid + c - '0';
37857c478bd9Sstevel@tonic-gate 			if (pid > maxpid)
37867c478bd9Sstevel@tonic-gate 				return (NULL);
37877c478bd9Sstevel@tonic-gate 		}
37887c478bd9Sstevel@tonic-gate 	}
37897c478bd9Sstevel@tonic-gate 
37907c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_PIDDIR);
37917c478bd9Sstevel@tonic-gate 
37927c478bd9Sstevel@tonic-gate 	mutex_enter(&pidlock);
37937c478bd9Sstevel@tonic-gate 	if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
37947c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
37957c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
37967c478bd9Sstevel@tonic-gate 		return (NULL);
37977c478bd9Sstevel@tonic-gate 	}
37987c478bd9Sstevel@tonic-gate 	ASSERT(p->p_stat != 0);
37997c478bd9Sstevel@tonic-gate 
3800ddf7fe95Scasper 	/* NOTE: we're holding pidlock across the policy call. */
38017c478bd9Sstevel@tonic-gate 	if (secpolicy_basic_procinfo(CRED(), p, curproc) != 0) {
3802ddf7fe95Scasper 		mutex_exit(&pidlock);
38037c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
38047c478bd9Sstevel@tonic-gate 		return (NULL);
38057c478bd9Sstevel@tonic-gate 	}
38067c478bd9Sstevel@tonic-gate 
3807ddf7fe95Scasper 	mutex_enter(&p->p_lock);
3808ddf7fe95Scasper 	mutex_exit(&pidlock);
3809ddf7fe95Scasper 
38107c478bd9Sstevel@tonic-gate 	/*
38117c478bd9Sstevel@tonic-gate 	 * If a process vnode already exists and it is not invalid
38127c478bd9Sstevel@tonic-gate 	 * and it was created by the current process and it belongs
38137c478bd9Sstevel@tonic-gate 	 * to the same /proc mount point as our parent vnode, then
38147c478bd9Sstevel@tonic-gate 	 * just use it and discard the newly-allocated prnode.
38157c478bd9Sstevel@tonic-gate 	 */
38167c478bd9Sstevel@tonic-gate 	for (vp = p->p_trace; vp != NULL; vp = VTOP(vp)->pr_next) {
38177c478bd9Sstevel@tonic-gate 		if (!(VTOP(VTOP(vp)->pr_pidfile)->pr_flags & PR_INVAL) &&
38187c478bd9Sstevel@tonic-gate 		    VTOP(vp)->pr_owner == curproc &&
38197c478bd9Sstevel@tonic-gate 		    vp->v_vfsp == dp->v_vfsp) {
38207c478bd9Sstevel@tonic-gate 			ASSERT(!(VTOP(vp)->pr_flags & PR_INVAL));
38217c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
38227c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
38237c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
38247c478bd9Sstevel@tonic-gate 			return (vp);
38257c478bd9Sstevel@tonic-gate 		}
38267c478bd9Sstevel@tonic-gate 	}
38277c478bd9Sstevel@tonic-gate 	pnp->pr_owner = curproc;
38287c478bd9Sstevel@tonic-gate 
38297c478bd9Sstevel@tonic-gate 	/*
38307c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
38317c478bd9Sstevel@tonic-gate 	 * Finish the job.
38327c478bd9Sstevel@tonic-gate 	 */
38337c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;	/* the newly-allocated prcommon struct */
38347c478bd9Sstevel@tonic-gate 	if ((vp = p->p_trace) != NULL) {
38357c478bd9Sstevel@tonic-gate 		/* discard the new prcommon and use the existing prcommon */
38367c478bd9Sstevel@tonic-gate 		prfreecommon(pcp);
38377c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
38387c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
38397c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt > 0);
38407c478bd9Sstevel@tonic-gate 		pcp->prc_refcnt++;
38417c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
38427c478bd9Sstevel@tonic-gate 		pnp->pr_common = pcp;
38437c478bd9Sstevel@tonic-gate 	} else {
38447c478bd9Sstevel@tonic-gate 		/* initialize the new prcommon struct */
38457c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || p->p_as == &kas)
38467c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_SYS;
38475203e56bSJerry Jelinek 		if (p->p_stat == SZOMB || (p->p_flag & SEXITING) != 0)
38487c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
38497c478bd9Sstevel@tonic-gate 		pcp->prc_proc = p;
38507c478bd9Sstevel@tonic-gate 		pcp->prc_datamodel = p->p_model;
38517c478bd9Sstevel@tonic-gate 		pcp->prc_pid = p->p_pid;
38527c478bd9Sstevel@tonic-gate 		pcp->prc_slot = p->p_slot;
38537c478bd9Sstevel@tonic-gate 	}
38547c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = pcp;
38557c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
38567c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
38577c478bd9Sstevel@tonic-gate 	/*
38587c478bd9Sstevel@tonic-gate 	 * Link in the old, invalid directory vnode so we
38597c478bd9Sstevel@tonic-gate 	 * can later determine the last close of the file.
38607c478bd9Sstevel@tonic-gate 	 */
38617c478bd9Sstevel@tonic-gate 	pnp->pr_next = p->p_trace;
38627c478bd9Sstevel@tonic-gate 	p->p_trace = dp = PTOV(pnp);
38637c478bd9Sstevel@tonic-gate 
38647c478bd9Sstevel@tonic-gate 	/*
38657c478bd9Sstevel@tonic-gate 	 * Kludge for old /proc: initialize the PR_PIDFILE as well.
38667c478bd9Sstevel@tonic-gate 	 */
38677c478bd9Sstevel@tonic-gate 	vp = pnp->pr_pidfile;
38687c478bd9Sstevel@tonic-gate 	pnp = VTOP(vp);
38697c478bd9Sstevel@tonic-gate 	pnp->pr_ino = ptoi(pcp->prc_pid);
38707c478bd9Sstevel@tonic-gate 	pnp->pr_common = pcp;
38717c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = pcp;
38727c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
38737c478bd9Sstevel@tonic-gate 	pnp->pr_next = p->p_plist;
38747c478bd9Sstevel@tonic-gate 	p->p_plist = vp;
38757c478bd9Sstevel@tonic-gate 
38767c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
38777c478bd9Sstevel@tonic-gate 	return (dp);
38787c478bd9Sstevel@tonic-gate }
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_piddir(vnode_t * dp,char * comp)38817c478bd9Sstevel@tonic-gate pr_lookup_piddir(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 	user_t *up;
38887c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
38897c478bd9Sstevel@tonic-gate 	int i;
38907c478bd9Sstevel@tonic-gate 	enum prnodetype type;
38917c478bd9Sstevel@tonic-gate 
38927c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_PIDDIR);
38937c478bd9Sstevel@tonic-gate 
38947c478bd9Sstevel@tonic-gate 	for (i = 0; i < NPIDDIRFILES; i++) {
38957c478bd9Sstevel@tonic-gate 		/* Skip "." and ".." */
38967c478bd9Sstevel@tonic-gate 		dirp = &piddir[i+2];
38977c478bd9Sstevel@tonic-gate 		if (strcmp(comp, dirp->d_name) == 0)
38987c478bd9Sstevel@tonic-gate 			break;
38997c478bd9Sstevel@tonic-gate 	}
39007c478bd9Sstevel@tonic-gate 
39017c478bd9Sstevel@tonic-gate 	if (i >= NPIDDIRFILES)
39027c478bd9Sstevel@tonic-gate 		return (NULL);
39037c478bd9Sstevel@tonic-gate 
39047c478bd9Sstevel@tonic-gate 	type = (int)dirp->d_ino;
39057c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, type);
39067c478bd9Sstevel@tonic-gate 
39077c478bd9Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
39087c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
39097c478bd9Sstevel@tonic-gate 	if (p == NULL) {
39107c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
39117c478bd9Sstevel@tonic-gate 		return (NULL);
39127c478bd9Sstevel@tonic-gate 	}
39137c478bd9Sstevel@tonic-gate 	if (dpnp->pr_pcommon->prc_flags & PRC_DESTROY) {
39147c478bd9Sstevel@tonic-gate 		switch (type) {
39157c478bd9Sstevel@tonic-gate 		case PR_PSINFO:
39167c478bd9Sstevel@tonic-gate 		case PR_USAGE:
39177c478bd9Sstevel@tonic-gate 			break;
39187c478bd9Sstevel@tonic-gate 		default:
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 	switch (type) {
39267c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
39277c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
39287c478bd9Sstevel@tonic-gate 		up = PTOU(p);
39297c478bd9Sstevel@tonic-gate 		vp = (type == PR_CURDIR)? up->u_cdir :
39307c478bd9Sstevel@tonic-gate 		    (up->u_rdir? up->u_rdir : rootdir);
39317c478bd9Sstevel@tonic-gate 
3932e2fc3408SPatrick Mooney 		if (vp == NULL) {
3933e2fc3408SPatrick Mooney 			/* can't happen(?) */
39347c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
39357c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
39367c478bd9Sstevel@tonic-gate 			return (NULL);
39377c478bd9Sstevel@tonic-gate 		}
39387c478bd9Sstevel@tonic-gate 		/*
39397c478bd9Sstevel@tonic-gate 		 * Fill in the prnode so future references will
39407c478bd9Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
39417c478bd9Sstevel@tonic-gate 		 */
39427c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
39437c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
3944e2fc3408SPatrick Mooney 		PTOV(pnp)->v_flag |= VTRAVERSE;
39457c478bd9Sstevel@tonic-gate 		break;
39467c478bd9Sstevel@tonic-gate 	default:
39477c478bd9Sstevel@tonic-gate 		break;
39487c478bd9Sstevel@tonic-gate 	}
39497c478bd9Sstevel@tonic-gate 
39507c478bd9Sstevel@tonic-gate 	mutex_enter(&dpnp->pr_mutex);
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate 	if ((vp = dpnp->pr_files[i]) != NULL &&
39537c478bd9Sstevel@tonic-gate 	    !(VTOP(vp)->pr_flags & PR_INVAL)) {
39547c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
39557c478bd9Sstevel@tonic-gate 		mutex_exit(&dpnp->pr_mutex);
39567c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
39577c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
39587c478bd9Sstevel@tonic-gate 		return (vp);
39597c478bd9Sstevel@tonic-gate 	}
39607c478bd9Sstevel@tonic-gate 
39617c478bd9Sstevel@tonic-gate 	/*
39627c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
39637c478bd9Sstevel@tonic-gate 	 * Finish the job.
39647c478bd9Sstevel@tonic-gate 	 */
39657c478bd9Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
39667c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
39677c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
39687c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
39697c478bd9Sstevel@tonic-gate 	pnp->pr_index = i;
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate 	dpnp->pr_files[i] = vp = PTOV(pnp);
39727c478bd9Sstevel@tonic-gate 
39737c478bd9Sstevel@tonic-gate 	/*
39747c478bd9Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
39757c478bd9Sstevel@tonic-gate 	 */
39767c478bd9Sstevel@tonic-gate 	if (vp->v_type == VPROC) {
39777c478bd9Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
39787c478bd9Sstevel@tonic-gate 		p->p_plist = vp;
39797c478bd9Sstevel@tonic-gate 	}
39807c478bd9Sstevel@tonic-gate 	mutex_exit(&dpnp->pr_mutex);
39817c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
39827c478bd9Sstevel@tonic-gate 	return (vp);
39837c478bd9Sstevel@tonic-gate }
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_objectdir(vnode_t * dp,char * comp)39867c478bd9Sstevel@tonic-gate pr_lookup_objectdir(vnode_t *dp, char *comp)
39877c478bd9Sstevel@tonic-gate {
39887c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
39897c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
39907c478bd9Sstevel@tonic-gate 	proc_t *p;
39917c478bd9Sstevel@tonic-gate 	struct seg *seg;
39927c478bd9Sstevel@tonic-gate 	struct as *as;
39937c478bd9Sstevel@tonic-gate 	vnode_t *vp;
39947c478bd9Sstevel@tonic-gate 	vattr_t vattr;
39957c478bd9Sstevel@tonic-gate 
39967c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_OBJECTDIR);
39977c478bd9Sstevel@tonic-gate 
39987c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_OBJECT);
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) || (as = 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 	/*
40127c478bd9Sstevel@tonic-gate 	 * We drop p_lock before grabbing the address space lock
40137c478bd9Sstevel@tonic-gate 	 * in order to avoid a deadlock with the clock thread.
40147c478bd9Sstevel@tonic-gate 	 * The process will not disappear and its address space
40157c478bd9Sstevel@tonic-gate 	 * will not change because it is marked P_PR_LOCK.
40167c478bd9Sstevel@tonic-gate 	 */
40177c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
4018dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_ENTER(as, RW_READER);
40197c478bd9Sstevel@tonic-gate 	if ((seg = AS_SEGFIRST(as)) == NULL) {
40207c478bd9Sstevel@tonic-gate 		vp = NULL;
40217c478bd9Sstevel@tonic-gate 		goto out;
40227c478bd9Sstevel@tonic-gate 	}
40237c478bd9Sstevel@tonic-gate 	if (strcmp(comp, "a.out") == 0) {
40247c478bd9Sstevel@tonic-gate 		vp = p->p_exec;
40257c478bd9Sstevel@tonic-gate 		goto out;
40267c478bd9Sstevel@tonic-gate 	}
40277c478bd9Sstevel@tonic-gate 	do {
40287c478bd9Sstevel@tonic-gate 		/*
40297c478bd9Sstevel@tonic-gate 		 * Manufacture a filename for the "object" directory.
40307c478bd9Sstevel@tonic-gate 		 */
40317c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID|AT_NODEID;
40327c478bd9Sstevel@tonic-gate 		if (seg->s_ops == &segvn_ops &&
40337c478bd9Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
40347c478bd9Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
4035da6c28aaSamw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
40367c478bd9Sstevel@tonic-gate 			char name[64];
40377c478bd9Sstevel@tonic-gate 
40387c478bd9Sstevel@tonic-gate 			if (vp == p->p_exec)	/* "a.out" */
40397c478bd9Sstevel@tonic-gate 				continue;
40407c478bd9Sstevel@tonic-gate 			pr_object_name(name, vp, &vattr);
40417c478bd9Sstevel@tonic-gate 			if (strcmp(name, comp) == 0)
40427c478bd9Sstevel@tonic-gate 				goto out;
40437c478bd9Sstevel@tonic-gate 		}
40447c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
40457c478bd9Sstevel@tonic-gate 
40467c478bd9Sstevel@tonic-gate 	vp = NULL;
40477c478bd9Sstevel@tonic-gate out:
40487c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
40497c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
40507c478bd9Sstevel@tonic-gate 	}
4051dc32d872SJosef 'Jeff' Sipek 	AS_LOCK_EXIT(as);
40527c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
40537c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
40547c478bd9Sstevel@tonic-gate 
40557c478bd9Sstevel@tonic-gate 	if (vp == NULL)
40567c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
40577c478bd9Sstevel@tonic-gate 	else {
40587c478bd9Sstevel@tonic-gate 		/*
40597c478bd9Sstevel@tonic-gate 		 * Fill in the prnode so future references will
40607c478bd9Sstevel@tonic-gate 		 * be able to find the underlying object's vnode.
40617c478bd9Sstevel@tonic-gate 		 * Don't link this prnode into the list of all
40627c478bd9Sstevel@tonic-gate 		 * prnodes for the process; this is a one-use node.
40637c478bd9Sstevel@tonic-gate 		 * Its use is entirely to catch and fail opens for writing.
40647c478bd9Sstevel@tonic-gate 		 */
40657c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
40667c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
40677c478bd9Sstevel@tonic-gate 	}
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate 	return (vp);
40707c478bd9Sstevel@tonic-gate }
40717c478bd9Sstevel@tonic-gate 
40727c478bd9Sstevel@tonic-gate /*
40737c478bd9Sstevel@tonic-gate  * Find or construct an lwp vnode for the given lwpid.
40747c478bd9Sstevel@tonic-gate  */
40757c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_lwpdir(vnode_t * dp,char * comp)40767c478bd9Sstevel@tonic-gate pr_lookup_lwpdir(vnode_t *dp, char *comp)
40777c478bd9Sstevel@tonic-gate {
40787c478bd9Sstevel@tonic-gate 	id_t tid;	/* same type as t->t_tid */
40797c478bd9Sstevel@tonic-gate 	int want_agent;
40807c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
40817c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
40827c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
40837c478bd9Sstevel@tonic-gate 	vnode_t *vp;
40847c478bd9Sstevel@tonic-gate 	proc_t *p;
40857c478bd9Sstevel@tonic-gate 	kthread_t *t;
40867c478bd9Sstevel@tonic-gate 	lwpdir_t *ldp;
40877c478bd9Sstevel@tonic-gate 	lwpent_t *lep;
40887c478bd9Sstevel@tonic-gate 	int tslot;
40897c478bd9Sstevel@tonic-gate 	int c;
40907c478bd9Sstevel@tonic-gate 
40917c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_LWPDIR);
40927c478bd9Sstevel@tonic-gate 
40937c478bd9Sstevel@tonic-gate 	tid = 0;
40947c478bd9Sstevel@tonic-gate 	if (strcmp(comp, "agent") == 0)
40957c478bd9Sstevel@tonic-gate 		want_agent = 1;
40967c478bd9Sstevel@tonic-gate 	else {
40977c478bd9Sstevel@tonic-gate 		want_agent = 0;
40987c478bd9Sstevel@tonic-gate 		while ((c = *comp++) != '\0') {
40997c478bd9Sstevel@tonic-gate 			id_t otid;
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate 			if (c < '0' || c > '9')
41027c478bd9Sstevel@tonic-gate 				return (NULL);
41037c478bd9Sstevel@tonic-gate 			otid = tid;
41047c478bd9Sstevel@tonic-gate 			tid = 10*tid + c - '0';
41057c478bd9Sstevel@tonic-gate 			if (tid/10 != otid)	/* integer overflow */
41067c478bd9Sstevel@tonic-gate 				return (NULL);
41077c478bd9Sstevel@tonic-gate 		}
41087c478bd9Sstevel@tonic-gate 	}
41097c478bd9Sstevel@tonic-gate 
41107c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_LWPIDDIR);
41117c478bd9Sstevel@tonic-gate 
41127c478bd9Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
41137c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
41147c478bd9Sstevel@tonic-gate 	if (p == NULL) {
41157c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
41167c478bd9Sstevel@tonic-gate 		return (NULL);
41177c478bd9Sstevel@tonic-gate 	}
41187c478bd9Sstevel@tonic-gate 
41197c478bd9Sstevel@tonic-gate 	if (want_agent) {
41207c478bd9Sstevel@tonic-gate 		if ((t = p->p_agenttp) == NULL)
41217c478bd9Sstevel@tonic-gate 			lep = NULL;
41227c478bd9Sstevel@tonic-gate 		else {
41237c478bd9Sstevel@tonic-gate 			tid = t->t_tid;
41247c478bd9Sstevel@tonic-gate 			tslot = t->t_dslot;
41257c478bd9Sstevel@tonic-gate 			lep = p->p_lwpdir[tslot].ld_entry;
41267c478bd9Sstevel@tonic-gate 		}
41277c478bd9Sstevel@tonic-gate 	} else {
41287c478bd9Sstevel@tonic-gate 		if ((ldp = lwp_hash_lookup(p, tid)) == NULL)
41297c478bd9Sstevel@tonic-gate 			lep = NULL;
41307c478bd9Sstevel@tonic-gate 		else {
41317c478bd9Sstevel@tonic-gate 			tslot = (int)(ldp - p->p_lwpdir);
41327c478bd9Sstevel@tonic-gate 			lep = ldp->ld_entry;
41337c478bd9Sstevel@tonic-gate 		}
41347c478bd9Sstevel@tonic-gate 	}
41357c478bd9Sstevel@tonic-gate 
41367c478bd9Sstevel@tonic-gate 	if (lep == NULL) {
41377c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
41387c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
41397c478bd9Sstevel@tonic-gate 		return (NULL);
41407c478bd9Sstevel@tonic-gate 	}
41417c478bd9Sstevel@tonic-gate 
41427c478bd9Sstevel@tonic-gate 	/*
41437c478bd9Sstevel@tonic-gate 	 * If an lwp vnode already exists and it is not invalid
41447c478bd9Sstevel@tonic-gate 	 * and it was created by the current process and it belongs
41457c478bd9Sstevel@tonic-gate 	 * to the same /proc mount point as our parent vnode, then
41467c478bd9Sstevel@tonic-gate 	 * just use it and discard the newly-allocated prnode.
41477c478bd9Sstevel@tonic-gate 	 */
41487c478bd9Sstevel@tonic-gate 	for (vp = lep->le_trace; vp != NULL; vp = VTOP(vp)->pr_next) {
41497c478bd9Sstevel@tonic-gate 		if (!(VTOP(vp)->pr_flags & PR_INVAL) &&
41507c478bd9Sstevel@tonic-gate 		    VTOP(vp)->pr_owner == curproc &&
41517c478bd9Sstevel@tonic-gate 		    vp->v_vfsp == dp->v_vfsp) {
41527c478bd9Sstevel@tonic-gate 			VN_HOLD(vp);
41537c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
41547c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
41557c478bd9Sstevel@tonic-gate 			return (vp);
41567c478bd9Sstevel@tonic-gate 		}
41577c478bd9Sstevel@tonic-gate 	}
41587c478bd9Sstevel@tonic-gate 	pnp->pr_owner = curproc;
41597c478bd9Sstevel@tonic-gate 
41607c478bd9Sstevel@tonic-gate 	/*
41617c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
41627c478bd9Sstevel@tonic-gate 	 * Finish the job.
41637c478bd9Sstevel@tonic-gate 	 */
41647c478bd9Sstevel@tonic-gate 	pcp = pnp->pr_common;	/* the newly-allocated prcommon struct */
41657c478bd9Sstevel@tonic-gate 	if ((vp = lep->le_trace) != NULL) {
41667c478bd9Sstevel@tonic-gate 		/* discard the new prcommon and use the existing prcommon */
41677c478bd9Sstevel@tonic-gate 		prfreecommon(pcp);
41687c478bd9Sstevel@tonic-gate 		pcp = VTOP(vp)->pr_common;
41697c478bd9Sstevel@tonic-gate 		mutex_enter(&pcp->prc_mutex);
41707c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt > 0);
41717c478bd9Sstevel@tonic-gate 		pcp->prc_refcnt++;
41727c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
41737c478bd9Sstevel@tonic-gate 		pnp->pr_common = pcp;
41747c478bd9Sstevel@tonic-gate 	} else {
41757c478bd9Sstevel@tonic-gate 		/* initialize the new prcommon struct */
41767c478bd9Sstevel@tonic-gate 		pcp->prc_flags |= PRC_LWP;
41777c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || p->p_as == &kas)
41787c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_SYS;
41797c478bd9Sstevel@tonic-gate 		if ((t = lep->le_thread) == NULL)
41807c478bd9Sstevel@tonic-gate 			pcp->prc_flags |= PRC_DESTROY;
41817c478bd9Sstevel@tonic-gate 		pcp->prc_proc = p;
41827c478bd9Sstevel@tonic-gate 		pcp->prc_datamodel = dpnp->pr_pcommon->prc_datamodel;
41837c478bd9Sstevel@tonic-gate 		pcp->prc_pid = p->p_pid;
41847c478bd9Sstevel@tonic-gate 		pcp->prc_slot = p->p_slot;
41857c478bd9Sstevel@tonic-gate 		pcp->prc_thread = t;
41867c478bd9Sstevel@tonic-gate 		pcp->prc_tid = tid;
41877c478bd9Sstevel@tonic-gate 		pcp->prc_tslot = tslot;
41887c478bd9Sstevel@tonic-gate 	}
41897c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
41907c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
41917c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
41927c478bd9Sstevel@tonic-gate 	/*
41937c478bd9Sstevel@tonic-gate 	 * Link in the old, invalid directory vnode so we
41947c478bd9Sstevel@tonic-gate 	 * can later determine the last close of the file.
41957c478bd9Sstevel@tonic-gate 	 */
41967c478bd9Sstevel@tonic-gate 	pnp->pr_next = lep->le_trace;
41977c478bd9Sstevel@tonic-gate 	lep->le_trace = vp = PTOV(pnp);
41987c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
41997c478bd9Sstevel@tonic-gate 	return (vp);
42007c478bd9Sstevel@tonic-gate }
42017c478bd9Sstevel@tonic-gate 
42027c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_lwpiddir(vnode_t * dp,char * comp)42037c478bd9Sstevel@tonic-gate pr_lookup_lwpiddir(vnode_t *dp, char *comp)
42047c478bd9Sstevel@tonic-gate {
42057c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
42067c478bd9Sstevel@tonic-gate 	vnode_t *vp;
42077c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
42087c478bd9Sstevel@tonic-gate 	proc_t *p;
42097c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
42107c478bd9Sstevel@tonic-gate 	int i;
42117c478bd9Sstevel@tonic-gate 	enum prnodetype type;
42127c478bd9Sstevel@tonic-gate 
42137c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_LWPIDDIR);
42147c478bd9Sstevel@tonic-gate 
42157c478bd9Sstevel@tonic-gate 	for (i = 0; i < NLWPIDDIRFILES; i++) {
42167c478bd9Sstevel@tonic-gate 		/* Skip "." and ".." */
42177c478bd9Sstevel@tonic-gate 		dirp = &lwpiddir[i+2];
42187c478bd9Sstevel@tonic-gate 		if (strcmp(comp, dirp->d_name) == 0)
42197c478bd9Sstevel@tonic-gate 			break;
42207c478bd9Sstevel@tonic-gate 	}
42217c478bd9Sstevel@tonic-gate 
42227c478bd9Sstevel@tonic-gate 	if (i >= NLWPIDDIRFILES)
42237c478bd9Sstevel@tonic-gate 		return (NULL);
42247c478bd9Sstevel@tonic-gate 
42257c478bd9Sstevel@tonic-gate 	type = (int)dirp->d_ino;
42267c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, type);
42277c478bd9Sstevel@tonic-gate 
42287c478bd9Sstevel@tonic-gate 	p = pr_p_lock(dpnp);
42297c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
42307c478bd9Sstevel@tonic-gate 	if (p == NULL) {
42317c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
42327c478bd9Sstevel@tonic-gate 		return (NULL);
42337c478bd9Sstevel@tonic-gate 	}
42347c478bd9Sstevel@tonic-gate 	if (dpnp->pr_common->prc_flags & PRC_DESTROY) {
42357c478bd9Sstevel@tonic-gate 		/*
42367c478bd9Sstevel@tonic-gate 		 * Only the lwpsinfo file is present for zombie lwps.
42377c478bd9Sstevel@tonic-gate 		 * Nothing is present if the lwp has been reaped.
42387c478bd9Sstevel@tonic-gate 		 */
42397c478bd9Sstevel@tonic-gate 		if (dpnp->pr_common->prc_tslot == -1 ||
42407c478bd9Sstevel@tonic-gate 		    type != PR_LWPSINFO) {
42417c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
42427c478bd9Sstevel@tonic-gate 			prfreenode(pnp);
42437c478bd9Sstevel@tonic-gate 			return (NULL);
42447c478bd9Sstevel@tonic-gate 		}
42457c478bd9Sstevel@tonic-gate 	}
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate #if defined(__sparc)
42487c478bd9Sstevel@tonic-gate 	/* the asrs file exists only for sparc v9 _LP64 processes */
42497c478bd9Sstevel@tonic-gate 	if (type == PR_ASRS && p->p_model != DATAMODEL_LP64) {
42507c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
42517c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
42527c478bd9Sstevel@tonic-gate 		return (NULL);
42537c478bd9Sstevel@tonic-gate 	}
42547c478bd9Sstevel@tonic-gate #endif
42557c478bd9Sstevel@tonic-gate 
42567c478bd9Sstevel@tonic-gate 	mutex_enter(&dpnp->pr_mutex);
42577c478bd9Sstevel@tonic-gate 
42587c478bd9Sstevel@tonic-gate 	if ((vp = dpnp->pr_files[i]) != NULL &&
42597c478bd9Sstevel@tonic-gate 	    !(VTOP(vp)->pr_flags & PR_INVAL)) {
42607c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
42617c478bd9Sstevel@tonic-gate 		mutex_exit(&dpnp->pr_mutex);
42627c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
42637c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
42647c478bd9Sstevel@tonic-gate 		return (vp);
42657c478bd9Sstevel@tonic-gate 	}
42667c478bd9Sstevel@tonic-gate 
42677c478bd9Sstevel@tonic-gate 	/*
42687c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
42697c478bd9Sstevel@tonic-gate 	 * Finish the job.
42707c478bd9Sstevel@tonic-gate 	 */
42717c478bd9Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
42727c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
42737c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
42747c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
42757c478bd9Sstevel@tonic-gate 	pnp->pr_index = i;
42767c478bd9Sstevel@tonic-gate 
42777c478bd9Sstevel@tonic-gate 	dpnp->pr_files[i] = vp = PTOV(pnp);
42787c478bd9Sstevel@tonic-gate 
42797c478bd9Sstevel@tonic-gate 	/*
42807c478bd9Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
42817c478bd9Sstevel@tonic-gate 	 */
42827c478bd9Sstevel@tonic-gate 	if (vp->v_type == VPROC) {
42837c478bd9Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
42847c478bd9Sstevel@tonic-gate 		p->p_plist = vp;
42857c478bd9Sstevel@tonic-gate 	}
42867c478bd9Sstevel@tonic-gate 	mutex_exit(&dpnp->pr_mutex);
42877c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
42887c478bd9Sstevel@tonic-gate 	return (vp);
42897c478bd9Sstevel@tonic-gate }
42907c478bd9Sstevel@tonic-gate 
42917c478bd9Sstevel@tonic-gate /*
4292da29c6a3SDan McDonald  * Lookup one of the process's file vnodes.
42937c478bd9Sstevel@tonic-gate  */
42947c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_fddir(vnode_t * dp,char * comp)42957c478bd9Sstevel@tonic-gate pr_lookup_fddir(vnode_t *dp, char *comp)
42967c478bd9Sstevel@tonic-gate {
42977c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
42987c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
42997c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
43007c478bd9Sstevel@tonic-gate 	proc_t *p;
43017c478bd9Sstevel@tonic-gate 	file_t *fp;
43027c478bd9Sstevel@tonic-gate 	uint_t fd;
43037c478bd9Sstevel@tonic-gate 	int c;
43047c478bd9Sstevel@tonic-gate 
43057c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_FDDIR);
43067c478bd9Sstevel@tonic-gate 
43077c478bd9Sstevel@tonic-gate 	fd = 0;
43087c478bd9Sstevel@tonic-gate 	while ((c = *comp++) != '\0') {
43097c478bd9Sstevel@tonic-gate 		int ofd;
43107c478bd9Sstevel@tonic-gate 		if (c < '0' || c > '9')
43117c478bd9Sstevel@tonic-gate 			return (NULL);
43127c478bd9Sstevel@tonic-gate 		ofd = fd;
43137c478bd9Sstevel@tonic-gate 		fd = 10 * fd + c - '0';
43147c478bd9Sstevel@tonic-gate 		if (fd / 10 != ofd)	/* integer overflow */
43157c478bd9Sstevel@tonic-gate 			return (NULL);
43167c478bd9Sstevel@tonic-gate 	}
43177c478bd9Sstevel@tonic-gate 
43187c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_FD);
43197c478bd9Sstevel@tonic-gate 
43207c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
43217c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
43227c478bd9Sstevel@tonic-gate 		return (NULL);
43237c478bd9Sstevel@tonic-gate 	}
43247c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
43257c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
43267c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
43277c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
43287c478bd9Sstevel@tonic-gate 		return (NULL);
43297c478bd9Sstevel@tonic-gate 	}
43307c478bd9Sstevel@tonic-gate 
4331a02120c4SAndy Fiddaman 	if ((fp = pr_getf(p, fd, NULL)) != NULL) {
43327c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 07111;
43337c478bd9Sstevel@tonic-gate 		if (fp->f_flag & FREAD)
43347c478bd9Sstevel@tonic-gate 			pnp->pr_mode |= 0444;
43357c478bd9Sstevel@tonic-gate 		if (fp->f_flag & FWRITE)
43367c478bd9Sstevel@tonic-gate 			pnp->pr_mode |= 0222;
43377c478bd9Sstevel@tonic-gate 		vp = fp->f_vnode;
43387c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
43397c478bd9Sstevel@tonic-gate 	}
4340a02120c4SAndy Fiddaman 
43417c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
434237e2cd25SPatrick Mooney 	if (fp != NULL) {
434337e2cd25SPatrick Mooney 		pr_releasef(fp);
434437e2cd25SPatrick Mooney 	}
43457c478bd9Sstevel@tonic-gate 
4346a02120c4SAndy Fiddaman 	if (vp == NULL) {
43477c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
4348a02120c4SAndy Fiddaman 		return (NULL);
4349a02120c4SAndy Fiddaman 	}
4350a02120c4SAndy Fiddaman 
43517c478bd9Sstevel@tonic-gate 	/*
43527c478bd9Sstevel@tonic-gate 	 * Fill in the prnode so future references will
43537c478bd9Sstevel@tonic-gate 	 * be able to find the underlying object's vnode.
43547c478bd9Sstevel@tonic-gate 	 * Don't link this prnode into the list of all
43557c478bd9Sstevel@tonic-gate 	 * prnodes for the process; this is a one-use node.
43567c478bd9Sstevel@tonic-gate 	 */
43577c478bd9Sstevel@tonic-gate 	pnp->pr_realvp = vp;
43587c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;		/* needed for prlookup */
43597c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
43607c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
4361e2fc3408SPatrick Mooney 	if (pnp->pr_realvp->v_type == VDIR) {
43627c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
4363e2fc3408SPatrick Mooney 		vp->v_flag |= VTRAVERSE;
4364e2fc3408SPatrick Mooney 	}
4365a02120c4SAndy Fiddaman 
4366a02120c4SAndy Fiddaman 	return (vp);
43677c478bd9Sstevel@tonic-gate }
43687c478bd9Sstevel@tonic-gate 
4369a02120c4SAndy Fiddaman static vnode_t *
pr_lookup_fdinfodir(vnode_t * dp,char * comp)4370a02120c4SAndy Fiddaman pr_lookup_fdinfodir(vnode_t *dp, char *comp)
4371a02120c4SAndy Fiddaman {
4372a02120c4SAndy Fiddaman 	prnode_t *dpnp = VTOP(dp);
4373a02120c4SAndy Fiddaman 	prnode_t *pnp;
4374a02120c4SAndy Fiddaman 	vnode_t *vp = NULL;
4375a02120c4SAndy Fiddaman 	proc_t *p;
4376a02120c4SAndy Fiddaman 	uint_t fd;
4377a02120c4SAndy Fiddaman 	int c;
4378a02120c4SAndy Fiddaman 
4379a02120c4SAndy Fiddaman 	ASSERT(dpnp->pr_type == PR_FDINFODIR);
4380a02120c4SAndy Fiddaman 
4381a02120c4SAndy Fiddaman 	fd = 0;
4382a02120c4SAndy Fiddaman 	while ((c = *comp++) != '\0') {
4383a02120c4SAndy Fiddaman 		int ofd;
4384a02120c4SAndy Fiddaman 		if (c < '0' || c > '9')
4385a02120c4SAndy Fiddaman 			return (NULL);
4386a02120c4SAndy Fiddaman 		ofd = fd;
4387a02120c4SAndy Fiddaman 		fd = 10 * fd + c - '0';
4388a02120c4SAndy Fiddaman 		if (fd / 10 != ofd)	/* integer overflow */
4389a02120c4SAndy Fiddaman 			return (NULL);
4390a02120c4SAndy Fiddaman 	}
4391a02120c4SAndy Fiddaman 
4392a02120c4SAndy Fiddaman 	pnp = prgetnode(dp, PR_FDINFO);
4393a02120c4SAndy Fiddaman 
4394a02120c4SAndy Fiddaman 	if (prlock(dpnp, ZNO) != 0) {
4395a02120c4SAndy Fiddaman 		prfreenode(pnp);
4396a02120c4SAndy Fiddaman 		return (NULL);
4397a02120c4SAndy Fiddaman 	}
4398a02120c4SAndy Fiddaman 	p = dpnp->pr_common->prc_proc;
4399a02120c4SAndy Fiddaman 	if ((p->p_flag & SSYS) || p->p_as == &kas) {
4400a02120c4SAndy Fiddaman 		prunlock(dpnp);
4401a02120c4SAndy Fiddaman 		prfreenode(pnp);
4402a02120c4SAndy Fiddaman 		return (NULL);
4403a02120c4SAndy Fiddaman 	}
4404a02120c4SAndy Fiddaman 
4405a02120c4SAndy Fiddaman 	/*
4406a02120c4SAndy Fiddaman 	 * Don't link this prnode into the list of all
4407a02120c4SAndy Fiddaman 	 * prnodes for the process; this is a one-use node.
4408a02120c4SAndy Fiddaman 	 * Unlike the FDDIR case, the underlying vnode is not stored in
4409a02120c4SAndy Fiddaman 	 * pnp->pr_realvp. Instead, the fd number is stored in pnp->pr_index
4410a02120c4SAndy Fiddaman 	 * and used by pr_read_fdinfo() to return information for the right
4411a02120c4SAndy Fiddaman 	 * file descriptor.
4412a02120c4SAndy Fiddaman 	 */
4413a02120c4SAndy Fiddaman 	pnp->pr_common = dpnp->pr_common;
4414a02120c4SAndy Fiddaman 	pnp->pr_pcommon = dpnp->pr_pcommon;
4415a02120c4SAndy Fiddaman 	pnp->pr_parent = dp;
4416a02120c4SAndy Fiddaman 	pnp->pr_index = fd;
4417a02120c4SAndy Fiddaman 	VN_HOLD(dp);
4418a02120c4SAndy Fiddaman 	prunlock(dpnp);
4419a02120c4SAndy Fiddaman 	vp = PTOV(pnp);
4420a02120c4SAndy Fiddaman 
44217c478bd9Sstevel@tonic-gate 	return (vp);
44227c478bd9Sstevel@tonic-gate }
44237c478bd9Sstevel@tonic-gate 
44247c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_pathdir(vnode_t * dp,char * comp)44257c478bd9Sstevel@tonic-gate pr_lookup_pathdir(vnode_t *dp, char *comp)
44267c478bd9Sstevel@tonic-gate {
44277c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
44287c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
44297c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
44307c478bd9Sstevel@tonic-gate 	proc_t *p;
44317c478bd9Sstevel@tonic-gate 	uint_t fd, flags = 0;
44327c478bd9Sstevel@tonic-gate 	int c;
44337c478bd9Sstevel@tonic-gate 	uf_entry_t *ufp;
44347c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
44357c478bd9Sstevel@tonic-gate 	enum { NAME_FD, NAME_OBJECT, NAME_ROOT, NAME_CWD, NAME_UNKNOWN } type;
44367c478bd9Sstevel@tonic-gate 	char *tmp;
44377c478bd9Sstevel@tonic-gate 	int idx;
44387c478bd9Sstevel@tonic-gate 	struct seg *seg;
44397c478bd9Sstevel@tonic-gate 	struct as *as = NULL;
44407c478bd9Sstevel@tonic-gate 	vattr_t vattr;
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_PATHDIR);
44437c478bd9Sstevel@tonic-gate 
44447c478bd9Sstevel@tonic-gate 	/*
44457c478bd9Sstevel@tonic-gate 	 * First, check if this is a numeric entry, in which case we have a
44467c478bd9Sstevel@tonic-gate 	 * file descriptor.
44477c478bd9Sstevel@tonic-gate 	 */
44487c478bd9Sstevel@tonic-gate 	fd = 0;
44497c478bd9Sstevel@tonic-gate 	type = NAME_FD;
44507c478bd9Sstevel@tonic-gate 	tmp = comp;
44517c478bd9Sstevel@tonic-gate 	while ((c = *tmp++) != '\0') {
44527c478bd9Sstevel@tonic-gate 		int ofd;
44537c478bd9Sstevel@tonic-gate 		if (c < '0' || c > '9') {
44547c478bd9Sstevel@tonic-gate 			type = NAME_UNKNOWN;
44557c478bd9Sstevel@tonic-gate 			break;
44567c478bd9Sstevel@tonic-gate 		}
44577c478bd9Sstevel@tonic-gate 		ofd = fd;
44587c478bd9Sstevel@tonic-gate 		fd = 10*fd + c - '0';
44597c478bd9Sstevel@tonic-gate 		if (fd/10 != ofd) {	/* integer overflow */
44607c478bd9Sstevel@tonic-gate 			type = NAME_UNKNOWN;
44617c478bd9Sstevel@tonic-gate 			break;
44627c478bd9Sstevel@tonic-gate 		}
44637c478bd9Sstevel@tonic-gate 	}
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 	/*
44667c478bd9Sstevel@tonic-gate 	 * Next, see if it is one of the special values {root, cwd}.
44677c478bd9Sstevel@tonic-gate 	 */
44687c478bd9Sstevel@tonic-gate 	if (type == NAME_UNKNOWN) {
44697c478bd9Sstevel@tonic-gate 		if (strcmp(comp, "root") == 0)
44707c478bd9Sstevel@tonic-gate 			type = NAME_ROOT;
44717c478bd9Sstevel@tonic-gate 		else if (strcmp(comp, "cwd") == 0)
44727c478bd9Sstevel@tonic-gate 			type = NAME_CWD;
44737c478bd9Sstevel@tonic-gate 	}
44747c478bd9Sstevel@tonic-gate 
44757c478bd9Sstevel@tonic-gate 	/*
44767c478bd9Sstevel@tonic-gate 	 * Grab the necessary data from the process
44777c478bd9Sstevel@tonic-gate 	 */
44787c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0)
44797c478bd9Sstevel@tonic-gate 		return (NULL);
44807c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
44817c478bd9Sstevel@tonic-gate 
44827c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
44837c478bd9Sstevel@tonic-gate 
44847c478bd9Sstevel@tonic-gate 	switch (type) {
44857c478bd9Sstevel@tonic-gate 	case NAME_ROOT:
44867c478bd9Sstevel@tonic-gate 		if ((vp = PTOU(p)->u_rdir) == NULL)
44877c478bd9Sstevel@tonic-gate 			vp = p->p_zone->zone_rootvp;
44887c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
44897c478bd9Sstevel@tonic-gate 		break;
44907c478bd9Sstevel@tonic-gate 	case NAME_CWD:
44917c478bd9Sstevel@tonic-gate 		vp = PTOU(p)->u_cdir;
44927c478bd9Sstevel@tonic-gate 		VN_HOLD(vp);
44937c478bd9Sstevel@tonic-gate 		break;
44947c478bd9Sstevel@tonic-gate 	default:
44957c478bd9Sstevel@tonic-gate 		if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
44967c478bd9Sstevel@tonic-gate 			prunlock(dpnp);
44977c478bd9Sstevel@tonic-gate 			return (NULL);
44987c478bd9Sstevel@tonic-gate 		}
44997c478bd9Sstevel@tonic-gate 	}
45007c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 	/*
45037c478bd9Sstevel@tonic-gate 	 * Determine if this is an object entry
45047c478bd9Sstevel@tonic-gate 	 */
45057c478bd9Sstevel@tonic-gate 	if (type == NAME_UNKNOWN) {
45067c478bd9Sstevel@tonic-gate 		/*
45077c478bd9Sstevel@tonic-gate 		 * Start with the inode index immediately after the number of
45087c478bd9Sstevel@tonic-gate 		 * files.
45097c478bd9Sstevel@tonic-gate 		 */
45107c478bd9Sstevel@tonic-gate 		mutex_enter(&fip->fi_lock);
45117c478bd9Sstevel@tonic-gate 		idx = fip->fi_nfiles + 4;
45127c478bd9Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
45137c478bd9Sstevel@tonic-gate 
45147c478bd9Sstevel@tonic-gate 		if (strcmp(comp, "a.out") == 0) {
45157c478bd9Sstevel@tonic-gate 			if (p->p_execdir != NULL) {
45167c478bd9Sstevel@tonic-gate 				vp = p->p_execdir;
45177c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
45187c478bd9Sstevel@tonic-gate 				type = NAME_OBJECT;
45197c478bd9Sstevel@tonic-gate 				flags |= PR_AOUT;
45207c478bd9Sstevel@tonic-gate 			} else {
45217c478bd9Sstevel@tonic-gate 				vp = p->p_exec;
45227c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
45237c478bd9Sstevel@tonic-gate 				type = NAME_OBJECT;
45247c478bd9Sstevel@tonic-gate 			}
45257c478bd9Sstevel@tonic-gate 		} else {
4526dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_READER);
45277c478bd9Sstevel@tonic-gate 			if ((seg = AS_SEGFIRST(as)) != NULL) {
45287c478bd9Sstevel@tonic-gate 				do {
45297c478bd9Sstevel@tonic-gate 					/*
45307c478bd9Sstevel@tonic-gate 					 * Manufacture a filename for the
45317c478bd9Sstevel@tonic-gate 					 * "object" directory.
45327c478bd9Sstevel@tonic-gate 					 */
45337c478bd9Sstevel@tonic-gate 					vattr.va_mask = AT_FSID|AT_NODEID;
45347c478bd9Sstevel@tonic-gate 					if (seg->s_ops == &segvn_ops &&
45357c478bd9Sstevel@tonic-gate 					    SEGOP_GETVP(seg, seg->s_base, &vp)
45367c478bd9Sstevel@tonic-gate 					    == 0 &&
45377c478bd9Sstevel@tonic-gate 					    vp != NULL && vp->v_type == VREG &&
4538da6c28aaSamw 					    VOP_GETATTR(vp, &vattr, 0, CRED(),
4539da6c28aaSamw 					    NULL) == 0) {
45407c478bd9Sstevel@tonic-gate 						char name[64];
45417c478bd9Sstevel@tonic-gate 
45427c478bd9Sstevel@tonic-gate 						if (vp == p->p_exec)
45437c478bd9Sstevel@tonic-gate 							continue;
45447c478bd9Sstevel@tonic-gate 						idx++;
45457c478bd9Sstevel@tonic-gate 						pr_object_name(name, vp,
45467c478bd9Sstevel@tonic-gate 						    &vattr);
45477c478bd9Sstevel@tonic-gate 						if (strcmp(name, comp) == 0)
45487c478bd9Sstevel@tonic-gate 							break;
45497c478bd9Sstevel@tonic-gate 					}
45507c478bd9Sstevel@tonic-gate 				} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
45517c478bd9Sstevel@tonic-gate 			}
45527c478bd9Sstevel@tonic-gate 
45537c478bd9Sstevel@tonic-gate 			if (seg == NULL) {
45547c478bd9Sstevel@tonic-gate 				vp = NULL;
45557c478bd9Sstevel@tonic-gate 			} else {
45567c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
45577c478bd9Sstevel@tonic-gate 				type = NAME_OBJECT;
45587c478bd9Sstevel@tonic-gate 			}
45597c478bd9Sstevel@tonic-gate 
4560dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
45617c478bd9Sstevel@tonic-gate 		}
45627c478bd9Sstevel@tonic-gate 	}
45637c478bd9Sstevel@tonic-gate 
45647c478bd9Sstevel@tonic-gate 
45657c478bd9Sstevel@tonic-gate 	switch (type) {
45667c478bd9Sstevel@tonic-gate 	case NAME_FD:
45677c478bd9Sstevel@tonic-gate 		mutex_enter(&fip->fi_lock);
45687c478bd9Sstevel@tonic-gate 		if (fd < fip->fi_nfiles) {
45697c478bd9Sstevel@tonic-gate 			UF_ENTER(ufp, fip, fd);
45707c478bd9Sstevel@tonic-gate 			if (ufp->uf_file != NULL) {
45717c478bd9Sstevel@tonic-gate 				vp = ufp->uf_file->f_vnode;
45727c478bd9Sstevel@tonic-gate 				VN_HOLD(vp);
45737c478bd9Sstevel@tonic-gate 			}
45747c478bd9Sstevel@tonic-gate 			UF_EXIT(ufp);
45757c478bd9Sstevel@tonic-gate 		}
45767c478bd9Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
45777c478bd9Sstevel@tonic-gate 		idx = fd + 4;
45787c478bd9Sstevel@tonic-gate 		break;
45797c478bd9Sstevel@tonic-gate 	case NAME_ROOT:
45807c478bd9Sstevel@tonic-gate 		idx = 2;
45817c478bd9Sstevel@tonic-gate 		break;
45827c478bd9Sstevel@tonic-gate 	case NAME_CWD:
45837c478bd9Sstevel@tonic-gate 		idx = 3;
45847c478bd9Sstevel@tonic-gate 		break;
45857c478bd9Sstevel@tonic-gate 	case NAME_OBJECT:
45867c478bd9Sstevel@tonic-gate 	case NAME_UNKNOWN:
45877c478bd9Sstevel@tonic-gate 		/* Nothing to do */
45887c478bd9Sstevel@tonic-gate 		break;
45897c478bd9Sstevel@tonic-gate 	}
45907c478bd9Sstevel@tonic-gate 
45917c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
45927c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
45937c478bd9Sstevel@tonic-gate 
45947c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
45957c478bd9Sstevel@tonic-gate 		pnp = prgetnode(dp, PR_PATH);
45967c478bd9Sstevel@tonic-gate 
45977c478bd9Sstevel@tonic-gate 		pnp->pr_flags |= flags;
45987c478bd9Sstevel@tonic-gate 		pnp->pr_common = dpnp->pr_common;
45997c478bd9Sstevel@tonic-gate 		pnp->pr_pcommon = dpnp->pr_pcommon;
46007c478bd9Sstevel@tonic-gate 		pnp->pr_realvp = vp;
46017c478bd9Sstevel@tonic-gate 		pnp->pr_parent = dp;		/* needed for prlookup */
46027c478bd9Sstevel@tonic-gate 		pnp->pr_ino = pmkino(idx, dpnp->pr_common->prc_slot, PR_PATH);
46037c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
46047c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
46057c478bd9Sstevel@tonic-gate 		vp->v_type = VLNK;
46067c478bd9Sstevel@tonic-gate 	}
46077c478bd9Sstevel@tonic-gate 
46087c478bd9Sstevel@tonic-gate 	return (vp);
46097c478bd9Sstevel@tonic-gate }
46107c478bd9Sstevel@tonic-gate 
46117c478bd9Sstevel@tonic-gate /*
46127c478bd9Sstevel@tonic-gate  * Look up one of the process's active templates.
46137c478bd9Sstevel@tonic-gate  */
46147c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_tmpldir(vnode_t * dp,char * comp)46157c478bd9Sstevel@tonic-gate pr_lookup_tmpldir(vnode_t *dp, char *comp)
46167c478bd9Sstevel@tonic-gate {
46177c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
46187c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
46197c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
46207c478bd9Sstevel@tonic-gate 	proc_t *p;
46217c478bd9Sstevel@tonic-gate 	int i;
46227c478bd9Sstevel@tonic-gate 
46237c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_TMPLDIR);
46247c478bd9Sstevel@tonic-gate 
46257c478bd9Sstevel@tonic-gate 	for (i = 0; i < ct_ntypes; i++)
46267c478bd9Sstevel@tonic-gate 		if (strcmp(comp, ct_types[i]->ct_type_name) == 0)
46277c478bd9Sstevel@tonic-gate 			break;
46287c478bd9Sstevel@tonic-gate 	if (i == ct_ntypes)
46297c478bd9Sstevel@tonic-gate 		return (NULL);
46307c478bd9Sstevel@tonic-gate 
46317c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_TMPL);
46327c478bd9Sstevel@tonic-gate 
46337c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
46347c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
46357c478bd9Sstevel@tonic-gate 		return (NULL);
46367c478bd9Sstevel@tonic-gate 	}
46377c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
46387c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas ||
46397c478bd9Sstevel@tonic-gate 	    (dpnp->pr_common->prc_flags & (PRC_DESTROY | PRC_LWP)) != PRC_LWP) {
46407c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
46417c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
46427c478bd9Sstevel@tonic-gate 		return (NULL);
46437c478bd9Sstevel@tonic-gate 	}
46447c478bd9Sstevel@tonic-gate 	if (ttolwp(dpnp->pr_common->prc_thread)->lwp_ct_active[i] != NULL) {
46457c478bd9Sstevel@tonic-gate 		pnp->pr_common = dpnp->pr_common;
46467c478bd9Sstevel@tonic-gate 		pnp->pr_pcommon = dpnp->pr_pcommon;
46477c478bd9Sstevel@tonic-gate 		pnp->pr_parent = dp;
46487c478bd9Sstevel@tonic-gate 		pnp->pr_cttype = i;
46497c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
46507c478bd9Sstevel@tonic-gate 		vp = PTOV(pnp);
46517c478bd9Sstevel@tonic-gate 	} else {
46527c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
46537c478bd9Sstevel@tonic-gate 	}
46547c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
46557c478bd9Sstevel@tonic-gate 
46567c478bd9Sstevel@tonic-gate 	return (vp);
46577c478bd9Sstevel@tonic-gate }
46587c478bd9Sstevel@tonic-gate 
46597c478bd9Sstevel@tonic-gate /*
46607c478bd9Sstevel@tonic-gate  * Look up one of the contracts owned by the process.
46617c478bd9Sstevel@tonic-gate  */
46627c478bd9Sstevel@tonic-gate static vnode_t *
pr_lookup_ctdir(vnode_t * dp,char * comp)46637c478bd9Sstevel@tonic-gate pr_lookup_ctdir(vnode_t *dp, char *comp)
46647c478bd9Sstevel@tonic-gate {
46657c478bd9Sstevel@tonic-gate 	prnode_t *dpnp = VTOP(dp);
46667c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
46677c478bd9Sstevel@tonic-gate 	vnode_t *vp = NULL;
46687c478bd9Sstevel@tonic-gate 	proc_t *p;
46697c478bd9Sstevel@tonic-gate 	id_t id = 0;
46707c478bd9Sstevel@tonic-gate 	contract_t *ct;
46717c478bd9Sstevel@tonic-gate 	int c;
46727c478bd9Sstevel@tonic-gate 
46737c478bd9Sstevel@tonic-gate 	ASSERT(dpnp->pr_type == PR_CTDIR);
46747c478bd9Sstevel@tonic-gate 
46757c478bd9Sstevel@tonic-gate 	while ((c = *comp++) != '\0') {
46767c478bd9Sstevel@tonic-gate 		id_t oid;
46777c478bd9Sstevel@tonic-gate 		if (c < '0' || c > '9')
46787c478bd9Sstevel@tonic-gate 			return (NULL);
46797c478bd9Sstevel@tonic-gate 		oid = id;
46807c478bd9Sstevel@tonic-gate 		id = 10 * id + c - '0';
46817c478bd9Sstevel@tonic-gate 		if (id / 10 != oid)	/* integer overflow */
46827c478bd9Sstevel@tonic-gate 			return (NULL);
46837c478bd9Sstevel@tonic-gate 	}
46847c478bd9Sstevel@tonic-gate 
46857c478bd9Sstevel@tonic-gate 	/*
46867c478bd9Sstevel@tonic-gate 	 * Search all contracts; we'll filter below.
46877c478bd9Sstevel@tonic-gate 	 */
46887c478bd9Sstevel@tonic-gate 	ct = contract_ptr(id, GLOBAL_ZONEUNIQID);
46897c478bd9Sstevel@tonic-gate 	if (ct == NULL)
46907c478bd9Sstevel@tonic-gate 		return (NULL);
46917c478bd9Sstevel@tonic-gate 
46927c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_CT);
46937c478bd9Sstevel@tonic-gate 
46947c478bd9Sstevel@tonic-gate 	if (prlock(dpnp, ZNO) != 0) {
46957c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
46967c478bd9Sstevel@tonic-gate 		contract_rele(ct);
46977c478bd9Sstevel@tonic-gate 		return (NULL);
46987c478bd9Sstevel@tonic-gate 	}
46997c478bd9Sstevel@tonic-gate 	p = dpnp->pr_common->prc_proc;
47007c478bd9Sstevel@tonic-gate 	/*
47017c478bd9Sstevel@tonic-gate 	 * We only allow lookups of contracts owned by this process, or,
47027c478bd9Sstevel@tonic-gate 	 * if we are zsched and this is a zone's procfs, contracts on
47037c478bd9Sstevel@tonic-gate 	 * stuff in the zone which are held by processes or contracts
47047c478bd9Sstevel@tonic-gate 	 * outside the zone.  (see logic in contract_status_common)
47057c478bd9Sstevel@tonic-gate 	 */
47067c478bd9Sstevel@tonic-gate 	if ((ct->ct_owner != p) &&
4707fa9e4066Sahrens 	    !(p == VTOZONE(dp)->zone_zsched && ct->ct_state < CTS_ORPHAN &&
4708fa9e4066Sahrens 	    VTOZONE(dp)->zone_uniqid == contract_getzuniqid(ct) &&
4709fa9e4066Sahrens 	    VTOZONE(dp)->zone_uniqid != GLOBAL_ZONEUNIQID &&
47107c478bd9Sstevel@tonic-gate 	    ct->ct_czuniqid == GLOBAL_ZONEUNIQID)) {
47117c478bd9Sstevel@tonic-gate 		prunlock(dpnp);
47127c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
47137c478bd9Sstevel@tonic-gate 		contract_rele(ct);
47147c478bd9Sstevel@tonic-gate 		return (NULL);
47157c478bd9Sstevel@tonic-gate 	}
47167c478bd9Sstevel@tonic-gate 	pnp->pr_common = dpnp->pr_common;
47177c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = dpnp->pr_pcommon;
47187c478bd9Sstevel@tonic-gate 	pnp->pr_contract = ct;
47197c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
47207c478bd9Sstevel@tonic-gate 	pnp->pr_ino = pmkino(id, pnp->pr_common->prc_slot, PR_CT);
47217c478bd9Sstevel@tonic-gate 	VN_HOLD(dp);
47227c478bd9Sstevel@tonic-gate 	prunlock(dpnp);
47237c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
47247c478bd9Sstevel@tonic-gate 
47257c478bd9Sstevel@tonic-gate 	return (vp);
47267c478bd9Sstevel@tonic-gate }
47277c478bd9Sstevel@tonic-gate 
47287c478bd9Sstevel@tonic-gate /*
47297c478bd9Sstevel@tonic-gate  * Construct an lwp vnode for the old /proc interface.
47307c478bd9Sstevel@tonic-gate  * We stand on our head to make the /proc plumbing correct.
47317c478bd9Sstevel@tonic-gate  */
47327c478bd9Sstevel@tonic-gate vnode_t *
prlwpnode(prnode_t * pnp,uint_t tid)47337c478bd9Sstevel@tonic-gate prlwpnode(prnode_t *pnp, uint_t tid)
47347c478bd9Sstevel@tonic-gate {
47357c478bd9Sstevel@tonic-gate 	char comp[12];
47367c478bd9Sstevel@tonic-gate 	vnode_t *dp;
47377c478bd9Sstevel@tonic-gate 	vnode_t *vp;
47387c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
47397c478bd9Sstevel@tonic-gate 	proc_t *p;
47407c478bd9Sstevel@tonic-gate 
47417c478bd9Sstevel@tonic-gate 	/*
47427c478bd9Sstevel@tonic-gate 	 * Lookup the /proc/<pid>/lwp/<lwpid> directory vnode.
47437c478bd9Sstevel@tonic-gate 	 */
47447c478bd9Sstevel@tonic-gate 	if (pnp->pr_type == PR_PIDFILE) {
47457c478bd9Sstevel@tonic-gate 		dp = pnp->pr_parent;		/* /proc/<pid> */
47467c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
47477c478bd9Sstevel@tonic-gate 		vp = pr_lookup_piddir(dp, "lwp");
47487c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
47497c478bd9Sstevel@tonic-gate 		if ((dp = vp) == NULL)		/* /proc/<pid>/lwp */
47507c478bd9Sstevel@tonic-gate 			return (NULL);
47517c478bd9Sstevel@tonic-gate 	} else if (pnp->pr_type == PR_LWPIDFILE) {
47527c478bd9Sstevel@tonic-gate 		dp = pnp->pr_parent;		/* /proc/<pid>/lwp/<lwpid> */
47537c478bd9Sstevel@tonic-gate 		dp = VTOP(dp)->pr_parent;	/* /proc/<pid>/lwp */
47547c478bd9Sstevel@tonic-gate 		VN_HOLD(dp);
47557c478bd9Sstevel@tonic-gate 	} else {
47567c478bd9Sstevel@tonic-gate 		return (NULL);
47577c478bd9Sstevel@tonic-gate 	}
47587c478bd9Sstevel@tonic-gate 
47597c478bd9Sstevel@tonic-gate 	(void) pr_u32tos(tid, comp, sizeof (comp));
47607c478bd9Sstevel@tonic-gate 	vp = pr_lookup_lwpdir(dp, comp);
47617c478bd9Sstevel@tonic-gate 	VN_RELE(dp);
47627c478bd9Sstevel@tonic-gate 	if ((dp = vp) == NULL)
47637c478bd9Sstevel@tonic-gate 		return (NULL);
47647c478bd9Sstevel@tonic-gate 
47657c478bd9Sstevel@tonic-gate 	pnp = prgetnode(dp, PR_LWPIDFILE);
47667c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
47677c478bd9Sstevel@tonic-gate 
47687c478bd9Sstevel@tonic-gate 	/*
47697c478bd9Sstevel@tonic-gate 	 * prgetnode() initialized most of the prnode.
47707c478bd9Sstevel@tonic-gate 	 * Finish the job.
47717c478bd9Sstevel@tonic-gate 	 */
47727c478bd9Sstevel@tonic-gate 	pcp = VTOP(dp)->pr_common;
47737c478bd9Sstevel@tonic-gate 	pnp->pr_ino = ptoi(pcp->prc_pid);
47747c478bd9Sstevel@tonic-gate 	pnp->pr_common = pcp;
47757c478bd9Sstevel@tonic-gate 	pnp->pr_pcommon = VTOP(dp)->pr_pcommon;
47767c478bd9Sstevel@tonic-gate 	pnp->pr_parent = dp;
47777c478bd9Sstevel@tonic-gate 	/*
47787c478bd9Sstevel@tonic-gate 	 * Link new vnode into list of all /proc vnodes for the process.
47797c478bd9Sstevel@tonic-gate 	 */
47807c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
47817c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
47827c478bd9Sstevel@tonic-gate 	if (p == NULL) {
47837c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
47847c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
47857c478bd9Sstevel@tonic-gate 		vp = NULL;
47867c478bd9Sstevel@tonic-gate 	} else if (pcp->prc_thread == NULL) {
47877c478bd9Sstevel@tonic-gate 		prunlock(pnp);
47887c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
47897c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
47907c478bd9Sstevel@tonic-gate 		vp = NULL;
47917c478bd9Sstevel@tonic-gate 	} else {
47927c478bd9Sstevel@tonic-gate 		pnp->pr_next = p->p_plist;
47937c478bd9Sstevel@tonic-gate 		p->p_plist = vp;
47947c478bd9Sstevel@tonic-gate 		prunlock(pnp);
47957c478bd9Sstevel@tonic-gate 	}
47967c478bd9Sstevel@tonic-gate 
47977c478bd9Sstevel@tonic-gate 	return (vp);
47987c478bd9Sstevel@tonic-gate }
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate #if defined(DEBUG)
48017c478bd9Sstevel@tonic-gate 
48027c478bd9Sstevel@tonic-gate static	uint32_t nprnode;
48037c478bd9Sstevel@tonic-gate static	uint32_t nprcommon;
48047c478bd9Sstevel@tonic-gate 
48051a5e258fSJosef 'Jeff' Sipek #define	INCREMENT(x)	atomic_inc_32(&x);
48061a5e258fSJosef 'Jeff' Sipek #define	DECREMENT(x)	atomic_dec_32(&x);
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate #else
48097c478bd9Sstevel@tonic-gate 
48107c478bd9Sstevel@tonic-gate #define	INCREMENT(x)
48117c478bd9Sstevel@tonic-gate #define	DECREMENT(x)
48127c478bd9Sstevel@tonic-gate 
48137c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
48147c478bd9Sstevel@tonic-gate 
48157c478bd9Sstevel@tonic-gate /*
48167c478bd9Sstevel@tonic-gate  * New /proc vnode required; allocate it and fill in most of the fields.
48177c478bd9Sstevel@tonic-gate  */
48187c478bd9Sstevel@tonic-gate prnode_t *
prgetnode(vnode_t * dp,prnodetype_t type)48197c478bd9Sstevel@tonic-gate prgetnode(vnode_t *dp, prnodetype_t type)
48207c478bd9Sstevel@tonic-gate {
48217c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
48227c478bd9Sstevel@tonic-gate 	prcommon_t *pcp;
48237c478bd9Sstevel@tonic-gate 	vnode_t *vp;
48247c478bd9Sstevel@tonic-gate 	ulong_t nfiles;
48257c478bd9Sstevel@tonic-gate 
48267c478bd9Sstevel@tonic-gate 	INCREMENT(nprnode);
48277c478bd9Sstevel@tonic-gate 	pnp = kmem_zalloc(sizeof (prnode_t), KM_SLEEP);
48287c478bd9Sstevel@tonic-gate 
48297c478bd9Sstevel@tonic-gate 	mutex_init(&pnp->pr_mutex, NULL, MUTEX_DEFAULT, NULL);
48307c478bd9Sstevel@tonic-gate 	pnp->pr_type = type;
48317c478bd9Sstevel@tonic-gate 
48327c478bd9Sstevel@tonic-gate 	pnp->pr_vnode = vn_alloc(KM_SLEEP);
48337c478bd9Sstevel@tonic-gate 
48347c478bd9Sstevel@tonic-gate 	vp = PTOV(pnp);
48357c478bd9Sstevel@tonic-gate 	vp->v_flag = VNOCACHE|VNOMAP|VNOSWAP|VNOMOUNT;
48367c478bd9Sstevel@tonic-gate 	vn_setops(vp, prvnodeops);
48377c478bd9Sstevel@tonic-gate 	vp->v_vfsp = dp->v_vfsp;
48387c478bd9Sstevel@tonic-gate 	vp->v_type = VPROC;
48397c478bd9Sstevel@tonic-gate 	vp->v_data = (caddr_t)pnp;
48407c478bd9Sstevel@tonic-gate 
48417c478bd9Sstevel@tonic-gate 	switch (type) {
48427c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:
48437c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
48447c478bd9Sstevel@tonic-gate 		/*
48457c478bd9Sstevel@tonic-gate 		 * We need a prcommon and a files array for each of these.
48467c478bd9Sstevel@tonic-gate 		 */
48477c478bd9Sstevel@tonic-gate 		INCREMENT(nprcommon);
48487c478bd9Sstevel@tonic-gate 
48497c478bd9Sstevel@tonic-gate 		pcp = kmem_zalloc(sizeof (prcommon_t), KM_SLEEP);
48507c478bd9Sstevel@tonic-gate 		pcp->prc_refcnt = 1;
48517c478bd9Sstevel@tonic-gate 		pnp->pr_common = pcp;
48527c478bd9Sstevel@tonic-gate 		mutex_init(&pcp->prc_mutex, NULL, MUTEX_DEFAULT, NULL);
48537c478bd9Sstevel@tonic-gate 		cv_init(&pcp->prc_wait, NULL, CV_DEFAULT, NULL);
48547c478bd9Sstevel@tonic-gate 
48557c478bd9Sstevel@tonic-gate 		nfiles = (type == PR_PIDDIR)? NPIDDIRFILES : NLWPIDDIRFILES;
48567c478bd9Sstevel@tonic-gate 		pnp->pr_files =
48577c478bd9Sstevel@tonic-gate 		    kmem_zalloc(nfiles * sizeof (vnode_t *), KM_SLEEP);
48587c478bd9Sstevel@tonic-gate 
48597c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
48607c478bd9Sstevel@tonic-gate 		/*
48617c478bd9Sstevel@tonic-gate 		 * Mode should be read-search by all, but we cannot so long
48627c478bd9Sstevel@tonic-gate 		 * as we must support compatibility mode with old /proc.
48637c478bd9Sstevel@tonic-gate 		 * Make /proc/<pid> be read by owner only, search by all.
48647c478bd9Sstevel@tonic-gate 		 * Make /proc/<pid>/lwp/<lwpid> read-search by all.  Also,
48657c478bd9Sstevel@tonic-gate 		 * set VDIROPEN on /proc/<pid> so it can be opened for writing.
48667c478bd9Sstevel@tonic-gate 		 */
48677c478bd9Sstevel@tonic-gate 		if (type == PR_PIDDIR) {
48687c478bd9Sstevel@tonic-gate 			/* kludge for old /proc interface */
48697c478bd9Sstevel@tonic-gate 			prnode_t *xpnp = prgetnode(dp, PR_PIDFILE);
48707c478bd9Sstevel@tonic-gate 			pnp->pr_pidfile = PTOV(xpnp);
48717c478bd9Sstevel@tonic-gate 			pnp->pr_mode = 0511;
48727c478bd9Sstevel@tonic-gate 			vp->v_flag |= VDIROPEN;
48737c478bd9Sstevel@tonic-gate 		} else {
48747c478bd9Sstevel@tonic-gate 			pnp->pr_mode = 0555;
48757c478bd9Sstevel@tonic-gate 		}
48767c478bd9Sstevel@tonic-gate 
48777c478bd9Sstevel@tonic-gate 		break;
48787c478bd9Sstevel@tonic-gate 
48797c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
48807c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
48817c478bd9Sstevel@tonic-gate 	case PR_FDDIR:
4882a02120c4SAndy Fiddaman 	case PR_FDINFODIR:
48837c478bd9Sstevel@tonic-gate 	case PR_OBJECTDIR:
48847c478bd9Sstevel@tonic-gate 	case PR_PATHDIR:
48857c478bd9Sstevel@tonic-gate 	case PR_CTDIR:
48867c478bd9Sstevel@tonic-gate 	case PR_TMPLDIR:
48877c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
48887c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0500;	/* read-search by owner only */
48897c478bd9Sstevel@tonic-gate 		break;
48907c478bd9Sstevel@tonic-gate 
48917c478bd9Sstevel@tonic-gate 	case PR_CT:
48927c478bd9Sstevel@tonic-gate 		vp->v_type = VLNK;
48937c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0500;	/* read-search by owner only */
48947c478bd9Sstevel@tonic-gate 		break;
48957c478bd9Sstevel@tonic-gate 
48967c478bd9Sstevel@tonic-gate 	case PR_PATH:
48977c478bd9Sstevel@tonic-gate 	case PR_SELF:
48987c478bd9Sstevel@tonic-gate 		vp->v_type = VLNK;
48997c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0777;
49007c478bd9Sstevel@tonic-gate 		break;
49017c478bd9Sstevel@tonic-gate 
49027c478bd9Sstevel@tonic-gate 	case PR_LWPDIR:
49037c478bd9Sstevel@tonic-gate 		vp->v_type = VDIR;
49047c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0555;	/* read-search by all */
49057c478bd9Sstevel@tonic-gate 		break;
49067c478bd9Sstevel@tonic-gate 
49077c478bd9Sstevel@tonic-gate 	case PR_AS:
49087c478bd9Sstevel@tonic-gate 	case PR_TMPL:
49097c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0600;	/* read-write by owner only */
49107c478bd9Sstevel@tonic-gate 		break;
49117c478bd9Sstevel@tonic-gate 
49127c478bd9Sstevel@tonic-gate 	case PR_CTL:
49137c478bd9Sstevel@tonic-gate 	case PR_LWPCTL:
49147c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0200;	/* write-only by owner only */
49157c478bd9Sstevel@tonic-gate 		break;
49167c478bd9Sstevel@tonic-gate 
49177c478bd9Sstevel@tonic-gate 	case PR_PIDFILE:
49187c478bd9Sstevel@tonic-gate 	case PR_LWPIDFILE:
49197c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0600;	/* read-write by owner only */
49207c478bd9Sstevel@tonic-gate 		break;
49217c478bd9Sstevel@tonic-gate 
4922ab618543SJohn Levon 	case PR_LWPNAME:
4923ab618543SJohn Levon 		pnp->pr_mode = 0644;	/* readable by all + owner can write */
4924ab618543SJohn Levon 		break;
4925ab618543SJohn Levon 
49267c478bd9Sstevel@tonic-gate 	case PR_PSINFO:
49277c478bd9Sstevel@tonic-gate 	case PR_LPSINFO:
49287c478bd9Sstevel@tonic-gate 	case PR_LWPSINFO:
49297c478bd9Sstevel@tonic-gate 	case PR_USAGE:
49307c478bd9Sstevel@tonic-gate 	case PR_LUSAGE:
49317c478bd9Sstevel@tonic-gate 	case PR_LWPUSAGE:
49327c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0444;	/* read-only by all */
49337c478bd9Sstevel@tonic-gate 		break;
49347c478bd9Sstevel@tonic-gate 
49357c478bd9Sstevel@tonic-gate 	default:
49367c478bd9Sstevel@tonic-gate 		pnp->pr_mode = 0400;	/* read-only by owner only */
49377c478bd9Sstevel@tonic-gate 		break;
49387c478bd9Sstevel@tonic-gate 	}
49397c478bd9Sstevel@tonic-gate 	vn_exists(vp);
49407c478bd9Sstevel@tonic-gate 	return (pnp);
49417c478bd9Sstevel@tonic-gate }
49427c478bd9Sstevel@tonic-gate 
49437c478bd9Sstevel@tonic-gate /*
49447c478bd9Sstevel@tonic-gate  * Free the storage obtained from prgetnode().
49457c478bd9Sstevel@tonic-gate  */
49467c478bd9Sstevel@tonic-gate void
prfreenode(prnode_t * pnp)49477c478bd9Sstevel@tonic-gate prfreenode(prnode_t *pnp)
49487c478bd9Sstevel@tonic-gate {
49497c478bd9Sstevel@tonic-gate 	vnode_t *vp;
49507c478bd9Sstevel@tonic-gate 	ulong_t nfiles;
49517c478bd9Sstevel@tonic-gate 
49527c478bd9Sstevel@tonic-gate 	vn_invalid(PTOV(pnp));
49537c478bd9Sstevel@tonic-gate 	vn_free(PTOV(pnp));
49547c478bd9Sstevel@tonic-gate 	mutex_destroy(&pnp->pr_mutex);
49557c478bd9Sstevel@tonic-gate 
49567c478bd9Sstevel@tonic-gate 	switch (pnp->pr_type) {
49577c478bd9Sstevel@tonic-gate 	case PR_PIDDIR:
49587c478bd9Sstevel@tonic-gate 		/* kludge for old /proc interface */
49597c478bd9Sstevel@tonic-gate 		if (pnp->pr_pidfile != NULL) {
49607c478bd9Sstevel@tonic-gate 			prfreenode(VTOP(pnp->pr_pidfile));
49617c478bd9Sstevel@tonic-gate 			pnp->pr_pidfile = NULL;
49627c478bd9Sstevel@tonic-gate 		}
49637c478bd9Sstevel@tonic-gate 		/* FALLTHROUGH */
49647c478bd9Sstevel@tonic-gate 	case PR_LWPIDDIR:
49657c478bd9Sstevel@tonic-gate 		/*
49667c478bd9Sstevel@tonic-gate 		 * We allocated a prcommon and a files array for each of these.
49677c478bd9Sstevel@tonic-gate 		 */
49687c478bd9Sstevel@tonic-gate 		prfreecommon(pnp->pr_common);
49697c478bd9Sstevel@tonic-gate 		nfiles = (pnp->pr_type == PR_PIDDIR)?
49707c478bd9Sstevel@tonic-gate 		    NPIDDIRFILES : NLWPIDDIRFILES;
49717c478bd9Sstevel@tonic-gate 		kmem_free(pnp->pr_files, nfiles * sizeof (vnode_t *));
49727c478bd9Sstevel@tonic-gate 		break;
49737c478bd9Sstevel@tonic-gate 	default:
49747c478bd9Sstevel@tonic-gate 		break;
49757c478bd9Sstevel@tonic-gate 	}
49767c478bd9Sstevel@tonic-gate 	/*
49777c478bd9Sstevel@tonic-gate 	 * If there is an underlying vnode, be sure
49787c478bd9Sstevel@tonic-gate 	 * to release it after freeing the prnode.
49797c478bd9Sstevel@tonic-gate 	 */
49807c478bd9Sstevel@tonic-gate 	vp = pnp->pr_realvp;
49817c478bd9Sstevel@tonic-gate 	kmem_free(pnp, sizeof (*pnp));
49827c478bd9Sstevel@tonic-gate 	DECREMENT(nprnode);
49837c478bd9Sstevel@tonic-gate 	if (vp != NULL) {
49847c478bd9Sstevel@tonic-gate 		VN_RELE(vp);
49857c478bd9Sstevel@tonic-gate 	}
49867c478bd9Sstevel@tonic-gate }
49877c478bd9Sstevel@tonic-gate 
49887c478bd9Sstevel@tonic-gate /*
4989da6c28aaSamw  * Free a prcommon structure, if the reference count reaches zero.
49907c478bd9Sstevel@tonic-gate  */
49917c478bd9Sstevel@tonic-gate static void
prfreecommon(prcommon_t * pcp)49927c478bd9Sstevel@tonic-gate prfreecommon(prcommon_t *pcp)
49937c478bd9Sstevel@tonic-gate {
49947c478bd9Sstevel@tonic-gate 	mutex_enter(&pcp->prc_mutex);
49957c478bd9Sstevel@tonic-gate 	ASSERT(pcp->prc_refcnt > 0);
49967c478bd9Sstevel@tonic-gate 	if (--pcp->prc_refcnt != 0)
49977c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
49987c478bd9Sstevel@tonic-gate 	else {
49997c478bd9Sstevel@tonic-gate 		mutex_exit(&pcp->prc_mutex);
50002c76d751SPatrick Mooney 
50017c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_refcnt == 0);
50027c478bd9Sstevel@tonic-gate 		ASSERT(pcp->prc_selfopens == 0 && pcp->prc_writers == 0);
50032c76d751SPatrick Mooney 
50042c76d751SPatrick Mooney 		pollhead_clean(&pcp->prc_pollhead);
50057c478bd9Sstevel@tonic-gate 		mutex_destroy(&pcp->prc_mutex);
50067c478bd9Sstevel@tonic-gate 		cv_destroy(&pcp->prc_wait);
50077c478bd9Sstevel@tonic-gate 		kmem_free(pcp, sizeof (prcommon_t));
50087c478bd9Sstevel@tonic-gate 		DECREMENT(nprcommon);
50097c478bd9Sstevel@tonic-gate 	}
50107c478bd9Sstevel@tonic-gate }
50117c478bd9Sstevel@tonic-gate 
50127c478bd9Sstevel@tonic-gate /*
50137c478bd9Sstevel@tonic-gate  * Array of readdir functions, indexed by /proc file type.
50147c478bd9Sstevel@tonic-gate  */
50157c478bd9Sstevel@tonic-gate static int pr_readdir_notdir(), pr_readdir_procdir(), pr_readdir_piddir(),
50167c478bd9Sstevel@tonic-gate 	pr_readdir_objectdir(), pr_readdir_lwpdir(), pr_readdir_lwpiddir(),
5017a02120c4SAndy Fiddaman 	pr_readdir_fddir(), pr_readdir_fdinfodir(), pr_readdir_pathdir(),
5018a02120c4SAndy Fiddaman 	pr_readdir_tmpldir(), pr_readdir_ctdir();
50197c478bd9Sstevel@tonic-gate 
50207c478bd9Sstevel@tonic-gate static int (*pr_readdir_function[PR_NFILES])() = {
50217c478bd9Sstevel@tonic-gate 	pr_readdir_procdir,	/* /proc				*/
50227c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/self				*/
50237c478bd9Sstevel@tonic-gate 	pr_readdir_piddir,	/* /proc/<pid>				*/
50247c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/as			*/
50257c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/ctl			*/
50267c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/status			*/
50277c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lstatus			*/
50287c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/psinfo			*/
50297c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lpsinfo			*/
50307c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/map			*/
50317c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/rmap			*/
50327c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/xmap			*/
50337c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/cred			*/
50347c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/sigact			*/
50357c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/auxv			*/
50367c478bd9Sstevel@tonic-gate #if defined(__x86)
50377c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/ldt			*/
50387c478bd9Sstevel@tonic-gate #endif
50397c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/usage			*/
50407c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lusage			*/
50417c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/pagedata			*/
50427c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/watch			*/
50437c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/cwd			*/
50447c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/root			*/
50457c478bd9Sstevel@tonic-gate 	pr_readdir_fddir,	/* /proc/<pid>/fd			*/
50467c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/fd/nn			*/
5047a02120c4SAndy Fiddaman 	pr_readdir_fdinfodir,	/* /proc/<pid>/fdinfo			*/
5048a02120c4SAndy Fiddaman 	pr_readdir_notdir,	/* /proc/<pid>/fdinfo/nn		*/
50497c478bd9Sstevel@tonic-gate 	pr_readdir_objectdir,	/* /proc/<pid>/object			*/
50507c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/object/xxx		*/
50517c478bd9Sstevel@tonic-gate 	pr_readdir_lwpdir,	/* /proc/<pid>/lwp			*/
50527c478bd9Sstevel@tonic-gate 	pr_readdir_lwpiddir,	/* /proc/<pid>/lwp/<lwpid>		*/
50537c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpctl	*/
5054ab618543SJohn Levon 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpname	*/
50557c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpstatus	*/
50567c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpsinfo	*/
50577c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/lwpusage	*/
50587c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/xregs	*/
50597c478bd9Sstevel@tonic-gate 	pr_readdir_tmpldir,	/* /proc/<pid>/lwp/<lwpid>/templates	*/
50607c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/templates/<id> */
5061f971a346SBryan Cantrill 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/spymaster	*/
50627c478bd9Sstevel@tonic-gate #if defined(__sparc)
50637c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/gwindows	*/
50647c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/lwp/<lwpid>/asrs		*/
50657c478bd9Sstevel@tonic-gate #endif
50667c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/priv			*/
50677c478bd9Sstevel@tonic-gate 	pr_readdir_pathdir,	/* /proc/<pid>/path			*/
50687c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/path/xxx			*/
50697c478bd9Sstevel@tonic-gate 	pr_readdir_ctdir,	/* /proc/<pid>/contracts		*/
50707c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* /proc/<pid>/contracts/<ctid>		*/
5071d2a70789SRichard Lowe 	pr_readdir_notdir,	/* /proc/<pid>/secflags			*/
50727c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* old process file			*/
50737c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* old lwp file				*/
50747c478bd9Sstevel@tonic-gate 	pr_readdir_notdir,	/* old pagedata file			*/
50757c478bd9Sstevel@tonic-gate };
50767c478bd9Sstevel@tonic-gate 
50777c478bd9Sstevel@tonic-gate /* ARGSUSED */
50787c478bd9Sstevel@tonic-gate static int
prreaddir(vnode_t * vp,uio_t * uiop,cred_t * cr,int * eofp,caller_context_t * ct,int flags)5079da6c28aaSamw prreaddir(vnode_t *vp, uio_t *uiop, cred_t *cr, int *eofp,
5080da6c28aaSamw     caller_context_t *ct, int flags)
50817c478bd9Sstevel@tonic-gate {
50827c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
50837c478bd9Sstevel@tonic-gate 
50847c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
50857c478bd9Sstevel@tonic-gate 
5086da6c28aaSamw 	/* XXX - Do we need to pass ct and flags? */
50877c478bd9Sstevel@tonic-gate 	return (pr_readdir_function[pnp->pr_type](pnp, uiop, eofp));
50887c478bd9Sstevel@tonic-gate }
50897c478bd9Sstevel@tonic-gate 
50907c478bd9Sstevel@tonic-gate /* ARGSUSED */
50917c478bd9Sstevel@tonic-gate static int
pr_readdir_notdir(prnode_t * pnp,uio_t * uiop,int * eofp)50927c478bd9Sstevel@tonic-gate pr_readdir_notdir(prnode_t *pnp, uio_t *uiop, int *eofp)
50937c478bd9Sstevel@tonic-gate {
50947c478bd9Sstevel@tonic-gate 	return (ENOTDIR);
50957c478bd9Sstevel@tonic-gate }
50967c478bd9Sstevel@tonic-gate 
50977c478bd9Sstevel@tonic-gate /* ARGSUSED */
50987c478bd9Sstevel@tonic-gate static int
pr_readdir_procdir(prnode_t * pnp,uio_t * uiop,int * eofp)50997c478bd9Sstevel@tonic-gate pr_readdir_procdir(prnode_t *pnp, uio_t *uiop, int *eofp)
51007c478bd9Sstevel@tonic-gate {
51017c478bd9Sstevel@tonic-gate 	zoneid_t zoneid;
51027c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
51037c478bd9Sstevel@tonic-gate 	int error, eof = 0;
51047c478bd9Sstevel@tonic-gate 	offset_t n;
51057c478bd9Sstevel@tonic-gate 
51067c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PROCDIR);
51077c478bd9Sstevel@tonic-gate 
5108fa9e4066Sahrens 	zoneid = VTOZONE(PTOV(pnp))->zone_id;
51097c478bd9Sstevel@tonic-gate 
51107c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PNSIZ, PRSDSIZE, uiop,
5111b38f0970Sck153898 	    PRROOTINO, PRROOTINO, 0)) != 0)
51127c478bd9Sstevel@tonic-gate 		return (error);
51137c478bd9Sstevel@tonic-gate 
51147c478bd9Sstevel@tonic-gate 	/*
51157c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until all processes
51167c478bd9Sstevel@tonic-gate 	 * have been examined.
51177c478bd9Sstevel@tonic-gate 	 */
51187c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
51197c478bd9Sstevel@tonic-gate 		uint_t pid;
51207c478bd9Sstevel@tonic-gate 		int pslot;
51217c478bd9Sstevel@tonic-gate 		proc_t *p;
51227c478bd9Sstevel@tonic-gate 
51237c478bd9Sstevel@tonic-gate 		/*
51247c478bd9Sstevel@tonic-gate 		 * Find next entry.  Skip processes not visible where
51257c478bd9Sstevel@tonic-gate 		 * this /proc was mounted.
51267c478bd9Sstevel@tonic-gate 		 */
51277c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
51287c478bd9Sstevel@tonic-gate 		while (n < v.v_proc &&
51297c478bd9Sstevel@tonic-gate 		    ((p = pid_entry(n)) == NULL || p->p_stat == SIDL ||
51307c478bd9Sstevel@tonic-gate 		    (zoneid != GLOBAL_ZONEID && p->p_zone->zone_id != zoneid) ||
51317c478bd9Sstevel@tonic-gate 		    secpolicy_basic_procinfo(CRED(), p, curproc) != 0))
51327c478bd9Sstevel@tonic-gate 			n++;
51337c478bd9Sstevel@tonic-gate 
51347c478bd9Sstevel@tonic-gate 		/*
51357c478bd9Sstevel@tonic-gate 		 * Stop when entire proc table has been examined.
51367c478bd9Sstevel@tonic-gate 		 */
51377c478bd9Sstevel@tonic-gate 		if (n >= v.v_proc) {
51387c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
51397c478bd9Sstevel@tonic-gate 			eof = 1;
51407c478bd9Sstevel@tonic-gate 			break;
51417c478bd9Sstevel@tonic-gate 		}
51427c478bd9Sstevel@tonic-gate 
51437c478bd9Sstevel@tonic-gate 		ASSERT(p->p_stat != 0);
51447c478bd9Sstevel@tonic-gate 		pid = p->p_pid;
51457c478bd9Sstevel@tonic-gate 		pslot = p->p_slot;
51467c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
51477c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, n,
51487c478bd9Sstevel@tonic-gate 		    pmkino(0, pslot, PR_PIDDIR), pid);
51497c478bd9Sstevel@tonic-gate 		if (error)
51507c478bd9Sstevel@tonic-gate 			break;
51517c478bd9Sstevel@tonic-gate 	}
51527c478bd9Sstevel@tonic-gate 
51537c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
51547c478bd9Sstevel@tonic-gate }
51557c478bd9Sstevel@tonic-gate 
51567c478bd9Sstevel@tonic-gate /* ARGSUSED */
51577c478bd9Sstevel@tonic-gate static int
pr_readdir_piddir(prnode_t * pnp,uio_t * uiop,int * eofp)51587c478bd9Sstevel@tonic-gate pr_readdir_piddir(prnode_t *pnp, uio_t *uiop, int *eofp)
51597c478bd9Sstevel@tonic-gate {
51607c478bd9Sstevel@tonic-gate 	int zombie = ((pnp->pr_pcommon->prc_flags & PRC_DESTROY) != 0);
51617c478bd9Sstevel@tonic-gate 	prdirent_t dirent;
51627c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
51637c478bd9Sstevel@tonic-gate 	offset_t off;
51647c478bd9Sstevel@tonic-gate 	int error;
51657c478bd9Sstevel@tonic-gate 
51667c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PIDDIR);
51677c478bd9Sstevel@tonic-gate 
51687c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
51697c478bd9Sstevel@tonic-gate 	    uiop->uio_offset % sizeof (prdirent_t) != 0 ||
51707c478bd9Sstevel@tonic-gate 	    uiop->uio_resid < sizeof (prdirent_t))
51717c478bd9Sstevel@tonic-gate 		return (EINVAL);
51727c478bd9Sstevel@tonic-gate 	if (pnp->pr_pcommon->prc_proc == NULL)
51737c478bd9Sstevel@tonic-gate 		return (ENOENT);
51747c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (piddir))
51757c478bd9Sstevel@tonic-gate 		goto out;
51767c478bd9Sstevel@tonic-gate 
51777c478bd9Sstevel@tonic-gate 	/*
51787c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied, omitting some
51797c478bd9Sstevel@tonic-gate 	 * files along the way if the process is a zombie.
51807c478bd9Sstevel@tonic-gate 	 */
51817c478bd9Sstevel@tonic-gate 	for (dirp = &piddir[uiop->uio_offset / sizeof (prdirent_t)];
51827c478bd9Sstevel@tonic-gate 	    uiop->uio_resid >= sizeof (prdirent_t) &&
51837c478bd9Sstevel@tonic-gate 	    dirp < &piddir[NPIDDIRFILES+2];
51847c478bd9Sstevel@tonic-gate 	    uiop->uio_offset = off + sizeof (prdirent_t), dirp++) {
51857c478bd9Sstevel@tonic-gate 		off = uiop->uio_offset;
51867c478bd9Sstevel@tonic-gate 		if (zombie) {
51877c478bd9Sstevel@tonic-gate 			switch (dirp->d_ino) {
51887c478bd9Sstevel@tonic-gate 			case PR_PIDDIR:
51897c478bd9Sstevel@tonic-gate 			case PR_PROCDIR:
51907c478bd9Sstevel@tonic-gate 			case PR_PSINFO:
51917c478bd9Sstevel@tonic-gate 			case PR_USAGE:
51927c478bd9Sstevel@tonic-gate 				break;
51937c478bd9Sstevel@tonic-gate 			default:
51947c478bd9Sstevel@tonic-gate 				continue;
51957c478bd9Sstevel@tonic-gate 			}
51967c478bd9Sstevel@tonic-gate 		}
51977c478bd9Sstevel@tonic-gate 		bcopy(dirp, &dirent, sizeof (prdirent_t));
51987c478bd9Sstevel@tonic-gate 		if (dirent.d_ino == PR_PROCDIR)
51997c478bd9Sstevel@tonic-gate 			dirent.d_ino = PRROOTINO;
52007c478bd9Sstevel@tonic-gate 		else
52017c478bd9Sstevel@tonic-gate 			dirent.d_ino = pmkino(0, pnp->pr_pcommon->prc_slot,
52027c478bd9Sstevel@tonic-gate 			    dirent.d_ino);
52037c478bd9Sstevel@tonic-gate 		if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
52047c478bd9Sstevel@tonic-gate 		    UIO_READ, uiop)) != 0)
52057c478bd9Sstevel@tonic-gate 			return (error);
52067c478bd9Sstevel@tonic-gate 	}
52077c478bd9Sstevel@tonic-gate out:
52087c478bd9Sstevel@tonic-gate 	if (eofp)
52097c478bd9Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= sizeof (piddir));
52107c478bd9Sstevel@tonic-gate 	return (0);
52117c478bd9Sstevel@tonic-gate }
52127c478bd9Sstevel@tonic-gate 
52137c478bd9Sstevel@tonic-gate static void
rebuild_objdir(struct as * as)52147c478bd9Sstevel@tonic-gate rebuild_objdir(struct as *as)
52157c478bd9Sstevel@tonic-gate {
52167c478bd9Sstevel@tonic-gate 	struct seg *seg;
52177c478bd9Sstevel@tonic-gate 	vnode_t *vp;
52187c478bd9Sstevel@tonic-gate 	vattr_t vattr;
52197c478bd9Sstevel@tonic-gate 	vnode_t **dir;
52207c478bd9Sstevel@tonic-gate 	ulong_t nalloc;
52217c478bd9Sstevel@tonic-gate 	ulong_t nentries;
52227c478bd9Sstevel@tonic-gate 	int i, j;
52237c478bd9Sstevel@tonic-gate 	ulong_t nold, nnew;
52247c478bd9Sstevel@tonic-gate 
5225dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_WRITE_HELD(as));
52267c478bd9Sstevel@tonic-gate 
52277c478bd9Sstevel@tonic-gate 	if (as->a_updatedir == 0 && as->a_objectdir != NULL)
52287c478bd9Sstevel@tonic-gate 		return;
52297c478bd9Sstevel@tonic-gate 	as->a_updatedir = 0;
52307c478bd9Sstevel@tonic-gate 
52317c478bd9Sstevel@tonic-gate 	if ((nalloc = avl_numnodes(&as->a_segtree)) == 0 ||
52327c478bd9Sstevel@tonic-gate 	    (seg = AS_SEGFIRST(as)) == NULL)	/* can't happen? */
52337c478bd9Sstevel@tonic-gate 		return;
52347c478bd9Sstevel@tonic-gate 
52357c478bd9Sstevel@tonic-gate 	/*
52367c478bd9Sstevel@tonic-gate 	 * Allocate space for the new object directory.
52377c478bd9Sstevel@tonic-gate 	 * (This is usually about two times too many entries.)
52387c478bd9Sstevel@tonic-gate 	 */
52397c478bd9Sstevel@tonic-gate 	nalloc = (nalloc + 0xf) & ~0xf;		/* multiple of 16 */
52407c478bd9Sstevel@tonic-gate 	dir = kmem_zalloc(nalloc * sizeof (vnode_t *), KM_SLEEP);
52417c478bd9Sstevel@tonic-gate 
52427c478bd9Sstevel@tonic-gate 	/* fill in the new directory with desired entries */
52437c478bd9Sstevel@tonic-gate 	nentries = 0;
52447c478bd9Sstevel@tonic-gate 	do {
52457c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID|AT_NODEID;
52467c478bd9Sstevel@tonic-gate 		if (seg->s_ops == &segvn_ops &&
52477c478bd9Sstevel@tonic-gate 		    SEGOP_GETVP(seg, seg->s_base, &vp) == 0 &&
52487c478bd9Sstevel@tonic-gate 		    vp != NULL && vp->v_type == VREG &&
5249da6c28aaSamw 		    VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) == 0) {
52507c478bd9Sstevel@tonic-gate 			for (i = 0; i < nentries; i++)
52517c478bd9Sstevel@tonic-gate 				if (vp == dir[i])
52527c478bd9Sstevel@tonic-gate 					break;
52537c478bd9Sstevel@tonic-gate 			if (i == nentries) {
52547c478bd9Sstevel@tonic-gate 				ASSERT(nentries < nalloc);
52557c478bd9Sstevel@tonic-gate 				dir[nentries++] = vp;
52567c478bd9Sstevel@tonic-gate 			}
52577c478bd9Sstevel@tonic-gate 		}
52587c478bd9Sstevel@tonic-gate 	} while ((seg = AS_SEGNEXT(as, seg)) != NULL);
52597c478bd9Sstevel@tonic-gate 
52607c478bd9Sstevel@tonic-gate 	if (as->a_objectdir == NULL) {	/* first time */
52617c478bd9Sstevel@tonic-gate 		as->a_objectdir = dir;
52627c478bd9Sstevel@tonic-gate 		as->a_sizedir = nalloc;
52637c478bd9Sstevel@tonic-gate 		return;
52647c478bd9Sstevel@tonic-gate 	}
52657c478bd9Sstevel@tonic-gate 
52667c478bd9Sstevel@tonic-gate 	/*
52677c478bd9Sstevel@tonic-gate 	 * Null out all of the defunct entries in the old directory.
52687c478bd9Sstevel@tonic-gate 	 */
52697c478bd9Sstevel@tonic-gate 	nold = 0;
52707c478bd9Sstevel@tonic-gate 	nnew = nentries;
52717c478bd9Sstevel@tonic-gate 	for (i = 0; i < as->a_sizedir; i++) {
52727c478bd9Sstevel@tonic-gate 		if ((vp = as->a_objectdir[i]) != NULL) {
52737c478bd9Sstevel@tonic-gate 			for (j = 0; j < nentries; j++) {
52747c478bd9Sstevel@tonic-gate 				if (vp == dir[j]) {
52757c478bd9Sstevel@tonic-gate 					dir[j] = NULL;
52767c478bd9Sstevel@tonic-gate 					nnew--;
52777c478bd9Sstevel@tonic-gate 					break;
52787c478bd9Sstevel@tonic-gate 				}
52797c478bd9Sstevel@tonic-gate 			}
52807c478bd9Sstevel@tonic-gate 			if (j == nentries)
52817c478bd9Sstevel@tonic-gate 				as->a_objectdir[i] = NULL;
52827c478bd9Sstevel@tonic-gate 			else
52837c478bd9Sstevel@tonic-gate 				nold++;
52847c478bd9Sstevel@tonic-gate 		}
52857c478bd9Sstevel@tonic-gate 	}
52867c478bd9Sstevel@tonic-gate 
52877c478bd9Sstevel@tonic-gate 	if (nold + nnew > as->a_sizedir) {
52887c478bd9Sstevel@tonic-gate 		/*
52897c478bd9Sstevel@tonic-gate 		 * Reallocate the old directory to have enough
52907c478bd9Sstevel@tonic-gate 		 * space for the old and new entries combined.
52917c478bd9Sstevel@tonic-gate 		 * Round up to the next multiple of 16.
52927c478bd9Sstevel@tonic-gate 		 */
52937c478bd9Sstevel@tonic-gate 		ulong_t newsize = (nold + nnew + 0xf) & ~0xf;
52947c478bd9Sstevel@tonic-gate 		vnode_t **newdir = kmem_zalloc(newsize * sizeof (vnode_t *),
52957c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
52967c478bd9Sstevel@tonic-gate 		bcopy(as->a_objectdir, newdir,
52977c478bd9Sstevel@tonic-gate 		    as->a_sizedir * sizeof (vnode_t *));
52987c478bd9Sstevel@tonic-gate 		kmem_free(as->a_objectdir, as->a_sizedir * sizeof (vnode_t *));
52997c478bd9Sstevel@tonic-gate 		as->a_objectdir = newdir;
53007c478bd9Sstevel@tonic-gate 		as->a_sizedir = newsize;
53017c478bd9Sstevel@tonic-gate 	}
53027c478bd9Sstevel@tonic-gate 
53037c478bd9Sstevel@tonic-gate 	/*
53047c478bd9Sstevel@tonic-gate 	 * Move all new entries to the old directory and
53057c478bd9Sstevel@tonic-gate 	 * deallocate the space used by the new directory.
53067c478bd9Sstevel@tonic-gate 	 */
53077c478bd9Sstevel@tonic-gate 	if (nnew) {
53087c478bd9Sstevel@tonic-gate 		for (i = 0, j = 0; i < nentries; i++) {
53097c478bd9Sstevel@tonic-gate 			if ((vp = dir[i]) == NULL)
53107c478bd9Sstevel@tonic-gate 				continue;
53117c478bd9Sstevel@tonic-gate 			for (; j < as->a_sizedir; j++) {
53127c478bd9Sstevel@tonic-gate 				if (as->a_objectdir[j] != NULL)
53137c478bd9Sstevel@tonic-gate 					continue;
53147c478bd9Sstevel@tonic-gate 				as->a_objectdir[j++] = vp;
53157c478bd9Sstevel@tonic-gate 				break;
53167c478bd9Sstevel@tonic-gate 			}
53177c478bd9Sstevel@tonic-gate 		}
53187c478bd9Sstevel@tonic-gate 	}
53197c478bd9Sstevel@tonic-gate 	kmem_free(dir, nalloc * sizeof (vnode_t *));
53207c478bd9Sstevel@tonic-gate }
53217c478bd9Sstevel@tonic-gate 
53227c478bd9Sstevel@tonic-gate /*
53237c478bd9Sstevel@tonic-gate  * Return the vnode from a slot in the process's object directory.
53247c478bd9Sstevel@tonic-gate  * The caller must have locked the process's address space.
53257c478bd9Sstevel@tonic-gate  * The only caller is below, in pr_readdir_objectdir().
53267c478bd9Sstevel@tonic-gate  */
53277c478bd9Sstevel@tonic-gate static vnode_t *
obj_entry(struct as * as,int slot)53287c478bd9Sstevel@tonic-gate obj_entry(struct as *as, int slot)
53297c478bd9Sstevel@tonic-gate {
5330dc32d872SJosef 'Jeff' Sipek 	ASSERT(AS_LOCK_HELD(as));
53317c478bd9Sstevel@tonic-gate 	if (as->a_objectdir == NULL)
53327c478bd9Sstevel@tonic-gate 		return (NULL);
53337c478bd9Sstevel@tonic-gate 	ASSERT(slot < as->a_sizedir);
53347c478bd9Sstevel@tonic-gate 	return (as->a_objectdir[slot]);
53357c478bd9Sstevel@tonic-gate }
53367c478bd9Sstevel@tonic-gate 
53377c478bd9Sstevel@tonic-gate /* ARGSUSED */
53387c478bd9Sstevel@tonic-gate static int
pr_readdir_objectdir(prnode_t * pnp,uio_t * uiop,int * eofp)53397c478bd9Sstevel@tonic-gate pr_readdir_objectdir(prnode_t *pnp, uio_t *uiop, int *eofp)
53407c478bd9Sstevel@tonic-gate {
53417c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
53427c478bd9Sstevel@tonic-gate 	int error, eof = 0;
53437c478bd9Sstevel@tonic-gate 	offset_t n;
53447c478bd9Sstevel@tonic-gate 	int pslot;
53457c478bd9Sstevel@tonic-gate 	size_t objdirsize;
53467c478bd9Sstevel@tonic-gate 	proc_t *p;
53477c478bd9Sstevel@tonic-gate 	struct as *as;
53487c478bd9Sstevel@tonic-gate 	vnode_t *vp;
53497c478bd9Sstevel@tonic-gate 
53507c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_OBJECTDIR);
53517c478bd9Sstevel@tonic-gate 
53527c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
53537c478bd9Sstevel@tonic-gate 		return (error);
53547c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
53557c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
53567c478bd9Sstevel@tonic-gate 
53577c478bd9Sstevel@tonic-gate 	/*
53587c478bd9Sstevel@tonic-gate 	 * We drop p_lock before grabbing the address space lock
53597c478bd9Sstevel@tonic-gate 	 * in order to avoid a deadlock with the clock thread.
53607c478bd9Sstevel@tonic-gate 	 * The process will not disappear and its address space
53617c478bd9Sstevel@tonic-gate 	 * will not change because it is marked P_PR_LOCK.
53627c478bd9Sstevel@tonic-gate 	 */
53637c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
53647c478bd9Sstevel@tonic-gate 
53657c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, 64, PRSDSIZE, uiop,
53667c478bd9Sstevel@tonic-gate 	    pmkino(0, pslot, PR_PIDDIR),
5367b38f0970Sck153898 	    pmkino(0, pslot, PR_OBJECTDIR), 0)) != 0) {
53687c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
53697c478bd9Sstevel@tonic-gate 		prunlock(pnp);
53707c478bd9Sstevel@tonic-gate 		return (error);
53717c478bd9Sstevel@tonic-gate 	}
53727c478bd9Sstevel@tonic-gate 
53737c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
53747c478bd9Sstevel@tonic-gate 		as = NULL;
53757c478bd9Sstevel@tonic-gate 		objdirsize = 0;
537643d09bd4Spetede 	}
537743d09bd4Spetede 
537843d09bd4Spetede 	/*
537943d09bd4Spetede 	 * Loop until user's request is satisfied or until
538043d09bd4Spetede 	 * all mapped objects have been examined. Cannot hold
538143d09bd4Spetede 	 * the address space lock for the following call as
538243d09bd4Spetede 	 * gfs_readdir_pred() utimately causes a call to uiomove().
538343d09bd4Spetede 	 */
538443d09bd4Spetede 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
538543d09bd4Spetede 		vattr_t vattr;
538643d09bd4Spetede 		char str[64];
538743d09bd4Spetede 
538843d09bd4Spetede 		/*
538943d09bd4Spetede 		 * Set the correct size of the directory just
539043d09bd4Spetede 		 * in case the process has changed it's address
539143d09bd4Spetede 		 * space via mmap/munmap calls.
539243d09bd4Spetede 		 */
539343d09bd4Spetede 		if (as != NULL) {
5394dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
53957c478bd9Sstevel@tonic-gate 			if (as->a_updatedir)
53967c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
53977c478bd9Sstevel@tonic-gate 			objdirsize = as->a_sizedir;
53987c478bd9Sstevel@tonic-gate 		}
53997c478bd9Sstevel@tonic-gate 
54007c478bd9Sstevel@tonic-gate 		/*
54017c478bd9Sstevel@tonic-gate 		 * Find next object.
54027c478bd9Sstevel@tonic-gate 		 */
54037c478bd9Sstevel@tonic-gate 		vattr.va_mask = AT_FSID | AT_NODEID;
54047c478bd9Sstevel@tonic-gate 		while (n < objdirsize && (((vp = obj_entry(as, n)) == NULL) ||
5405da6c28aaSamw 		    (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL)
5406da6c28aaSamw 		    != 0))) {
54077c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID | AT_NODEID;
54087c478bd9Sstevel@tonic-gate 			n++;
54097c478bd9Sstevel@tonic-gate 		}
54107c478bd9Sstevel@tonic-gate 
541143d09bd4Spetede 		if (as != NULL)
5412dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
541343d09bd4Spetede 
54147c478bd9Sstevel@tonic-gate 		/*
54157c478bd9Sstevel@tonic-gate 		 * Stop when all objects have been reported.
54167c478bd9Sstevel@tonic-gate 		 */
54177c478bd9Sstevel@tonic-gate 		if (n >= objdirsize) {
54187c478bd9Sstevel@tonic-gate 			eof = 1;
54197c478bd9Sstevel@tonic-gate 			break;
54207c478bd9Sstevel@tonic-gate 		}
54217c478bd9Sstevel@tonic-gate 
54227c478bd9Sstevel@tonic-gate 		if (vp == p->p_exec)
54237c478bd9Sstevel@tonic-gate 			(void) strcpy(str, "a.out");
54247c478bd9Sstevel@tonic-gate 		else
54257c478bd9Sstevel@tonic-gate 			pr_object_name(str, vp, &vattr);
54267c478bd9Sstevel@tonic-gate 
54277c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emit(&gstate, uiop, n, vattr.va_nodeid,
5428b38f0970Sck153898 		    str, 0);
542943d09bd4Spetede 
54307c478bd9Sstevel@tonic-gate 		if (error)
54317c478bd9Sstevel@tonic-gate 			break;
54327c478bd9Sstevel@tonic-gate 	}
54337c478bd9Sstevel@tonic-gate 
54347c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
54357c478bd9Sstevel@tonic-gate 	prunlock(pnp);
54367c478bd9Sstevel@tonic-gate 
54377c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
54387c478bd9Sstevel@tonic-gate }
54397c478bd9Sstevel@tonic-gate 
54407c478bd9Sstevel@tonic-gate /* ARGSUSED */
54417c478bd9Sstevel@tonic-gate static int
pr_readdir_lwpdir(prnode_t * pnp,uio_t * uiop,int * eofp)54427c478bd9Sstevel@tonic-gate pr_readdir_lwpdir(prnode_t *pnp, uio_t *uiop, int *eofp)
54437c478bd9Sstevel@tonic-gate {
54447c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
54457c478bd9Sstevel@tonic-gate 	int error, eof = 0;
54467c478bd9Sstevel@tonic-gate 	offset_t tslot;
54477c478bd9Sstevel@tonic-gate 	proc_t *p;
54487c478bd9Sstevel@tonic-gate 	int pslot;
54497c478bd9Sstevel@tonic-gate 	lwpdir_t *lwpdir;
54507c478bd9Sstevel@tonic-gate 	int lwpdirsize;
54517c478bd9Sstevel@tonic-gate 
54527c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPDIR);
54537c478bd9Sstevel@tonic-gate 
54547c478bd9Sstevel@tonic-gate 	p = pr_p_lock(pnp);
54557c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
54567c478bd9Sstevel@tonic-gate 	if (p == NULL)
54577c478bd9Sstevel@tonic-gate 		return (ENOENT);
54587c478bd9Sstevel@tonic-gate 	ASSERT(p == pnp->pr_common->prc_proc);
54597c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
54607c478bd9Sstevel@tonic-gate 	lwpdir = p->p_lwpdir;
54617c478bd9Sstevel@tonic-gate 	lwpdirsize = p->p_lwpdir_sz;
54627c478bd9Sstevel@tonic-gate 
54637c478bd9Sstevel@tonic-gate 	/*
54647c478bd9Sstevel@tonic-gate 	 * Drop p->p_lock so we can safely do uiomove().
54657c478bd9Sstevel@tonic-gate 	 * The lwp directory will not change because
54667c478bd9Sstevel@tonic-gate 	 * we have the process locked with P_PR_LOCK.
54677c478bd9Sstevel@tonic-gate 	 */
54687c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
54697c478bd9Sstevel@tonic-gate 
54707c478bd9Sstevel@tonic-gate 
54717c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
5472b38f0970Sck153898 	    pmkino(0, pslot, PR_PIDDIR),
5473b38f0970Sck153898 	    pmkino(0, pslot, PR_LWPDIR), 0)) != 0) {
54747c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
54757c478bd9Sstevel@tonic-gate 		prunlock(pnp);
54767c478bd9Sstevel@tonic-gate 		return (error);
54777c478bd9Sstevel@tonic-gate 	}
54787c478bd9Sstevel@tonic-gate 
54797c478bd9Sstevel@tonic-gate 	/*
54807c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until all lwps
54817c478bd9Sstevel@tonic-gate 	 * have been examined.
54827c478bd9Sstevel@tonic-gate 	 */
54837c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &tslot)) == 0) {
54847c478bd9Sstevel@tonic-gate 		lwpent_t *lep;
54857c478bd9Sstevel@tonic-gate 		uint_t tid;
54867c478bd9Sstevel@tonic-gate 
54877c478bd9Sstevel@tonic-gate 		/*
54887c478bd9Sstevel@tonic-gate 		 * Find next LWP.
54897c478bd9Sstevel@tonic-gate 		 */
54907c478bd9Sstevel@tonic-gate 		while (tslot < lwpdirsize &&
54917c478bd9Sstevel@tonic-gate 		    ((lep = lwpdir[tslot].ld_entry) == NULL))
54927c478bd9Sstevel@tonic-gate 			tslot++;
54937c478bd9Sstevel@tonic-gate 		/*
54947c478bd9Sstevel@tonic-gate 		 * Stop when all lwps have been reported.
54957c478bd9Sstevel@tonic-gate 		 */
54967c478bd9Sstevel@tonic-gate 		if (tslot >= lwpdirsize) {
54977c478bd9Sstevel@tonic-gate 			eof = 1;
54987c478bd9Sstevel@tonic-gate 			break;
54997c478bd9Sstevel@tonic-gate 		}
55007c478bd9Sstevel@tonic-gate 
55017c478bd9Sstevel@tonic-gate 		tid = lep->le_lwpid;
55027c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, tslot,
55037c478bd9Sstevel@tonic-gate 		    pmkino(tslot, pslot, PR_LWPIDDIR), tid);
55047c478bd9Sstevel@tonic-gate 		if (error)
55057c478bd9Sstevel@tonic-gate 			break;
55067c478bd9Sstevel@tonic-gate 	}
55077c478bd9Sstevel@tonic-gate 
55087c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
55097c478bd9Sstevel@tonic-gate 	prunlock(pnp);
55107c478bd9Sstevel@tonic-gate 
55117c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
55127c478bd9Sstevel@tonic-gate }
55137c478bd9Sstevel@tonic-gate 
55147c478bd9Sstevel@tonic-gate /* ARGSUSED */
55157c478bd9Sstevel@tonic-gate static int
pr_readdir_lwpiddir(prnode_t * pnp,uio_t * uiop,int * eofp)55167c478bd9Sstevel@tonic-gate pr_readdir_lwpiddir(prnode_t *pnp, uio_t *uiop, int *eofp)
55177c478bd9Sstevel@tonic-gate {
55187c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
55197c478bd9Sstevel@tonic-gate 	int zombie = ((pcp->prc_flags & PRC_DESTROY) != 0);
55207c478bd9Sstevel@tonic-gate 	prdirent_t dirent;
55217c478bd9Sstevel@tonic-gate 	prdirent_t *dirp;
55227c478bd9Sstevel@tonic-gate 	offset_t off;
55237c478bd9Sstevel@tonic-gate 	int error;
55247c478bd9Sstevel@tonic-gate 	int pslot;
55257c478bd9Sstevel@tonic-gate 	int tslot;
55267c478bd9Sstevel@tonic-gate 
55277c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_LWPIDDIR);
55287c478bd9Sstevel@tonic-gate 
55297c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
55307c478bd9Sstevel@tonic-gate 	    uiop->uio_offset % sizeof (prdirent_t) != 0 ||
55317c478bd9Sstevel@tonic-gate 	    uiop->uio_resid < sizeof (prdirent_t))
55327c478bd9Sstevel@tonic-gate 		return (EINVAL);
55337c478bd9Sstevel@tonic-gate 	if (pcp->prc_proc == NULL || pcp->prc_tslot == -1)
55347c478bd9Sstevel@tonic-gate 		return (ENOENT);
55357c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset >= sizeof (lwpiddir))
55367c478bd9Sstevel@tonic-gate 		goto out;
55377c478bd9Sstevel@tonic-gate 
55387c478bd9Sstevel@tonic-gate 	/*
55397c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied, omitting some files
55407c478bd9Sstevel@tonic-gate 	 * along the way if the lwp is a zombie and also depending
55417c478bd9Sstevel@tonic-gate 	 * on the data model of the process.
55427c478bd9Sstevel@tonic-gate 	 */
55437c478bd9Sstevel@tonic-gate 	pslot = pcp->prc_slot;
55447c478bd9Sstevel@tonic-gate 	tslot = pcp->prc_tslot;
55457c478bd9Sstevel@tonic-gate 	for (dirp = &lwpiddir[uiop->uio_offset / sizeof (prdirent_t)];
55467c478bd9Sstevel@tonic-gate 	    uiop->uio_resid >= sizeof (prdirent_t) &&
55477c478bd9Sstevel@tonic-gate 	    dirp < &lwpiddir[NLWPIDDIRFILES+2];
55487c478bd9Sstevel@tonic-gate 	    uiop->uio_offset = off + sizeof (prdirent_t), dirp++) {
55497c478bd9Sstevel@tonic-gate 		off = uiop->uio_offset;
55507c478bd9Sstevel@tonic-gate 		if (zombie) {
55517c478bd9Sstevel@tonic-gate 			switch (dirp->d_ino) {
55527c478bd9Sstevel@tonic-gate 			case PR_LWPIDDIR:
55537c478bd9Sstevel@tonic-gate 			case PR_LWPDIR:
55547c478bd9Sstevel@tonic-gate 			case PR_LWPSINFO:
55557c478bd9Sstevel@tonic-gate 				break;
55567c478bd9Sstevel@tonic-gate 			default:
55577c478bd9Sstevel@tonic-gate 				continue;
55587c478bd9Sstevel@tonic-gate 			}
55597c478bd9Sstevel@tonic-gate 		}
55607c478bd9Sstevel@tonic-gate #if defined(__sparc)
55617c478bd9Sstevel@tonic-gate 		/* the asrs file exists only for sparc v9 _LP64 processes */
55627c478bd9Sstevel@tonic-gate 		if (dirp->d_ino == PR_ASRS &&
55637c478bd9Sstevel@tonic-gate 		    pcp->prc_datamodel != DATAMODEL_LP64)
55647c478bd9Sstevel@tonic-gate 			continue;
55657c478bd9Sstevel@tonic-gate #endif
55667c478bd9Sstevel@tonic-gate 		bcopy(dirp, &dirent, sizeof (prdirent_t));
55677c478bd9Sstevel@tonic-gate 		if (dirent.d_ino == PR_LWPDIR)
55687c478bd9Sstevel@tonic-gate 			dirent.d_ino = pmkino(0, pslot, dirp->d_ino);
55697c478bd9Sstevel@tonic-gate 		else
55707c478bd9Sstevel@tonic-gate 			dirent.d_ino = pmkino(tslot, pslot, dirp->d_ino);
55717c478bd9Sstevel@tonic-gate 		if ((error = uiomove((caddr_t)&dirent, sizeof (prdirent_t),
55727c478bd9Sstevel@tonic-gate 		    UIO_READ, uiop)) != 0)
55737c478bd9Sstevel@tonic-gate 			return (error);
55747c478bd9Sstevel@tonic-gate 	}
55757c478bd9Sstevel@tonic-gate out:
55767c478bd9Sstevel@tonic-gate 	if (eofp)
55777c478bd9Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= sizeof (lwpiddir));
55787c478bd9Sstevel@tonic-gate 	return (0);
55797c478bd9Sstevel@tonic-gate }
55807c478bd9Sstevel@tonic-gate 
5581a02120c4SAndy Fiddaman /*
5582a02120c4SAndy Fiddaman  * Helper function for reading a directory which lists open file desciptors
5583a02120c4SAndy Fiddaman  */
55847c478bd9Sstevel@tonic-gate static int
pr_readdir_fdlist(prnode_t * pnp,uio_t * uiop,int * eofp,prnodetype_t dirtype,prnodetype_t entrytype)5585a02120c4SAndy Fiddaman pr_readdir_fdlist(prnode_t *pnp, uio_t *uiop, int *eofp,
5586a02120c4SAndy Fiddaman     prnodetype_t dirtype, prnodetype_t entrytype)
55877c478bd9Sstevel@tonic-gate {
55887c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
55897c478bd9Sstevel@tonic-gate 	int error, eof = 0;
55907c478bd9Sstevel@tonic-gate 	offset_t n;
55917c478bd9Sstevel@tonic-gate 	proc_t *p;
55927c478bd9Sstevel@tonic-gate 	int pslot;
55937c478bd9Sstevel@tonic-gate 	int fddirsize;
55947c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
55957c478bd9Sstevel@tonic-gate 
55967c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
55977c478bd9Sstevel@tonic-gate 		return (error);
55987c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
55997c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
56007c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
56017c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
56027c478bd9Sstevel@tonic-gate 
56037c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PLNSIZ, PRSDSIZE, uiop,
5604a02120c4SAndy Fiddaman 	    pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, dirtype), 0)) != 0) {
56057c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
56067c478bd9Sstevel@tonic-gate 		prunlock(pnp);
56077c478bd9Sstevel@tonic-gate 		return (error);
56087c478bd9Sstevel@tonic-gate 	}
56097c478bd9Sstevel@tonic-gate 
56107c478bd9Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
56117c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
56127c478bd9Sstevel@tonic-gate 		fddirsize = 0;
56137c478bd9Sstevel@tonic-gate 	else
56147c478bd9Sstevel@tonic-gate 		fddirsize = fip->fi_nfiles;
56157c478bd9Sstevel@tonic-gate 
56167c478bd9Sstevel@tonic-gate 	/*
56177c478bd9Sstevel@tonic-gate 	 * Loop until user's request is satisfied or until
56187c478bd9Sstevel@tonic-gate 	 * all file descriptors have been examined.
56197c478bd9Sstevel@tonic-gate 	 */
56207c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
56217c478bd9Sstevel@tonic-gate 		/*
56227c478bd9Sstevel@tonic-gate 		 * Find next fd.
56237c478bd9Sstevel@tonic-gate 		 */
56247c478bd9Sstevel@tonic-gate 		while (n < fddirsize && fip->fi_list[n].uf_file == NULL)
56257c478bd9Sstevel@tonic-gate 			n++;
56267c478bd9Sstevel@tonic-gate 		/*
56277c478bd9Sstevel@tonic-gate 		 * Stop when all fds have been reported.
56287c478bd9Sstevel@tonic-gate 		 */
56297c478bd9Sstevel@tonic-gate 		if (n >= fddirsize) {
56307c478bd9Sstevel@tonic-gate 			eof = 1;
56317c478bd9Sstevel@tonic-gate 			break;
56327c478bd9Sstevel@tonic-gate 		}
56337c478bd9Sstevel@tonic-gate 
56347c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, n,
5635a02120c4SAndy Fiddaman 		    pmkino(n, pslot, entrytype), n);
56367c478bd9Sstevel@tonic-gate 		if (error)
56377c478bd9Sstevel@tonic-gate 			break;
56387c478bd9Sstevel@tonic-gate 	}
56397c478bd9Sstevel@tonic-gate 
56407c478bd9Sstevel@tonic-gate 	mutex_exit(&fip->fi_lock);
56417c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
56427c478bd9Sstevel@tonic-gate 	prunlock(pnp);
56437c478bd9Sstevel@tonic-gate 
56447c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
56457c478bd9Sstevel@tonic-gate }
56467c478bd9Sstevel@tonic-gate 
5647a02120c4SAndy Fiddaman static int
pr_readdir_fddir(prnode_t * pnp,uio_t * uiop,int * eofp)5648a02120c4SAndy Fiddaman pr_readdir_fddir(prnode_t *pnp, uio_t *uiop, int *eofp)
5649a02120c4SAndy Fiddaman {
5650a02120c4SAndy Fiddaman 
5651a02120c4SAndy Fiddaman 	ASSERT(pnp->pr_type == PR_FDDIR);
5652a02120c4SAndy Fiddaman 
5653a02120c4SAndy Fiddaman 	return (pr_readdir_fdlist(pnp, uiop, eofp, pnp->pr_type, PR_FD));
5654a02120c4SAndy Fiddaman }
5655a02120c4SAndy Fiddaman 
5656a02120c4SAndy Fiddaman static int
pr_readdir_fdinfodir(prnode_t * pnp,uio_t * uiop,int * eofp)5657a02120c4SAndy Fiddaman pr_readdir_fdinfodir(prnode_t *pnp, uio_t *uiop, int *eofp)
5658a02120c4SAndy Fiddaman {
5659a02120c4SAndy Fiddaman 
5660a02120c4SAndy Fiddaman 	ASSERT(pnp->pr_type == PR_FDINFODIR);
5661a02120c4SAndy Fiddaman 
5662a02120c4SAndy Fiddaman 	return (pr_readdir_fdlist(pnp, uiop, eofp, pnp->pr_type, PR_FDINFO));
5663a02120c4SAndy Fiddaman }
5664a02120c4SAndy Fiddaman 
56657c478bd9Sstevel@tonic-gate /* ARGSUSED */
56667c478bd9Sstevel@tonic-gate static int
pr_readdir_pathdir(prnode_t * pnp,uio_t * uiop,int * eofp)56677c478bd9Sstevel@tonic-gate pr_readdir_pathdir(prnode_t *pnp, uio_t *uiop, int *eofp)
56687c478bd9Sstevel@tonic-gate {
56697c478bd9Sstevel@tonic-gate 	longlong_t bp[DIRENT64_RECLEN(64) / sizeof (longlong_t)];
56707c478bd9Sstevel@tonic-gate 	dirent64_t *dirent = (dirent64_t *)bp;
56717c478bd9Sstevel@tonic-gate 	int reclen;
56727c478bd9Sstevel@tonic-gate 	ssize_t oresid;
56737c478bd9Sstevel@tonic-gate 	offset_t off, idx;
56747c478bd9Sstevel@tonic-gate 	int error = 0;
56757c478bd9Sstevel@tonic-gate 	proc_t *p;
56767c478bd9Sstevel@tonic-gate 	int fd, obj;
56777c478bd9Sstevel@tonic-gate 	int pslot;
56787c478bd9Sstevel@tonic-gate 	int fddirsize;
56797c478bd9Sstevel@tonic-gate 	uf_info_t *fip;
56807c478bd9Sstevel@tonic-gate 	struct as *as = NULL;
56817c478bd9Sstevel@tonic-gate 	size_t objdirsize;
56827c478bd9Sstevel@tonic-gate 	vattr_t vattr;
56837c478bd9Sstevel@tonic-gate 	vnode_t *vp;
56847c478bd9Sstevel@tonic-gate 
56857c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_PATHDIR);
56867c478bd9Sstevel@tonic-gate 
56877c478bd9Sstevel@tonic-gate 	if (uiop->uio_offset < 0 ||
56887c478bd9Sstevel@tonic-gate 	    uiop->uio_resid <= 0 ||
56897c478bd9Sstevel@tonic-gate 	    (uiop->uio_offset % PRSDSIZE) != 0)
56907c478bd9Sstevel@tonic-gate 		return (EINVAL);
56917c478bd9Sstevel@tonic-gate 	oresid = uiop->uio_resid;
56927c478bd9Sstevel@tonic-gate 	bzero(bp, sizeof (bp));
56937c478bd9Sstevel@tonic-gate 
56947c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
56957c478bd9Sstevel@tonic-gate 		return (error);
56967c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
56977c478bd9Sstevel@tonic-gate 	fip = P_FINFO(p);
56987c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
56997c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
57007c478bd9Sstevel@tonic-gate 
57017c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || (as = p->p_as) == &kas) {
57027c478bd9Sstevel@tonic-gate 		as = NULL;
57037c478bd9Sstevel@tonic-gate 		objdirsize = 0;
57047c478bd9Sstevel@tonic-gate 	} else {
5705dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_ENTER(as, RW_WRITER);
57067c478bd9Sstevel@tonic-gate 		if (as->a_updatedir)
57077c478bd9Sstevel@tonic-gate 			rebuild_objdir(as);
57087c478bd9Sstevel@tonic-gate 		objdirsize = as->a_sizedir;
5709dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
57107c478bd9Sstevel@tonic-gate 		as = NULL;
57117c478bd9Sstevel@tonic-gate 	}
57127c478bd9Sstevel@tonic-gate 
57137c478bd9Sstevel@tonic-gate 	mutex_enter(&fip->fi_lock);
57147c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
57157c478bd9Sstevel@tonic-gate 		fddirsize = 0;
57167c478bd9Sstevel@tonic-gate 	else
57177c478bd9Sstevel@tonic-gate 		fddirsize = fip->fi_nfiles;
57187c478bd9Sstevel@tonic-gate 
57197c478bd9Sstevel@tonic-gate 	for (; uiop->uio_resid > 0; uiop->uio_offset = off + PRSDSIZE) {
57207c478bd9Sstevel@tonic-gate 		/*
57217c478bd9Sstevel@tonic-gate 		 * There are 4 special files in the path directory: ".", "..",
57227c478bd9Sstevel@tonic-gate 		 * "root", and "cwd".  We handle those specially here.
57237c478bd9Sstevel@tonic-gate 		 */
57247c478bd9Sstevel@tonic-gate 		off = uiop->uio_offset;
57257c478bd9Sstevel@tonic-gate 		idx = off / PRSDSIZE;
57267c478bd9Sstevel@tonic-gate 		if (off == 0) {				/* "." */
57277c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(0, pslot, PR_PATHDIR);
57287c478bd9Sstevel@tonic-gate 			dirent->d_name[0] = '.';
57297c478bd9Sstevel@tonic-gate 			dirent->d_name[1] = '\0';
57307c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(1);
57317c478bd9Sstevel@tonic-gate 		} else if (idx == 1) {			/* ".." */
57327c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(0, pslot, PR_PIDDIR);
57337c478bd9Sstevel@tonic-gate 			dirent->d_name[0] = '.';
57347c478bd9Sstevel@tonic-gate 			dirent->d_name[1] = '.';
57357c478bd9Sstevel@tonic-gate 			dirent->d_name[2] = '\0';
57367c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(2);
57377c478bd9Sstevel@tonic-gate 		} else if (idx == 2) {			/* "root" */
57387c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
57397c478bd9Sstevel@tonic-gate 			(void) strcpy(dirent->d_name, "root");
57407c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(4);
57417c478bd9Sstevel@tonic-gate 		} else if (idx == 3) {			/* "cwd" */
57427c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
57437c478bd9Sstevel@tonic-gate 			(void) strcpy(dirent->d_name, "cwd");
57447c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(3);
57457c478bd9Sstevel@tonic-gate 		} else if (idx < 4 + fddirsize) {
57467c478bd9Sstevel@tonic-gate 			/*
57477c478bd9Sstevel@tonic-gate 			 * In this case, we have one of the file descriptors.
57487c478bd9Sstevel@tonic-gate 			 */
57497c478bd9Sstevel@tonic-gate 			fd = idx - 4;
57507c478bd9Sstevel@tonic-gate 			if (fip->fi_list[fd].uf_file == NULL)
57517c478bd9Sstevel@tonic-gate 				continue;
57527c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
57537c478bd9Sstevel@tonic-gate 			(void) pr_u32tos(fd, dirent->d_name, PLNSIZ+1);
57547c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(PLNSIZ);
57557c478bd9Sstevel@tonic-gate 		} else if (idx < 4 + fddirsize + objdirsize) {
57567c478bd9Sstevel@tonic-gate 			if (fip != NULL) {
57577c478bd9Sstevel@tonic-gate 				mutex_exit(&fip->fi_lock);
57587c478bd9Sstevel@tonic-gate 				fip = NULL;
57597c478bd9Sstevel@tonic-gate 			}
57607c478bd9Sstevel@tonic-gate 
57617c478bd9Sstevel@tonic-gate 			/*
57627c478bd9Sstevel@tonic-gate 			 * We drop p_lock before grabbing the address space lock
57637c478bd9Sstevel@tonic-gate 			 * in order to avoid a deadlock with the clock thread.
57647c478bd9Sstevel@tonic-gate 			 * The process will not disappear and its address space
57657c478bd9Sstevel@tonic-gate 			 * will not change because it is marked P_PR_LOCK.
57667c478bd9Sstevel@tonic-gate 			 */
57677c478bd9Sstevel@tonic-gate 			if (as == NULL) {
57687c478bd9Sstevel@tonic-gate 				as = p->p_as;
5769dc32d872SJosef 'Jeff' Sipek 				AS_LOCK_ENTER(as, RW_WRITER);
57707c478bd9Sstevel@tonic-gate 			}
57717c478bd9Sstevel@tonic-gate 
57727c478bd9Sstevel@tonic-gate 			if (as->a_updatedir) {
57737c478bd9Sstevel@tonic-gate 				rebuild_objdir(as);
57747c478bd9Sstevel@tonic-gate 				objdirsize = as->a_sizedir;
57757c478bd9Sstevel@tonic-gate 			}
57767c478bd9Sstevel@tonic-gate 
57777c478bd9Sstevel@tonic-gate 			obj = idx - 4 - fddirsize;
57787c478bd9Sstevel@tonic-gate 			if ((vp = obj_entry(as, obj)) == NULL)
57797c478bd9Sstevel@tonic-gate 				continue;
57807c478bd9Sstevel@tonic-gate 			vattr.va_mask = AT_FSID|AT_NODEID;
5781da6c28aaSamw 			if (VOP_GETATTR(vp, &vattr, 0, CRED(), NULL) != 0)
57827c478bd9Sstevel@tonic-gate 				continue;
57837c478bd9Sstevel@tonic-gate 			if (vp == p->p_exec)
57847c478bd9Sstevel@tonic-gate 				(void) strcpy(dirent->d_name, "a.out");
57857c478bd9Sstevel@tonic-gate 			else
57867c478bd9Sstevel@tonic-gate 				pr_object_name(dirent->d_name, vp, &vattr);
57877c478bd9Sstevel@tonic-gate 			dirent->d_ino = pmkino(idx, pslot, PR_PATH);
57887c478bd9Sstevel@tonic-gate 			reclen = DIRENT64_RECLEN(strlen(dirent->d_name));
57897c478bd9Sstevel@tonic-gate 		} else {
57907c478bd9Sstevel@tonic-gate 			break;
57917c478bd9Sstevel@tonic-gate 		}
57927c478bd9Sstevel@tonic-gate 
57937c478bd9Sstevel@tonic-gate 		dirent->d_off = uiop->uio_offset + PRSDSIZE;
57947c478bd9Sstevel@tonic-gate 		dirent->d_reclen = (ushort_t)reclen;
57957c478bd9Sstevel@tonic-gate 		if (reclen > uiop->uio_resid) {
57967c478bd9Sstevel@tonic-gate 			/*
57977c478bd9Sstevel@tonic-gate 			 * Error if no entries have been returned yet.
57987c478bd9Sstevel@tonic-gate 			 */
57997c478bd9Sstevel@tonic-gate 			if (uiop->uio_resid == oresid)
58007c478bd9Sstevel@tonic-gate 				error = EINVAL;
58017c478bd9Sstevel@tonic-gate 			break;
58027c478bd9Sstevel@tonic-gate 		}
58037c478bd9Sstevel@tonic-gate 		/*
58047c478bd9Sstevel@tonic-gate 		 * Drop the address space lock to do the uiomove().
58057c478bd9Sstevel@tonic-gate 		 */
58067c478bd9Sstevel@tonic-gate 		if (as != NULL)
5807dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_EXIT(as);
58087c478bd9Sstevel@tonic-gate 
58097c478bd9Sstevel@tonic-gate 		error = uiomove((caddr_t)dirent, reclen, UIO_READ, uiop);
58107c478bd9Sstevel@tonic-gate 		if (as != NULL)
5811dc32d872SJosef 'Jeff' Sipek 			AS_LOCK_ENTER(as, RW_WRITER);
58127c478bd9Sstevel@tonic-gate 
58137c478bd9Sstevel@tonic-gate 		if (error)
58147c478bd9Sstevel@tonic-gate 			break;
58157c478bd9Sstevel@tonic-gate 	}
58167c478bd9Sstevel@tonic-gate 
58177c478bd9Sstevel@tonic-gate 	if (error == 0 && eofp)
58187c478bd9Sstevel@tonic-gate 		*eofp = (uiop->uio_offset >= (fddirsize + 2) * PRSDSIZE);
58197c478bd9Sstevel@tonic-gate 
58207c478bd9Sstevel@tonic-gate 	if (fip != NULL)
58217c478bd9Sstevel@tonic-gate 		mutex_exit(&fip->fi_lock);
58227c478bd9Sstevel@tonic-gate 	if (as != NULL)
5823dc32d872SJosef 'Jeff' Sipek 		AS_LOCK_EXIT(as);
58247c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
58257c478bd9Sstevel@tonic-gate 	prunlock(pnp);
58267c478bd9Sstevel@tonic-gate 	return (error);
58277c478bd9Sstevel@tonic-gate }
58287c478bd9Sstevel@tonic-gate 
58297c478bd9Sstevel@tonic-gate static int
pr_readdir_tmpldir(prnode_t * pnp,uio_t * uiop,int * eofp)58307c478bd9Sstevel@tonic-gate pr_readdir_tmpldir(prnode_t *pnp, uio_t *uiop, int *eofp)
58317c478bd9Sstevel@tonic-gate {
58327c478bd9Sstevel@tonic-gate 	proc_t *p;
58337c478bd9Sstevel@tonic-gate 	int pslot, tslot;
58347c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
58357c478bd9Sstevel@tonic-gate 	int error, eof = 0;
58367c478bd9Sstevel@tonic-gate 	offset_t n;
58377c478bd9Sstevel@tonic-gate 
58387c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_TMPLDIR);
58397c478bd9Sstevel@tonic-gate 
58407c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
58417c478bd9Sstevel@tonic-gate 		return (error);
58427c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
58437c478bd9Sstevel@tonic-gate 	pslot = pnp->pr_common->prc_slot;
58447c478bd9Sstevel@tonic-gate 	tslot = pnp->pr_common->prc_tslot;
58457c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
58467c478bd9Sstevel@tonic-gate 
58477c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
58487c478bd9Sstevel@tonic-gate 	    pmkino(tslot, pslot, PR_LWPDIR),
5849b38f0970Sck153898 	    pmkino(tslot, pslot, PR_TMPLDIR), 0)) != 0) {
58507c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
58517c478bd9Sstevel@tonic-gate 		prunlock(pnp);
58527c478bd9Sstevel@tonic-gate 		return (error);
58537c478bd9Sstevel@tonic-gate 	}
58547c478bd9Sstevel@tonic-gate 
58557c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
58567c478bd9Sstevel@tonic-gate 		/*
58577c478bd9Sstevel@tonic-gate 		 * Check for an active template.  Reading a directory's
58587c478bd9Sstevel@tonic-gate 		 * contents is already racy, so we don't bother taking
58597c478bd9Sstevel@tonic-gate 		 * any locks.
58607c478bd9Sstevel@tonic-gate 		 */
58617c478bd9Sstevel@tonic-gate 		while (n < ct_ntypes &&
58627c478bd9Sstevel@tonic-gate 		    pnp->pr_common->prc_thread->t_lwp->lwp_ct_active[n] == NULL)
58637c478bd9Sstevel@tonic-gate 			n++;
58647c478bd9Sstevel@tonic-gate 		/*
58657c478bd9Sstevel@tonic-gate 		 * Stop when all types have been reported.
58667c478bd9Sstevel@tonic-gate 		 */
58677c478bd9Sstevel@tonic-gate 		if (n >= ct_ntypes) {
58687c478bd9Sstevel@tonic-gate 			eof = 1;
58697c478bd9Sstevel@tonic-gate 			break;
58707c478bd9Sstevel@tonic-gate 		}
58717c478bd9Sstevel@tonic-gate 		/*
58727c478bd9Sstevel@tonic-gate 		 * The pmkino invocation below will need to be updated
58737c478bd9Sstevel@tonic-gate 		 * when we create our fifth contract type.
58747c478bd9Sstevel@tonic-gate 		 */
58757c478bd9Sstevel@tonic-gate 		ASSERT(ct_ntypes <= 4);
58767c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emit(&gstate, uiop, n,
58777c478bd9Sstevel@tonic-gate 		    pmkino((tslot << 2) | n, pslot, PR_TMPL),
5878b38f0970Sck153898 		    ct_types[n]->ct_type_name, 0);
58797c478bd9Sstevel@tonic-gate 		if (error)
58807c478bd9Sstevel@tonic-gate 			break;
58817c478bd9Sstevel@tonic-gate 	}
58827c478bd9Sstevel@tonic-gate 
58837c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
58847c478bd9Sstevel@tonic-gate 	prunlock(pnp);
58857c478bd9Sstevel@tonic-gate 
58867c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
58877c478bd9Sstevel@tonic-gate }
58887c478bd9Sstevel@tonic-gate 
58897c478bd9Sstevel@tonic-gate static int
pr_readdir_ctdir(prnode_t * pnp,uio_t * uiop,int * eofp)58907c478bd9Sstevel@tonic-gate pr_readdir_ctdir(prnode_t *pnp, uio_t *uiop, int *eofp)
58917c478bd9Sstevel@tonic-gate {
58927c478bd9Sstevel@tonic-gate 	proc_t *p;
58937c478bd9Sstevel@tonic-gate 	int pslot;
58947c478bd9Sstevel@tonic-gate 	gfs_readdir_state_t gstate;
58957c478bd9Sstevel@tonic-gate 	int error, eof = 0;
58967c478bd9Sstevel@tonic-gate 	offset_t n;
58977c478bd9Sstevel@tonic-gate 	uint64_t zid;
58987c478bd9Sstevel@tonic-gate 
58997c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type == PR_CTDIR);
59007c478bd9Sstevel@tonic-gate 
59017c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0)
59027c478bd9Sstevel@tonic-gate 		return (error);
59037c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
59047c478bd9Sstevel@tonic-gate 	pslot = p->p_slot;
59057c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
59067c478bd9Sstevel@tonic-gate 
59077c478bd9Sstevel@tonic-gate 	if ((error = gfs_readdir_init(&gstate, PRDIRSIZE, PRSDSIZE, uiop,
5908b38f0970Sck153898 	    pmkino(0, pslot, PR_PIDDIR), pmkino(0, pslot, PR_CTDIR), 0)) != 0) {
59097c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
59107c478bd9Sstevel@tonic-gate 		prunlock(pnp);
59117c478bd9Sstevel@tonic-gate 		return (error);
59127c478bd9Sstevel@tonic-gate 	}
59137c478bd9Sstevel@tonic-gate 
5914fa9e4066Sahrens 	zid = VTOZONE(pnp->pr_vnode)->zone_uniqid;
59157c478bd9Sstevel@tonic-gate 	while ((error = gfs_readdir_pred(&gstate, uiop, &n)) == 0) {
59167c478bd9Sstevel@tonic-gate 		id_t next = contract_plookup(p, n, zid);
59177c478bd9Sstevel@tonic-gate 		if (next == -1) {
59187c478bd9Sstevel@tonic-gate 			eof = 1;
59197c478bd9Sstevel@tonic-gate 			break;
59207c478bd9Sstevel@tonic-gate 		}
59217c478bd9Sstevel@tonic-gate 		error = gfs_readdir_emitn(&gstate, uiop, next,
59227c478bd9Sstevel@tonic-gate 		    pmkino(next, pslot, PR_CT), next);
59237c478bd9Sstevel@tonic-gate 		if (error)
59247c478bd9Sstevel@tonic-gate 			break;
59257c478bd9Sstevel@tonic-gate 	}
59267c478bd9Sstevel@tonic-gate 
59277c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
59287c478bd9Sstevel@tonic-gate 	prunlock(pnp);
59297c478bd9Sstevel@tonic-gate 
59307c478bd9Sstevel@tonic-gate 	return (gfs_readdir_fini(&gstate, error, eofp, eof));
59317c478bd9Sstevel@tonic-gate }
59327c478bd9Sstevel@tonic-gate 
59337c478bd9Sstevel@tonic-gate /* ARGSUSED */
59347c478bd9Sstevel@tonic-gate static int
prfsync(vnode_t * vp,int syncflag,cred_t * cr,caller_context_t * ct)5935da6c28aaSamw prfsync(vnode_t *vp, int syncflag, cred_t *cr, caller_context_t *ct)
59367c478bd9Sstevel@tonic-gate {
59377c478bd9Sstevel@tonic-gate 	return (0);
59387c478bd9Sstevel@tonic-gate }
59397c478bd9Sstevel@tonic-gate 
59407c478bd9Sstevel@tonic-gate /*
59417c478bd9Sstevel@tonic-gate  * Utility: remove a /proc vnode from a linked list, threaded through pr_next.
59427c478bd9Sstevel@tonic-gate  */
59437c478bd9Sstevel@tonic-gate static void
pr_list_unlink(vnode_t * pvp,vnode_t ** listp)59447c478bd9Sstevel@tonic-gate pr_list_unlink(vnode_t *pvp, vnode_t **listp)
59457c478bd9Sstevel@tonic-gate {
59467c478bd9Sstevel@tonic-gate 	vnode_t *vp;
59477c478bd9Sstevel@tonic-gate 	prnode_t *pnp;
59487c478bd9Sstevel@tonic-gate 
59497c478bd9Sstevel@tonic-gate 	while ((vp = *listp) != NULL) {
59507c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
59517c478bd9Sstevel@tonic-gate 		if (vp == pvp) {
59527c478bd9Sstevel@tonic-gate 			*listp = pnp->pr_next;
59537c478bd9Sstevel@tonic-gate 			pnp->pr_next = NULL;
59547c478bd9Sstevel@tonic-gate 			break;
59557c478bd9Sstevel@tonic-gate 		}
59567c478bd9Sstevel@tonic-gate 		listp = &pnp->pr_next;
59577c478bd9Sstevel@tonic-gate 	}
59587c478bd9Sstevel@tonic-gate }
59597c478bd9Sstevel@tonic-gate 
59607c478bd9Sstevel@tonic-gate /* ARGSUSED */
59617c478bd9Sstevel@tonic-gate static void
prinactive(vnode_t * vp,cred_t * cr,caller_context_t * ct)5962da6c28aaSamw prinactive(vnode_t *vp, cred_t *cr, caller_context_t *ct)
59637c478bd9Sstevel@tonic-gate {
59647c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
59657c478bd9Sstevel@tonic-gate 	prnodetype_t type = pnp->pr_type;
59667c478bd9Sstevel@tonic-gate 	proc_t *p;
59677c478bd9Sstevel@tonic-gate 	vnode_t *dp;
59687c478bd9Sstevel@tonic-gate 	vnode_t *ovp = NULL;
59697c478bd9Sstevel@tonic-gate 	prnode_t *opnp = NULL;
59707c478bd9Sstevel@tonic-gate 
59717c478bd9Sstevel@tonic-gate 	switch (type) {
59727c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
59737c478bd9Sstevel@tonic-gate 	case PR_FD:
5974a02120c4SAndy Fiddaman 	case PR_FDINFO:
59757c478bd9Sstevel@tonic-gate 	case PR_SELF:
59767c478bd9Sstevel@tonic-gate 	case PR_PATH:
59777c478bd9Sstevel@tonic-gate 		/* These are not linked into the usual lists */
59787c478bd9Sstevel@tonic-gate 		ASSERT(vp->v_count == 1);
59797c478bd9Sstevel@tonic-gate 		if ((dp = pnp->pr_parent) != NULL)
59807c478bd9Sstevel@tonic-gate 			VN_RELE(dp);
59817c478bd9Sstevel@tonic-gate 		prfreenode(pnp);
59827c478bd9Sstevel@tonic-gate 		return;
59837c478bd9Sstevel@tonic-gate 	default:
59847c478bd9Sstevel@tonic-gate 		break;
59857c478bd9Sstevel@tonic-gate 	}
59867c478bd9Sstevel@tonic-gate 
59877c478bd9Sstevel@tonic-gate 	mutex_enter(&pr_pidlock);
59887c478bd9Sstevel@tonic-gate 	if (pnp->pr_pcommon == NULL)
59897c478bd9Sstevel@tonic-gate 		p = NULL;
59907c478bd9Sstevel@tonic-gate 	else if ((p = pnp->pr_pcommon->prc_proc) != NULL)
59917c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
59927c478bd9Sstevel@tonic-gate 	mutex_enter(&vp->v_lock);
59937c478bd9Sstevel@tonic-gate 
59947c478bd9Sstevel@tonic-gate 	if (type == PR_PROCDIR || vp->v_count > 1) {
5995ade42b55SSebastien Roy 		VN_RELE_LOCKED(vp);
59967c478bd9Sstevel@tonic-gate 		mutex_exit(&vp->v_lock);
59977c478bd9Sstevel@tonic-gate 		if (p != NULL)
59987c478bd9Sstevel@tonic-gate 			mutex_exit(&p->p_lock);
59997c478bd9Sstevel@tonic-gate 		mutex_exit(&pr_pidlock);
60007c478bd9Sstevel@tonic-gate 		return;
60017c478bd9Sstevel@tonic-gate 	}
60027c478bd9Sstevel@tonic-gate 
60037c478bd9Sstevel@tonic-gate 	if ((dp = pnp->pr_parent) != NULL) {
60047c478bd9Sstevel@tonic-gate 		prnode_t *dpnp;
60057c478bd9Sstevel@tonic-gate 
60067c478bd9Sstevel@tonic-gate 		switch (type) {
60077c478bd9Sstevel@tonic-gate 		case PR_PIDFILE:
60087c478bd9Sstevel@tonic-gate 		case PR_LWPIDFILE:
60097c478bd9Sstevel@tonic-gate 		case PR_OPAGEDATA:
60107c478bd9Sstevel@tonic-gate 			break;
60117c478bd9Sstevel@tonic-gate 		default:
60127c478bd9Sstevel@tonic-gate 			dpnp = VTOP(dp);
60137c478bd9Sstevel@tonic-gate 			mutex_enter(&dpnp->pr_mutex);
60147c478bd9Sstevel@tonic-gate 			if (dpnp->pr_files != NULL &&
60157c478bd9Sstevel@tonic-gate 			    dpnp->pr_files[pnp->pr_index] == vp)
60167c478bd9Sstevel@tonic-gate 				dpnp->pr_files[pnp->pr_index] = NULL;
60177c478bd9Sstevel@tonic-gate 			mutex_exit(&dpnp->pr_mutex);
60187c478bd9Sstevel@tonic-gate 			break;
60197c478bd9Sstevel@tonic-gate 		}
60207c478bd9Sstevel@tonic-gate 		pnp->pr_parent = NULL;
60217c478bd9Sstevel@tonic-gate 	}
60227c478bd9Sstevel@tonic-gate 
60237c478bd9Sstevel@tonic-gate 	ASSERT(vp->v_count == 1);
60247c478bd9Sstevel@tonic-gate 
60257c478bd9Sstevel@tonic-gate 	/*
60267c478bd9Sstevel@tonic-gate 	 * If we allocated an old /proc/pid node, free it too.
60277c478bd9Sstevel@tonic-gate 	 */
60287c478bd9Sstevel@tonic-gate 	if (pnp->pr_pidfile != NULL) {
60297c478bd9Sstevel@tonic-gate 		ASSERT(type == PR_PIDDIR);
60307c478bd9Sstevel@tonic-gate 		ovp = pnp->pr_pidfile;
60317c478bd9Sstevel@tonic-gate 		opnp = VTOP(ovp);
60327c478bd9Sstevel@tonic-gate 		ASSERT(opnp->pr_type == PR_PIDFILE);
60337c478bd9Sstevel@tonic-gate 		pnp->pr_pidfile = NULL;
60347c478bd9Sstevel@tonic-gate 	}
60357c478bd9Sstevel@tonic-gate 
60367c478bd9Sstevel@tonic-gate 	mutex_exit(&pr_pidlock);
60377c478bd9Sstevel@tonic-gate 
60387c478bd9Sstevel@tonic-gate 	if (p != NULL) {
60397c478bd9Sstevel@tonic-gate 		/*
60407c478bd9Sstevel@tonic-gate 		 * Remove the vnodes from the lists of
60417c478bd9Sstevel@tonic-gate 		 * /proc vnodes for the process.
60427c478bd9Sstevel@tonic-gate 		 */
60437c478bd9Sstevel@tonic-gate 		int slot;
60447c478bd9Sstevel@tonic-gate 
60457c478bd9Sstevel@tonic-gate 		switch (type) {
60467c478bd9Sstevel@tonic-gate 		case PR_PIDDIR:
60477c478bd9Sstevel@tonic-gate 			pr_list_unlink(vp, &p->p_trace);
60487c478bd9Sstevel@tonic-gate 			break;
60497c478bd9Sstevel@tonic-gate 		case PR_LWPIDDIR:
60507c478bd9Sstevel@tonic-gate 			if ((slot = pnp->pr_common->prc_tslot) != -1) {
60517c478bd9Sstevel@tonic-gate 				lwpent_t *lep = p->p_lwpdir[slot].ld_entry;
60527c478bd9Sstevel@tonic-gate 				pr_list_unlink(vp, &lep->le_trace);
60537c478bd9Sstevel@tonic-gate 			}
60547c478bd9Sstevel@tonic-gate 			break;
60557c478bd9Sstevel@tonic-gate 		default:
60567c478bd9Sstevel@tonic-gate 			pr_list_unlink(vp, &p->p_plist);
60577c478bd9Sstevel@tonic-gate 			break;
60587c478bd9Sstevel@tonic-gate 		}
60597c478bd9Sstevel@tonic-gate 		if (ovp != NULL)
60607c478bd9Sstevel@tonic-gate 			pr_list_unlink(ovp, &p->p_plist);
60617c478bd9Sstevel@tonic-gate 		mutex_exit(&p->p_lock);
60627c478bd9Sstevel@tonic-gate 	}
60637c478bd9Sstevel@tonic-gate 
60647c478bd9Sstevel@tonic-gate 	mutex_exit(&vp->v_lock);
60657c478bd9Sstevel@tonic-gate 
60667c478bd9Sstevel@tonic-gate 	if (type == PR_CT && pnp->pr_contract != NULL) {
60677c478bd9Sstevel@tonic-gate 		contract_rele(pnp->pr_contract);
60687c478bd9Sstevel@tonic-gate 		pnp->pr_contract = NULL;
60697c478bd9Sstevel@tonic-gate 	}
60707c478bd9Sstevel@tonic-gate 
60717c478bd9Sstevel@tonic-gate 	if (opnp != NULL)
60727c478bd9Sstevel@tonic-gate 		prfreenode(opnp);
60737c478bd9Sstevel@tonic-gate 	prfreenode(pnp);
60747c478bd9Sstevel@tonic-gate 	if (dp != NULL) {
60757c478bd9Sstevel@tonic-gate 		VN_RELE(dp);
60767c478bd9Sstevel@tonic-gate 	}
60777c478bd9Sstevel@tonic-gate }
60787c478bd9Sstevel@tonic-gate 
60797c478bd9Sstevel@tonic-gate /* ARGSUSED */
60807c478bd9Sstevel@tonic-gate static int
prseek(vnode_t * vp,offset_t ooff,offset_t * noffp,caller_context_t * ct)6081da6c28aaSamw prseek(vnode_t *vp, offset_t ooff, offset_t *noffp, caller_context_t *ct)
60827c478bd9Sstevel@tonic-gate {
60837c478bd9Sstevel@tonic-gate 	return (0);
60847c478bd9Sstevel@tonic-gate }
60857c478bd9Sstevel@tonic-gate 
60867c478bd9Sstevel@tonic-gate /*
60877c478bd9Sstevel@tonic-gate  * We use the p_execdir member of proc_t to expand the %d token in core file
60887c478bd9Sstevel@tonic-gate  * paths (the directory path for the executable that dumped core; see
6089bbf21555SRichard Lowe  * coreadm(8) for details). We'd like gcore(1) to be able to expand %d in
60907c478bd9Sstevel@tonic-gate  * the same way as core dumping from the kernel, but there's no convenient
60917c478bd9Sstevel@tonic-gate  * and comprehensible way to export the path name for p_execdir. To solve
60927c478bd9Sstevel@tonic-gate  * this, we try to find the actual path to the executable that was used. In
60937c478bd9Sstevel@tonic-gate  * pr_lookup_pathdir(), we mark the a.out path name vnode with the PR_AOUT
60947c478bd9Sstevel@tonic-gate  * flag, and use that here to indicate that more work is needed beyond the
60957c478bd9Sstevel@tonic-gate  * call to vnodetopath().
60967c478bd9Sstevel@tonic-gate  */
60977c478bd9Sstevel@tonic-gate static int
prreadlink_lookup(prnode_t * pnp,char * buf,size_t size,cred_t * cr)60987c478bd9Sstevel@tonic-gate prreadlink_lookup(prnode_t *pnp, char *buf, size_t size, cred_t *cr)
60997c478bd9Sstevel@tonic-gate {
61007c478bd9Sstevel@tonic-gate 	proc_t *p;
61017c478bd9Sstevel@tonic-gate 	vnode_t *vp, *execvp, *vrootp;
61027c478bd9Sstevel@tonic-gate 	int ret;
61037c478bd9Sstevel@tonic-gate 	size_t len;
61047c478bd9Sstevel@tonic-gate 	dirent64_t *dp;
61057c478bd9Sstevel@tonic-gate 	size_t dlen = DIRENT64_RECLEN(MAXPATHLEN);
61067c478bd9Sstevel@tonic-gate 	char *dbuf;
61077c478bd9Sstevel@tonic-gate 
61087c478bd9Sstevel@tonic-gate 	p = curproc;
61097c478bd9Sstevel@tonic-gate 	mutex_enter(&p->p_lock);
61107c478bd9Sstevel@tonic-gate 	if ((vrootp = PTOU(p)->u_rdir) == NULL)
61117c478bd9Sstevel@tonic-gate 		vrootp = rootdir;
61127c478bd9Sstevel@tonic-gate 	VN_HOLD(vrootp);
61137c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
61147c478bd9Sstevel@tonic-gate 
61157c478bd9Sstevel@tonic-gate 	ret = vnodetopath(vrootp, pnp->pr_realvp, buf, size, cr);
61167c478bd9Sstevel@tonic-gate 
61177c478bd9Sstevel@tonic-gate 	/*
61187c478bd9Sstevel@tonic-gate 	 * If PR_AOUT isn't set, then we looked up the path for the vnode;
61197c478bd9Sstevel@tonic-gate 	 * otherwise, we looked up the path for (what we believe to be) the
61207c478bd9Sstevel@tonic-gate 	 * containing directory.
61217c478bd9Sstevel@tonic-gate 	 */
61227c478bd9Sstevel@tonic-gate 	if ((pnp->pr_flags & PR_AOUT) == 0) {
61237c478bd9Sstevel@tonic-gate 		VN_RELE(vrootp);
61247c478bd9Sstevel@tonic-gate 		return (ret);
61257c478bd9Sstevel@tonic-gate 	}
61267c478bd9Sstevel@tonic-gate 
61277c478bd9Sstevel@tonic-gate 	/*
61287c478bd9Sstevel@tonic-gate 	 * Fail if there's a problem locking the process. This will only
61297c478bd9Sstevel@tonic-gate 	 * occur if the process is changing so the information we would
61307c478bd9Sstevel@tonic-gate 	 * report would already be invalid.
61317c478bd9Sstevel@tonic-gate 	 */
61327c478bd9Sstevel@tonic-gate 	if (prlock(pnp, ZNO) != 0) {
61337c478bd9Sstevel@tonic-gate 		VN_RELE(vrootp);
61347c478bd9Sstevel@tonic-gate 		return (EIO);
61357c478bd9Sstevel@tonic-gate 	}
61367c478bd9Sstevel@tonic-gate 
61377c478bd9Sstevel@tonic-gate 	p = pnp->pr_common->prc_proc;
61387c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
61397c478bd9Sstevel@tonic-gate 
61407c478bd9Sstevel@tonic-gate 	execvp = p->p_exec;
61417c478bd9Sstevel@tonic-gate 	VN_HOLD(execvp);
61427c478bd9Sstevel@tonic-gate 
61437c478bd9Sstevel@tonic-gate 	/*
61447c478bd9Sstevel@tonic-gate 	 * If our initial lookup of the directory failed, fall back to
61457c478bd9Sstevel@tonic-gate 	 * the path name information for p_exec.
61467c478bd9Sstevel@tonic-gate 	 */
61477c478bd9Sstevel@tonic-gate 	if (ret != 0) {
61487c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
61497c478bd9Sstevel@tonic-gate 		prunlock(pnp);
61507c478bd9Sstevel@tonic-gate 		ret = vnodetopath(vrootp, execvp, buf, size, cr);
61517c478bd9Sstevel@tonic-gate 		VN_RELE(execvp);
61527c478bd9Sstevel@tonic-gate 		VN_RELE(vrootp);
61537c478bd9Sstevel@tonic-gate 		return (ret);
61547c478bd9Sstevel@tonic-gate 	}
61557c478bd9Sstevel@tonic-gate 
61567c478bd9Sstevel@tonic-gate 	len = strlen(buf);
61577c478bd9Sstevel@tonic-gate 
61587c478bd9Sstevel@tonic-gate 	/*
61597c478bd9Sstevel@tonic-gate 	 * We use u_comm as a guess for the last component of the full
61607c478bd9Sstevel@tonic-gate 	 * executable path name. If there isn't going to be enough space
61617c478bd9Sstevel@tonic-gate 	 * we fall back to using the p_exec so that we can have _an_
61627c478bd9Sstevel@tonic-gate 	 * answer even if it's not perfect.
61637c478bd9Sstevel@tonic-gate 	 */
61647c478bd9Sstevel@tonic-gate 	if (strlen(PTOU(p)->u_comm) + len + 1 < size) {
61657c478bd9Sstevel@tonic-gate 		buf[len] = '/';
61667c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, PTOU(p)->u_comm);
61677c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
61687c478bd9Sstevel@tonic-gate 		prunlock(pnp);
61697c478bd9Sstevel@tonic-gate 
61707c478bd9Sstevel@tonic-gate 		/*
61717c478bd9Sstevel@tonic-gate 		 * Do a forward lookup of our u_comm guess.
61727c478bd9Sstevel@tonic-gate 		 */
61737c478bd9Sstevel@tonic-gate 		if (lookupnameat(buf + len + 1, UIO_SYSSPACE, FOLLOW, NULLVPP,
61747c478bd9Sstevel@tonic-gate 		    &vp, pnp->pr_realvp) == 0) {
61757c478bd9Sstevel@tonic-gate 			if (vn_compare(vp, execvp)) {
61767c478bd9Sstevel@tonic-gate 				VN_RELE(vp);
61777c478bd9Sstevel@tonic-gate 				VN_RELE(execvp);
61787c478bd9Sstevel@tonic-gate 				VN_RELE(vrootp);
61797c478bd9Sstevel@tonic-gate 				return (0);
61807c478bd9Sstevel@tonic-gate 			}
61817c478bd9Sstevel@tonic-gate 
61827c478bd9Sstevel@tonic-gate 			VN_RELE(vp);
61837c478bd9Sstevel@tonic-gate 		}
61847c478bd9Sstevel@tonic-gate 	} else {
61857c478bd9Sstevel@tonic-gate 		mutex_enter(&p->p_lock);
61867c478bd9Sstevel@tonic-gate 		prunlock(pnp);
61877c478bd9Sstevel@tonic-gate 	}
61887c478bd9Sstevel@tonic-gate 
61897c478bd9Sstevel@tonic-gate 	dbuf = kmem_alloc(dlen, KM_SLEEP);
61907c478bd9Sstevel@tonic-gate 
61917c478bd9Sstevel@tonic-gate 	/*
61927c478bd9Sstevel@tonic-gate 	 * Try to find a matching vnode by iterating through the directory's
61937c478bd9Sstevel@tonic-gate 	 * entries. If that fails, fall back to the path information for
61947c478bd9Sstevel@tonic-gate 	 * p_exec.
61957c478bd9Sstevel@tonic-gate 	 */
61967c478bd9Sstevel@tonic-gate 	if ((ret = dirfindvp(vrootp, pnp->pr_realvp, execvp, cr, dbuf,
61977c478bd9Sstevel@tonic-gate 	    dlen, &dp)) == 0 && strlen(dp->d_name) + len + 1 < size) {
61987c478bd9Sstevel@tonic-gate 		buf[len] = '/';
61997c478bd9Sstevel@tonic-gate 		(void) strcpy(buf + len + 1, dp->d_name);
62007c478bd9Sstevel@tonic-gate 	} else {
62017c478bd9Sstevel@tonic-gate 		ret = vnodetopath(vrootp, execvp, buf, size, cr);
62027c478bd9Sstevel@tonic-gate 	}
62037c478bd9Sstevel@tonic-gate 
62047c478bd9Sstevel@tonic-gate 	kmem_free(dbuf, dlen);
62057c478bd9Sstevel@tonic-gate 	VN_RELE(execvp);
62067c478bd9Sstevel@tonic-gate 	VN_RELE(vrootp);
62077c478bd9Sstevel@tonic-gate 
62087c478bd9Sstevel@tonic-gate 	return (ret);
62097c478bd9Sstevel@tonic-gate }
62107c478bd9Sstevel@tonic-gate 
62117c478bd9Sstevel@tonic-gate /* ARGSUSED */
62127c478bd9Sstevel@tonic-gate static int
prreadlink(vnode_t * vp,uio_t * uiop,cred_t * cr,caller_context_t * ctp)6213da6c28aaSamw prreadlink(vnode_t *vp, uio_t *uiop, cred_t *cr, caller_context_t *ctp)
62147c478bd9Sstevel@tonic-gate {
62157c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
62167c478bd9Sstevel@tonic-gate 	char *buf;
62177c478bd9Sstevel@tonic-gate 	int ret = EINVAL;
62187c478bd9Sstevel@tonic-gate 	char idbuf[16];
62197c478bd9Sstevel@tonic-gate 	int length, rlength;
62207c478bd9Sstevel@tonic-gate 	contract_t *ct;
62217c478bd9Sstevel@tonic-gate 
62227c478bd9Sstevel@tonic-gate 	switch (pnp->pr_type) {
62237c478bd9Sstevel@tonic-gate 	case PR_SELF:
62247c478bd9Sstevel@tonic-gate 		(void) snprintf(idbuf, sizeof (idbuf), "%d", curproc->p_pid);
62257c478bd9Sstevel@tonic-gate 		ret = uiomove(idbuf, strlen(idbuf), UIO_READ, uiop);
62267c478bd9Sstevel@tonic-gate 		break;
62277c478bd9Sstevel@tonic-gate 	case PR_OBJECT:
62287c478bd9Sstevel@tonic-gate 	case PR_FD:
62297c478bd9Sstevel@tonic-gate 	case PR_CURDIR:
62307c478bd9Sstevel@tonic-gate 	case PR_ROOTDIR:
62317c478bd9Sstevel@tonic-gate 		if (pnp->pr_realvp->v_type == VDIR)
62327c478bd9Sstevel@tonic-gate 			ret = 0;
62337c478bd9Sstevel@tonic-gate 		break;
62347c478bd9Sstevel@tonic-gate 	case PR_PATH:
62357c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(MAXPATHLEN, KM_SLEEP);
62367c478bd9Sstevel@tonic-gate 
62377c478bd9Sstevel@tonic-gate 		if ((ret = prreadlink_lookup(pnp, buf, MAXPATHLEN, cr)) == 0)
62387c478bd9Sstevel@tonic-gate 			ret = uiomove(buf, strlen(buf), UIO_READ, uiop);
62397c478bd9Sstevel@tonic-gate 
62407c478bd9Sstevel@tonic-gate 		kmem_free(buf, MAXPATHLEN);
62417c478bd9Sstevel@tonic-gate 		break;
62427c478bd9Sstevel@tonic-gate 	case PR_CT:
62437c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_contract != NULL);
62447c478bd9Sstevel@tonic-gate 		ct = pnp->pr_contract;
62457c478bd9Sstevel@tonic-gate 		length = sizeof (CTFS_ROOT "//") + sizeof (idbuf) +
62467c478bd9Sstevel@tonic-gate 		    strlen(ct->ct_type->ct_type_name);
62477c478bd9Sstevel@tonic-gate 		buf = kmem_alloc(length, KM_SLEEP);
62487c478bd9Sstevel@tonic-gate 		rlength = snprintf(buf, length, CTFS_ROOT "/%s/%d",
62497c478bd9Sstevel@tonic-gate 		    ct->ct_type->ct_type_name, ct->ct_id);
62507c478bd9Sstevel@tonic-gate 		ASSERT(rlength < length);
62517c478bd9Sstevel@tonic-gate 		ret = uiomove(buf, rlength, UIO_READ, uiop);
62527c478bd9Sstevel@tonic-gate 		kmem_free(buf, length);
62537c478bd9Sstevel@tonic-gate 		break;
62547c478bd9Sstevel@tonic-gate 	default:
62557c478bd9Sstevel@tonic-gate 		break;
62567c478bd9Sstevel@tonic-gate 	}
62577c478bd9Sstevel@tonic-gate 
62587c478bd9Sstevel@tonic-gate 	return (ret);
62597c478bd9Sstevel@tonic-gate }
62607c478bd9Sstevel@tonic-gate 
6261da6c28aaSamw /*ARGSUSED2*/
62627c478bd9Sstevel@tonic-gate static int
prcmp(vnode_t * vp1,vnode_t * vp2,caller_context_t * ct)6263da6c28aaSamw prcmp(vnode_t *vp1, vnode_t *vp2, caller_context_t *ct)
62647c478bd9Sstevel@tonic-gate {
62657c478bd9Sstevel@tonic-gate 	prnode_t *pp1, *pp2;
62667c478bd9Sstevel@tonic-gate 
62677c478bd9Sstevel@tonic-gate 	if (vp1 == vp2)
62687c478bd9Sstevel@tonic-gate 		return (1);
62697c478bd9Sstevel@tonic-gate 
62707c478bd9Sstevel@tonic-gate 	if (!vn_matchops(vp1, prvnodeops) || !vn_matchops(vp2, prvnodeops))
62717c478bd9Sstevel@tonic-gate 		return (0);
62727c478bd9Sstevel@tonic-gate 
62737c478bd9Sstevel@tonic-gate 	pp1 = VTOP(vp1);
62747c478bd9Sstevel@tonic-gate 	pp2 = VTOP(vp2);
62757c478bd9Sstevel@tonic-gate 
62767c478bd9Sstevel@tonic-gate 	if (pp1->pr_type != pp2->pr_type)
62777c478bd9Sstevel@tonic-gate 		return (0);
62787c478bd9Sstevel@tonic-gate 	if (pp1->pr_type == PR_PROCDIR)
62797c478bd9Sstevel@tonic-gate 		return (1);
62807c478bd9Sstevel@tonic-gate 	if (pp1->pr_ino || pp2->pr_ino)
62817c478bd9Sstevel@tonic-gate 		return (pp2->pr_ino == pp1->pr_ino);
62827c478bd9Sstevel@tonic-gate 
62837c478bd9Sstevel@tonic-gate 	if (pp1->pr_common == NULL || pp2->pr_common == NULL)
62847c478bd9Sstevel@tonic-gate 		return (0);
62857c478bd9Sstevel@tonic-gate 
62867c478bd9Sstevel@tonic-gate 	return (pp1->pr_common->prc_slot == pp2->pr_common->prc_slot &&
62877c478bd9Sstevel@tonic-gate 	    pp1->pr_common->prc_tslot == pp2->pr_common->prc_tslot);
62887c478bd9Sstevel@tonic-gate }
62897c478bd9Sstevel@tonic-gate 
62907c478bd9Sstevel@tonic-gate static int
prrealvp(vnode_t * vp,vnode_t ** vpp,caller_context_t * ct)6291da6c28aaSamw prrealvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
62927c478bd9Sstevel@tonic-gate {
62937c478bd9Sstevel@tonic-gate 	vnode_t *rvp;
62947c478bd9Sstevel@tonic-gate 
62957c478bd9Sstevel@tonic-gate 	if ((rvp = VTOP(vp)->pr_realvp) != NULL) {
62967c478bd9Sstevel@tonic-gate 		vp = rvp;
6297da6c28aaSamw 		if (VOP_REALVP(vp, &rvp, ct) == 0)
62987c478bd9Sstevel@tonic-gate 			vp = rvp;
62997c478bd9Sstevel@tonic-gate 	}
63007c478bd9Sstevel@tonic-gate 
63017c478bd9Sstevel@tonic-gate 	*vpp = vp;
63027c478bd9Sstevel@tonic-gate 	return (0);
63037c478bd9Sstevel@tonic-gate }
63047c478bd9Sstevel@tonic-gate 
63057c478bd9Sstevel@tonic-gate /*
63067c478bd9Sstevel@tonic-gate  * Return the answer requested to poll().
63077c478bd9Sstevel@tonic-gate  * POLLIN, POLLRDNORM, and POLLOUT are recognized as in fs_poll().
63087c478bd9Sstevel@tonic-gate  * In addition, these have special meaning for /proc files:
63097c478bd9Sstevel@tonic-gate  *	POLLPRI		process or lwp stopped on an event of interest
63107c478bd9Sstevel@tonic-gate  *	POLLERR		/proc file descriptor is invalid
63117c478bd9Sstevel@tonic-gate  *	POLLHUP		process or lwp has terminated
63127c478bd9Sstevel@tonic-gate  */
6313da6c28aaSamw /*ARGSUSED5*/
63147c478bd9Sstevel@tonic-gate static int
prpoll(vnode_t * vp,short events,int anyyet,short * reventsp,pollhead_t ** phpp,caller_context_t * ct)63157c478bd9Sstevel@tonic-gate prpoll(vnode_t *vp, short events, int anyyet, short *reventsp,
6316da6c28aaSamw     pollhead_t **phpp, caller_context_t *ct)
63177c478bd9Sstevel@tonic-gate {
63187c478bd9Sstevel@tonic-gate 	prnode_t *pnp = VTOP(vp);
63197c478bd9Sstevel@tonic-gate 	prcommon_t *pcp = pnp->pr_common;
63207c478bd9Sstevel@tonic-gate 	pollhead_t *php = &pcp->prc_pollhead;
63217c478bd9Sstevel@tonic-gate 	proc_t *p;
63227c478bd9Sstevel@tonic-gate 	short revents;
63237c478bd9Sstevel@tonic-gate 	int error;
63247c478bd9Sstevel@tonic-gate 	int lockstate;
63257c478bd9Sstevel@tonic-gate 
63267c478bd9Sstevel@tonic-gate 	ASSERT(pnp->pr_type < PR_NFILES);
63277c478bd9Sstevel@tonic-gate 
63287c478bd9Sstevel@tonic-gate 	/*
63297c478bd9Sstevel@tonic-gate 	 * Support for old /proc interface.
63307c478bd9Sstevel@tonic-gate 	 */
63317c478bd9Sstevel@tonic-gate 	if (pnp->pr_pidfile != NULL) {
63327c478bd9Sstevel@tonic-gate 		vp = pnp->pr_pidfile;
63337c478bd9Sstevel@tonic-gate 		pnp = VTOP(vp);
63347c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_type == PR_PIDFILE);
63357c478bd9Sstevel@tonic-gate 		ASSERT(pnp->pr_common == pcp);
63367c478bd9Sstevel@tonic-gate 	}
63377c478bd9Sstevel@tonic-gate 
63387c478bd9Sstevel@tonic-gate 	*reventsp = revents = 0;
63397c478bd9Sstevel@tonic-gate 	*phpp = (pollhead_t *)NULL;
63407c478bd9Sstevel@tonic-gate 
63417c478bd9Sstevel@tonic-gate 	if (vp->v_type == VDIR) {
63427c478bd9Sstevel@tonic-gate 		*reventsp |= POLLNVAL;
63437c478bd9Sstevel@tonic-gate 		return (0);
63447c478bd9Sstevel@tonic-gate 	}
63457c478bd9Sstevel@tonic-gate 
6346f3bb54f3SPatrick Mooney 	/* avoid deadlock with prnotify() */
6347f3bb54f3SPatrick Mooney 	if (pollunlock(&lockstate) != 0) {
6348f3bb54f3SPatrick Mooney 		*reventsp = POLLNVAL;
6349f3bb54f3SPatrick Mooney 		return (0);
6350f3bb54f3SPatrick Mooney 	}
63517c478bd9Sstevel@tonic-gate 
63527c478bd9Sstevel@tonic-gate 	if ((error = prlock(pnp, ZNO)) != 0) {
63537c478bd9Sstevel@tonic-gate 		pollrelock(lockstate);
63547c478bd9Sstevel@tonic-gate 		switch (error) {
63557c478bd9Sstevel@tonic-gate 		case ENOENT:		/* process or lwp died */
63567c478bd9Sstevel@tonic-gate 			*reventsp = POLLHUP;
63577c478bd9Sstevel@tonic-gate 			error = 0;
63587c478bd9Sstevel@tonic-gate 			break;
63597c478bd9Sstevel@tonic-gate 		case EAGAIN:		/* invalidated */
63607c478bd9Sstevel@tonic-gate 			*reventsp = POLLERR;
63617c478bd9Sstevel@tonic-gate 			error = 0;
63627c478bd9Sstevel@tonic-gate 			break;
63637c478bd9Sstevel@tonic-gate 		}
63647c478bd9Sstevel@tonic-gate 		return (error);
63657c478bd9Sstevel@tonic-gate 	}
63667c478bd9Sstevel@tonic-gate 
63677c478bd9Sstevel@tonic-gate 	/*
63687c478bd9Sstevel@tonic-gate 	 * We have the process marked locked (P_PR_LOCK) and we are holding
63697c478bd9Sstevel@tonic-gate 	 * its p->p_lock.  We want to unmark the process but retain
63707c478bd9Sstevel@tonic-gate 	 * exclusive control w.r.t. other /proc controlling processes
63717c478bd9Sstevel@tonic-gate 	 * before reacquiring the polling locks.
63727c478bd9Sstevel@tonic-gate 	 *
63737c478bd9Sstevel@tonic-gate 	 * prunmark() does this for us.  It unmarks the process
63747c478bd9Sstevel@tonic-gate 	 * but retains p->p_lock so we still have exclusive control.
63757c478bd9Sstevel@tonic-gate 	 * We will drop p->p_lock at the end to relinquish control.
63767c478bd9Sstevel@tonic-gate 	 *
63777c478bd9Sstevel@tonic-gate 	 * We cannot call prunlock() at the end to relinquish control
63787c478bd9Sstevel@tonic-gate 	 * because prunlock(), like prunmark(), may drop and reacquire
63797c478bd9Sstevel@tonic-gate 	 * p->p_lock and that would lead to a lock order violation
63807c478bd9Sstevel@tonic-gate 	 * w.r.t. the polling locks we are about to reacquire.
63817c478bd9Sstevel@tonic-gate 	 */
63827c478bd9Sstevel@tonic-gate 	p = pcp->prc_proc;
63837c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
63847c478bd9Sstevel@tonic-gate 	prunmark(p);
63857c478bd9Sstevel@tonic-gate 
63867c478bd9Sstevel@tonic-gate 	pollrelock(lockstate);		/* reacquire dropped poll locks */
63877c478bd9Sstevel@tonic-gate 
63887c478bd9Sstevel@tonic-gate 	if ((p->p_flag & SSYS) || p->p_as == &kas)
63897c478bd9Sstevel@tonic-gate 		revents = POLLNVAL;
63907c478bd9Sstevel@tonic-gate 	else {
63917c478bd9Sstevel@tonic-gate 		short ev;
63927c478bd9Sstevel@tonic-gate 
63937c478bd9Sstevel@tonic-gate 		if ((ev = (events & (POLLIN|POLLRDNORM))) != 0)
63947c478bd9Sstevel@tonic-gate 			revents |= ev;
63957c478bd9Sstevel@tonic-gate 		/*
63967c478bd9Sstevel@tonic-gate 		 * POLLWRNORM (same as POLLOUT) really should not be
63977c478bd9Sstevel@tonic-gate 		 * used to indicate that the process or lwp stopped.
63987c478bd9Sstevel@tonic-gate 		 * However, USL chose to use POLLWRNORM rather than
63997c478bd9Sstevel@tonic-gate 		 * POLLPRI to indicate this, so we just accept either
64007c478bd9Sstevel@tonic-gate 		 * requested event to indicate stopped.  (grr...)
64017c478bd9Sstevel@tonic-gate 		 */
64027c478bd9Sstevel@tonic-gate 		if ((ev = (events & (POLLPRI|POLLOUT|POLLWRNORM))) != 0) {
64037c478bd9Sstevel@tonic-gate 			kthread_t *t;
64047c478bd9Sstevel@tonic-gate 
64057c478bd9Sstevel@tonic-gate 			if (pcp->prc_flags & PRC_LWP) {
64067c478bd9Sstevel@tonic-gate 				t = pcp->prc_thread;
64077c478bd9Sstevel@tonic-gate 				ASSERT(t != NULL);
64087c478bd9Sstevel@tonic-gate 				thread_lock(t);
64097c478bd9Sstevel@tonic-gate 			} else {
64107c478bd9Sstevel@tonic-gate 				t = prchoose(p);	/* returns locked t */
64117c478bd9Sstevel@tonic-gate 				ASSERT(t != NULL);
64127c478bd9Sstevel@tonic-gate 			}
64137c478bd9Sstevel@tonic-gate 
64147c478bd9Sstevel@tonic-gate 			if (ISTOPPED(t) || VSTOPPED(t))
64157c478bd9Sstevel@tonic-gate 				revents |= ev;
64167c478bd9Sstevel@tonic-gate 			thread_unlock(t);
64177c478bd9Sstevel@tonic-gate 		}
64187c478bd9Sstevel@tonic-gate 	}
64197c478bd9Sstevel@tonic-gate 
64207c478bd9Sstevel@tonic-gate 	*reventsp = revents;
6421a5eb7107SBryan Cantrill 	if ((!anyyet && revents == 0) || (events & POLLET)) {
64227c478bd9Sstevel@tonic-gate 		/*
64237c478bd9Sstevel@tonic-gate 		 * Arrange to wake up the polling lwp when
64247c478bd9Sstevel@tonic-gate 		 * the target process/lwp stops or terminates
64257c478bd9Sstevel@tonic-gate 		 * or when the file descriptor becomes invalid.
64267c478bd9Sstevel@tonic-gate 		 */
64277c478bd9Sstevel@tonic-gate 		pcp->prc_flags |= PRC_POLL;
64287c478bd9Sstevel@tonic-gate 		*phpp = php;
64297c478bd9Sstevel@tonic-gate 	}
64307c478bd9Sstevel@tonic-gate 	mutex_exit(&p->p_lock);
64317c478bd9Sstevel@tonic-gate 	return (0);
64327c478bd9Sstevel@tonic-gate }
64337c478bd9Sstevel@tonic-gate 
64347c478bd9Sstevel@tonic-gate /* in prioctl.c */
6435da6c28aaSamw extern int prioctl(vnode_t *, int, intptr_t, int, cred_t *, int *,
6436da6c28aaSamw 	caller_context_t *);
64377c478bd9Sstevel@tonic-gate 
64387c478bd9Sstevel@tonic-gate /*
64397c478bd9Sstevel@tonic-gate  * /proc vnode operations vector
64407c478bd9Sstevel@tonic-gate  */
64417c478bd9Sstevel@tonic-gate const fs_operation_def_t pr_vnodeops_template[] = {
6442aa59c4cbSrsb 	VOPNAME_OPEN,		{ .vop_open = propen },
6443aa59c4cbSrsb 	VOPNAME_CLOSE,		{ .vop_close = prclose },
6444aa59c4cbSrsb 	VOPNAME_READ,		{ .vop_read = prread },
6445aa59c4cbSrsb 	VOPNAME_WRITE,		{ .vop_write = prwrite },
6446aa59c4cbSrsb 	VOPNAME_IOCTL,		{ .vop_ioctl = prioctl },
6447aa59c4cbSrsb 	VOPNAME_GETATTR,	{ .vop_getattr = prgetattr },
6448aa59c4cbSrsb 	VOPNAME_ACCESS,		{ .vop_access = praccess },
6449aa59c4cbSrsb 	VOPNAME_LOOKUP,		{ .vop_lookup = prlookup },
6450aa59c4cbSrsb 	VOPNAME_CREATE,		{ .vop_create = prcreate },
6451aa59c4cbSrsb 	VOPNAME_READDIR,	{ .vop_readdir = prreaddir },
6452aa59c4cbSrsb 	VOPNAME_READLINK,	{ .vop_readlink = prreadlink },
6453aa59c4cbSrsb 	VOPNAME_FSYNC,		{ .vop_fsync = prfsync },
6454aa59c4cbSrsb 	VOPNAME_INACTIVE,	{ .vop_inactive = prinactive },
6455aa59c4cbSrsb 	VOPNAME_SEEK,		{ .vop_seek = prseek },
6456aa59c4cbSrsb 	VOPNAME_CMP,		{ .vop_cmp = prcmp },
6457aa59c4cbSrsb 	VOPNAME_FRLOCK,		{ .error = fs_error },
6458aa59c4cbSrsb 	VOPNAME_REALVP,		{ .vop_realvp = prrealvp },
6459aa59c4cbSrsb 	VOPNAME_POLL,		{ .vop_poll = prpoll },
6460aa59c4cbSrsb 	VOPNAME_DISPOSE,	{ .error = fs_error },
6461aa59c4cbSrsb 	VOPNAME_SHRLOCK,	{ .error = fs_error },
64627c478bd9Sstevel@tonic-gate 	NULL,			NULL
64637c478bd9Sstevel@tonic-gate };
6464