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