prvnops.c revision 406882169e00272f14067d948324d690893e6fe3
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#include <sys/pathname.h>
#include <sys/sysmacros.h>
#include <sys/vfs_opreg.h>
#include <sys/contract_impl.h>
#if defined(__sparc)
#endif
#if defined(__x86)
#endif
/*
* Created by prinit.
*/
/*
* Directory characteristics (patterned after the s5 file system).
*/
#define PRROOTINO 2
#define PRDIRSIZE 14
struct prdirect {
};
/*
* Directory characteristics.
*/
typedef struct prdirent {
unsigned short d_reclen; /* length of this record */
} prdirent_t;
/*
* Contents of a /proc/<pid> directory.
* Reuse d_ino field for the /proc file type.
*/
static prdirent_t piddir[] = {
"." },
".." },
"as" },
"ctl" },
"status" },
"lstatus" },
"psinfo" },
"lpsinfo" },
"map" },
"rmap" },
"xmap" },
"cred" },
"sigact" },
"auxv" },
"usage" },
"lusage" },
"pagedata" },
"watch" },
"cwd" },
"root" },
"fd" },
"object" },
"lwp" },
"priv" },
"path" },
"contracts" },
#if defined(__x86)
"ldt" },
#endif
};
/*
* Contents of a /proc/<pid>/lwp/<lwpid> directory.
*/
static prdirent_t lwpiddir[] = {
"." },
".." },
"lwpctl" },
"lwpstatus" },
"lwpsinfo" },
"lwpusage" },
"xregs" },
"templates" },
#if defined(__sparc)
"gwindows" },
"asrs" },
#endif
};
/*
* Span of entries in the array files (lstatus, lpsinfo, lusage).
* We make the span larger than the size of the structure on purpose,
* to make sure that programs cannot use the structure size by mistake.
* Align _ILP32 structures at 8 bytes, _LP64 structures at 16 bytes.
*/
#ifdef _LP64
#else
#endif
static void rebuild_objdir(struct as *);
static void prfreecommon(prcommon_t *);
static int
{
proc_t *p;
int error = 0;
/*
* Nothing to do for the /proc directory itself.
*/
if (type == PR_PROCDIR)
return (0);
/*
* If we are opening an underlying mapped object, reject opens
* for writing regardless of the objects's access modes.
* reject the open for any but a regular file or directory.
* Just do it if we are opening the current or root directory.
*/
switch (type) {
case PR_OBJECT:
case PR_FD:
case PR_CURDIR:
case PR_ROOTDIR:
else {
/*
* Need to hold rvp since VOP_OPEN() may release it.
*/
if (error) {
} else {
}
}
return (error);
default:
break;
}
/*
* If we are opening the pagedata file, allocate a prnode now
* to avoid calling kmem_alloc() while holding p->p_lock.
*/
/*
* If the process exists, lock it now.
* Otherwise we have a race condition with prclose().
*/
if (p == NULL) {
return (ENOENT);
}
/*
* Maintain a count of opens for write. Allow exactly one
* O_WRITE|O_EXCL request and fail subsequent ones.
* Don't fail opens of old (bletch!) /proc lwp files.
* Special case for open by the process itself:
* Always allow the open by self and discount this
* open for other opens for writing.
*/
if (p == curproc) {
pcp->prc_selfopens++;
} else if (type == PR_LWPIDFILE) {
/* EMPTY */;
goto out;
}
/* semantic for old /proc interface */
if (error)
goto out;
}
pcp->prc_writers++;
/*
* The vnode may have become invalid between the
* VOP_LOOKUP() of the /proc vnode and the VOP_OPEN().
* If so, do now what prinvalidate() should have done.
*/
if (p != curproc)
pcp->prc_selfopens++;
}
}
/*
* Do file-specific things.
*/
switch (type) {
default:
break;
case PR_PAGEDATA:
case PR_OPAGEDATA:
/*
* Enable data collection for page data file;
* get unique id from the hat layer.
*/
{
int id;
/*
* Drop p->p_lock to call hat_startstat()
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
mutex_enter(&p->p_lock);
} else {
mutex_enter(&p->p_lock);
/*
* Use our newly allocated prnode.
*/
/*
* prgetnode() initialized most of the prnode.
* Duplicate the remainder.
*/
}
}
break;
}
out:
return (error);
}
/* ARGSUSED */
static int
{
proc_t *p;
kthread_t *t;
/*
* Nothing to do for the /proc directory itself.
*/
if (type == PR_PROCDIR)
return (0);
/*
* If the process exists, lock it now.
* Otherwise we have a race condition with propen().
* Hold pr_pidlock across the reference to prc_selfopens,
* and prc_writers in case there is no process anymore,
* to cover the case of concurrent calls to prclose()
* after the process has been reaped by freeproc().
*/
/*
* There is nothing more to do until the last close of
* the file table entry except to clear the pr_owner
* field of the prnode and notify any waiters
* (their file descriptor may have just been closed).
*/
if (count > 1) {
if (p != NULL) {
}
return (0);
}
/*
* Decrement the count of self-opens for writing.
* Decrement the total count of opens for writing.
* Cancel exclusive opens when only self-opens remain.
*/
/*
* prc_selfopens also contains the count of
* invalid writers. See prinvalidate().
*/
--pcp->prc_selfopens;
}
}
/*
* If there is no process, there is nothing more to do.
*/
if (p == NULL)
return (0);
/*
* Do file-specific things.
*/
switch (type) {
default:
break;
case PR_PAGEDATA:
case PR_OPAGEDATA:
/*
* This is a page data file.
* Free the hat level statistics.
* Drop p->p_lock before calling hat_freestat().
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
break;
}
/*
* On last close of all writable file descriptors,
* Can't do this is the /proc agent lwp still exists.
*/
if (pcp->prc_writers == 0 &&
int killproc;
/*
* Cancel any watchpoints currently in effect.
* The process might disappear during this operation.
*/
return (0);
/*
* If any tracing flags are set, clear them.
*/
if (p->p_proc_flag & P_PR_TRACE) {
}
premptyset(&p->p_sigmask);
premptyset(&p->p_fltmask);
/*
* Cancel any outstanding single-step requests.
*/
/*
* Drop p_lock because prnostep() touches the stack.
* The loop is safe because the process is P_PR_LOCK'd.
*/
mutex_exit(&p->p_lock);
do {
mutex_enter(&p->p_lock);
}
/*
* Set runnable all lwps stopped by /proc.
*/
if (killproc)
else
allsetrun(p);
}
return (0);
}
/*
* Array of read functions, indexed by /proc file type.
*/
#if defined(__x86)
pr_read_ldt(),
#endif
#if defined(__sparc)
pr_read_gwindows(), pr_read_asrs(),
#endif
static int (*pr_read_function[PR_NFILES])() = {
pr_read_inval, /* /proc */
pr_read_inval, /* /proc/self */
pr_read_piddir, /* /proc/<pid> (old /proc read()) */
pr_read_as, /* /proc/<pid>/as */
pr_read_inval, /* /proc/<pid>/ctl */
pr_read_status, /* /proc/<pid>/status */
pr_read_lstatus, /* /proc/<pid>/lstatus */
pr_read_psinfo, /* /proc/<pid>/psinfo */
pr_read_lpsinfo, /* /proc/<pid>/lpsinfo */
pr_read_map, /* /proc/<pid>/map */
pr_read_rmap, /* /proc/<pid>/rmap */
pr_read_xmap, /* /proc/<pid>/xmap */
pr_read_cred, /* /proc/<pid>/cred */
pr_read_sigact, /* /proc/<pid>/sigact */
pr_read_auxv, /* /proc/<pid>/auxv */
#if defined(__x86)
pr_read_ldt, /* /proc/<pid>/ldt */
#endif
pr_read_usage, /* /proc/<pid>/usage */
pr_read_lusage, /* /proc/<pid>/lusage */
pr_read_pagedata, /* /proc/<pid>/pagedata */
pr_read_watch, /* /proc/<pid>/watch */
pr_read_inval, /* /proc/<pid>/cwd */
pr_read_inval, /* /proc/<pid>/root */
pr_read_inval, /* /proc/<pid>/fd */
pr_read_inval, /* /proc/<pid>/fd/nn */
pr_read_inval, /* /proc/<pid>/object */
pr_read_inval, /* /proc/<pid>/object/xxx */
pr_read_inval, /* /proc/<pid>/lwp */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid> */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
pr_read_lwpstatus, /* /proc/<pid>/lwp/<lwpid>/lwpstatus */
pr_read_lwpsinfo, /* /proc/<pid>/lwp/<lwpid>/lwpsinfo */
pr_read_lwpusage, /* /proc/<pid>/lwp/<lwpid>/lwpusage */
pr_read_xregs, /* /proc/<pid>/lwp/<lwpid>/xregs */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/templates */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/templates/<id> */
#if defined(__sparc)
pr_read_gwindows, /* /proc/<pid>/lwp/<lwpid>/gwindows */
pr_read_asrs, /* /proc/<pid>/lwp/<lwpid>/asrs */
#endif
pr_read_priv, /* /proc/<pid>/priv */
pr_read_inval, /* /proc/<pid>/path */
pr_read_inval, /* /proc/<pid>/path/xxx */
pr_read_inval, /* /proc/<pid>/contracts */
pr_read_inval, /* /proc/<pid>/contracts/<ctid> */
pr_read_pidfile, /* old process file */
pr_read_pidfile, /* old lwp file */
pr_read_opagedata, /* old pagedata file */
};
/* ARGSUSED */
static int
{
/*
* No read() on any /proc directory, use getdents(2) instead.
* Cannot read a control file either.
* An underlying mapped object file cannot get here.
*/
return (EINVAL);
}
static int
{
int error = 0;
}
return (error);
}
static int
{
int error;
/*
* /proc I/O cannot be done to a system process.
* A 32-bit process cannot read a 64-bit process.
*/
error = 0;
#ifdef _SYSCALL32_IMPL
PROCESS_NOT_32BIT(p)) {
#endif
} else {
/*
* We don't hold p_lock over an i/o operation because
* that could lead to deadlock with the clock thread.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
return (error);
}
static int
{
int error;
/*
* We kmem_alloc() the pstatus structure because
* it is so big it might blow the kernel stack.
*/
}
return (error);
}
static int
{
proc_t *p;
kthread_t *t;
int error;
int nlwp;
int i;
return (error);
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_lwpcnt can't change while process is locked */
continue;
}
return (error);
}
static int
{
proc_t *p;
int error = 0;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
else {
prgetpsinfo(p, &psinfo);
}
return (error);
}
static int
{
proc_t *p;
kthread_t *t;
lwpsinfo_t *sp;
int error;
int nlwp;
int i;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
return (ENOENT);
return (ENOENT);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_lwpcnt can't change while process is locked */
continue;
prgetlwpsinfo(t, sp);
else {
}
}
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
mutex_exit(&p->p_lock);
switch (type) {
case PR_XMAP:
break;
case PR_RMAP:
break;
case PR_MAP:
break;
}
mutex_enter(&p->p_lock);
return (error);
}
static int
{
}
static int
{
}
static int
{
}
static int
{
proc_t *p;
int error;
/*
* We kmem_alloc() the prcred_t structure because
* the number of supplementary groups is variable.
*/
pcrp =
KM_SLEEP);
goto out;
out:
return (error);
}
static int
{
proc_t *p;
int error;
goto out;
out:
return (error);
}
static int
{
proc_t *p;
int sig;
int error;
/*
* We kmem_alloc() the sigaction array because
* it is so big it might blow the kernel stack.
*/
goto out;
goto out;
}
out:
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
}
#if defined(__x86)
/*
* XX64
* This is almost certainly broken for the amd64 kernel, because
* we have two kinds of LDT structures to export -- one for compatibility
* mode, and one for long mode, sigh.
*
* For now lets just have a ldt of size 0 for 64-bit processes.
*/
static int
{
proc_t *p;
int error;
return (error);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_ldtlock);
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
return (0);
}
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
return (error);
}
#endif /* __x86 */
static int
{
proc_t *p;
kthread_t *t;
int error;
/* allocate now, before locking the process */
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL) {
goto out;
}
error = 0;
goto out;
}
/*
* Add the usage information for each active lwp.
*/
do {
if (t->t_proc_flag & TP_LWPEXIT)
continue;
praddusage(t, pup);
}
out:
return (error);
}
static int
{
int nlwp;
proc_t *p;
kthread_t *t;
int error;
int i;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
return (ENOENT);
return (ENOENT);
}
return (0);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_lwpcnt can't change while process is locked */
/*
* First the summation over defunct lwps.
*/
/*
* Fill one prusage struct for each active lwp.
*/
continue;
--nlwp;
prgetusage(t, pup);
}
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
static int
{
proc_t *p;
int error;
int nwarea;
struct watched_area *pwarea;
return (error);
return (0);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_nwarea can't change while process is locked */
/* gather the watched areas */
}
return (error);
}
static int
{
int error;
/*
* We kmem_alloc() the lwpstatus structure because
* it is so big it might blow the kernel stack.
*/
goto out;
goto out;
}
out:
return (error);
}
static int
{
proc_t *p;
kthread_t *t;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
return (ENOENT);
return (ENOENT);
}
return (0);
}
prgetlwpsinfo(t, &lwpsinfo);
else {
}
}
static int
{
proc_t *p;
int error;
/* allocate now, before locking the process */
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL) {
goto out;
}
goto out;
}
error = 0;
goto out;
}
out:
return (error);
}
/* ARGSUSED */
static int
{
#if defined(__sparc)
proc_t *p;
kthread_t *t;
int error;
char *xreg;
goto out;
goto out;
}
/* drop p->p_lock while (possibly) touching the stack */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
out:
return (error);
#else
return (0);
#endif
}
#if defined(__sparc)
static int
{
proc_t *p;
kthread_t *t;
int error;
goto out;
/*
* Drop p->p_lock while touching the stack.
* The P_PR_LOCK flag prevents the lwp from
* disappearing while we do this.
*/
mutex_exit(&p->p_lock);
size = sizeof (gwindows_t) -
mutex_enter(&p->p_lock);
goto out;
}
mutex_enter(&p->p_lock);
out:
return (error);
}
/* ARGSUSED */
static int
{
int error;
/* the asrs file exists only for sparc v9 _LP64 processes */
if (p->p_model != DATAMODEL_LP64 ||
return (0);
}
/*
* Drop p->p_lock while touching the stack.
* The P_PR_LOCK flag prevents the lwp from
* disappearing while we do this.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
return (error);
}
#endif /* __sparc */
static int
{
/* use the underlying PR_PIDFILE to read the process */
}
static int
{
int error;
/*
* /proc I/O cannot be done to a system process.
*/
} else {
/*
* We drop p_lock because we don't want to hold
* it over an I/O operation because that could
* lead to deadlock with the clock thread.
* The process will not disappear and its address
* space will not change because it is marked P_PR_LOCK.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
return (error);
}
#ifdef _SYSCALL32_IMPL
/*
* Array of ILP32 read functions, indexed by /proc file type.
*/
static int pr_read_status_32(),
#if defined(__sparc)
#endif
static int (*pr_read_function_32[PR_NFILES])() = {
pr_read_inval, /* /proc */
pr_read_inval, /* /proc/self */
pr_read_piddir, /* /proc/<pid> (old /proc read()) */
pr_read_as, /* /proc/<pid>/as */
pr_read_inval, /* /proc/<pid>/ctl */
pr_read_status_32, /* /proc/<pid>/status */
pr_read_lstatus_32, /* /proc/<pid>/lstatus */
pr_read_psinfo_32, /* /proc/<pid>/psinfo */
pr_read_lpsinfo_32, /* /proc/<pid>/lpsinfo */
pr_read_map_32, /* /proc/<pid>/map */
pr_read_rmap_32, /* /proc/<pid>/rmap */
pr_read_xmap_32, /* /proc/<pid>/xmap */
pr_read_cred, /* /proc/<pid>/cred */
pr_read_sigact_32, /* /proc/<pid>/sigact */
pr_read_auxv_32, /* /proc/<pid>/auxv */
#if defined(__x86)
pr_read_ldt, /* /proc/<pid>/ldt */
#endif
pr_read_usage_32, /* /proc/<pid>/usage */
pr_read_lusage_32, /* /proc/<pid>/lusage */
pr_read_pagedata_32, /* /proc/<pid>/pagedata */
pr_read_watch_32, /* /proc/<pid>/watch */
pr_read_inval, /* /proc/<pid>/cwd */
pr_read_inval, /* /proc/<pid>/root */
pr_read_inval, /* /proc/<pid>/fd */
pr_read_inval, /* /proc/<pid>/fd/nn */
pr_read_inval, /* /proc/<pid>/object */
pr_read_inval, /* /proc/<pid>/object/xxx */
pr_read_inval, /* /proc/<pid>/lwp */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid> */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
pr_read_lwpstatus_32, /* /proc/<pid>/lwp/<lwpid>/lwpstatus */
pr_read_lwpsinfo_32, /* /proc/<pid>/lwp/<lwpid>/lwpsinfo */
pr_read_lwpusage_32, /* /proc/<pid>/lwp/<lwpid>/lwpusage */
pr_read_xregs, /* /proc/<pid>/lwp/<lwpid>/xregs */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/templates */
pr_read_inval, /* /proc/<pid>/lwp/<lwpid>/templates/<id> */
#if defined(__sparc)
pr_read_gwindows_32, /* /proc/<pid>/lwp/<lwpid>/gwindows */
pr_read_asrs, /* /proc/<pid>/lwp/<lwpid>/asrs */
#endif
pr_read_priv, /* /proc/<pid>/priv */
pr_read_inval, /* /proc/<pid>/path */
pr_read_inval, /* /proc/<pid>/path/xxx */
pr_read_inval, /* /proc/<pid>/contracts */
pr_read_inval, /* /proc/<pid>/contracts/<ctid> */
pr_read_pidfile, /* old process file */
pr_read_pidfile, /* old lwp file */
pr_read_opagedata_32, /* old pagedata file */
};
static int
{
proc_t *p;
int error;
/*
* We kmem_alloc() the pstatus structure because
* it is so big it might blow the kernel stack.
*/
/*
* A 32-bit process cannot get the status of a 64-bit process.
* The fields for the 64-bit quantities are not large enough.
*/
if (PROCESS_NOT_32BIT(p)) {
} else {
}
}
return (error);
}
static int
{
proc_t *p;
kthread_t *t;
int error;
int nlwp;
int i;
return (error);
/*
* A 32-bit process cannot get the status of a 64-bit process.
* The fields for the 64-bit quantities are not large enough.
*/
if (PROCESS_NOT_32BIT(p)) {
return (EOVERFLOW);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_lwpcnt can't change while process is locked */
continue;
}
return (error);
}
static int
{
proc_t *p;
int error = 0;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
else {
prgetpsinfo32(p, &psinfo);
}
return (error);
}
static int
{
proc_t *p;
kthread_t *t;
int error;
int nlwp;
int i;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
return (ENOENT);
return (ENOENT);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_lwpcnt can't change while process is locked */
continue;
prgetlwpsinfo32(t, sp);
else {
}
}
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
if (PROCESS_NOT_32BIT(p)) {
return (EOVERFLOW);
}
mutex_exit(&p->p_lock);
switch (type) {
case PR_XMAP:
break;
case PR_RMAP:
break;
case PR_MAP:
break;
}
mutex_enter(&p->p_lock);
return (error);
}
static int
{
}
static int
{
}
static int
{
}
static int
{
proc_t *p;
struct sigaction32 *sap;
int sig;
int error;
/*
* We kmem_alloc() the sigaction32 array because
* it is so big it might blow the kernel stack.
*/
goto out;
if (PROCESS_NOT_32BIT(p)) {
goto out;
}
goto out;
}
out:
return (error);
}
static int
{
proc_t *p;
int error;
int i;
return (error);
if (PROCESS_NOT_32BIT(p)) {
return (EOVERFLOW);
}
return (0);
}
for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
}
}
static int
{
proc_t *p;
kthread_t *t;
int error;
/* allocate now, before locking the process */
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL) {
goto out;
}
error = 0;
goto out;
}
/*
* Add the usage information for each active lwp.
*/
do {
if (t->t_proc_flag & TP_LWPEXIT)
continue;
praddusage(t, pup);
}
out:
return (error);
}
static int
{
int nlwp;
proc_t *p;
kthread_t *t;
int error;
int i;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
return (ENOENT);
return (ENOENT);
}
return (0);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_lwpcnt can't change while process is locked */
/*
* First the summation over defunct lwps.
*/
/*
* Fill one prusage struct for each active lwp.
*/
continue;
--nlwp;
upup = (prusage32_t *)
prgetusage(t, pup);
}
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
if (PROCESS_NOT_32BIT(p)) {
return (EOVERFLOW);
}
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
static int
{
proc_t *p;
int error;
return (error);
return (0);
}
if (PROCESS_NOT_32BIT(p)) {
return (EOVERFLOW);
}
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
static int
{
proc_t *p;
int error;
int nwarea;
struct watched_area *pwarea;
return (error);
if (PROCESS_NOT_32BIT(p)) {
return (EOVERFLOW);
}
return (0);
}
/* drop p->p_lock to do kmem_alloc(KM_SLEEP) */
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
/* p->p_nwarea can't change while process is locked */
/* gather the watched areas */
}
return (error);
}
static int
{
proc_t *p;
int error;
/*
* We kmem_alloc() the lwpstatus structure because
* it is so big it might blow the kernel stack.
*/
goto out;
/*
* A 32-bit process cannot get the status of a 64-bit process.
* The fields for the 64-bit quantities are not large enough.
*/
if (PROCESS_NOT_32BIT(p)) {
goto out;
}
goto out;
}
out:
return (error);
}
static int
{
proc_t *p;
kthread_t *t;
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL)
return (ENOENT);
return (ENOENT);
}
return (0);
}
prgetlwpsinfo32(t, &lwpsinfo);
else {
}
}
static int
{
proc_t *p;
int error;
/* allocate now, before locking the process */
/*
* We don't want the full treatment of prlock(pnp) here.
* This file is world-readable and never goes invalid.
* It doesn't matter if we are in the middle of an exec().
*/
if (p == NULL) {
goto out;
}
goto out;
}
error = 0;
goto out;
}
out:
return (error);
}
#if defined(__sparc)
static int
{
proc_t *p;
kthread_t *t;
int error;
goto out;
if (PROCESS_NOT_32BIT(p)) {
goto out;
}
/*
* Drop p->p_lock while touching the stack.
* The P_PR_LOCK flag prevents the lwp from
* disappearing while we do this.
*/
mutex_exit(&p->p_lock);
size = sizeof (gwindows32_t) -
mutex_enter(&p->p_lock);
goto out;
}
mutex_enter(&p->p_lock);
out:
return (error);
}
#endif /* __sparc */
#endif /* _SYSCALL32_IMPL */
/* ARGSUSED */
static int
{
#ifdef _SYSCALL32_IMPL
/*
* What is read from the /proc files depends on the data
* model of the caller. An LP64 process will see LP64
* data. An ILP32 process will see ILP32 data.
*/
else
#else
#endif
}
/* ARGSUSED */
static int
{
int old = 0;
int error;
/*
* Only a handful of /proc files are writable, enumerate them here.
*/
case PR_PIDDIR: /* directory write()s: visceral revulsion. */
/* use the underlying PR_PIDFILE to write the process */
/* FALLTHROUGH */
case PR_PIDFILE:
case PR_LWPIDFILE:
old = 1;
/* FALLTHROUGH */
case PR_AS:
/*
* /proc I/O cannot be done to a system process.
*/
#ifdef _SYSCALL32_IMPL
PROCESS_NOT_32BIT(p)) {
#endif
} else {
/*
* See comments above (pr_read_pidfile)
* about this locking dance.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
}
}
return (error);
case PR_CTL:
case PR_LWPCTL:
/*
* Perform the action on the control file
* by passing curthreads credentials
* and not target process's credentials.
*/
#ifdef _SYSCALL32_IMPL
else
#else
#endif
/*
* This hack makes sure that the EINTR is passed
* all the way back to the caller's write() call.
*/
return (error);
default:
}
/* NOTREACHED */
}
static int
{
proc_t *p;
int error;
int ngroups;
/*
* This ugly bit of code allows us to keep both versions of this
* function from the same source.
*/
#ifdef _LP64
#else
(sizeof (obj64))
#endif
/*
* Return all the attributes. Should be refined
* so that it returns only those asked for.
* Most of this is complete fakery anyway.
*/
/*
* For files in the /proc/<pid>/object directory,
* return the attributes of the underlying object.
* For files in the /proc/<pid>/fd directory,
* return the attributes of the underlying file, but
* make it look inaccessible if it is not a regular file.
* Make directories look like symlinks.
*/
switch (type) {
case PR_CURDIR:
case PR_ROOTDIR:
break;
/* restrict full knowledge of the attributes to owner or root */
return (error);
/* FALLTHROUGH */
case PR_OBJECT:
case PR_FD:
if (error)
return (error);
else
}
}
return (0);
default:
break;
}
/*
* Large Files: Internally proc now uses VPROC to indicate
* a proc file. Since we have been returning VREG through
* VOP_GETATTR() until now, we continue to do this so as
* not to break apps depending on this return value.
*/
if (type == PR_PROCDIR) {
gethrestime(&now);
return (0);
}
/*
* /proc/<pid>/self is a symbolic link, and has no prcommon member
*/
gethrestime(&now);
return (0);
}
if (p == NULL)
return (ENOENT);
mutex_enter(&p->p_crlock);
mutex_exit(&p->p_crlock);
} else {
}
switch (type) {
case PR_PIDDIR:
/* va_nlink: count 'lwp', 'object' and 'fd' directory links */
break;
case PR_OBJECTDIR:
else {
mutex_exit(&p->p_lock);
if (as->a_updatedir)
mutex_enter(&p->p_lock);
}
break;
case PR_PATHDIR:
else {
mutex_exit(&p->p_lock);
if (as->a_updatedir)
mutex_enter(&p->p_lock);
}
break;
case PR_PATH:
case PR_CURDIR:
case PR_ROOTDIR:
case PR_CT:
break;
case PR_FDDIR:
break;
case PR_LWPDIR:
/*
* va_nlink: count each lwp as a directory link.
* va_size: size of p_lwpdir + 2
*/
break;
case PR_LWPIDDIR:
break;
case PR_CTDIR:
break;
case PR_TMPLDIR:
break;
case PR_AS:
case PR_PIDFILE:
case PR_LWPIDFILE:
else
break;
case PR_STATUS:
break;
case PR_LSTATUS:
break;
case PR_PSINFO:
break;
case PR_LPSINFO:
break;
case PR_MAP:
case PR_RMAP:
case PR_XMAP:
else {
mutex_exit(&p->p_lock);
else
mutex_enter(&p->p_lock);
}
break;
case PR_CRED:
mutex_enter(&p->p_crlock);
if (ngroups > 1)
mutex_exit(&p->p_crlock);
break;
case PR_PRIV:
break;
case PR_SIGACT:
break;
case PR_AUXV:
break;
#if defined(__x86)
case PR_LDT:
mutex_exit(&p->p_lock);
mutex_enter(&p->p_ldtlock);
mutex_exit(&p->p_ldtlock);
mutex_enter(&p->p_lock);
break;
#endif
case PR_USAGE:
break;
case PR_LUSAGE:
break;
case PR_PAGEDATA:
else {
/*
* We can drop p->p_lock before grabbing the
* address space lock because p->p_as will not
* change while the process is marked P_PR_LOCK.
*/
mutex_exit(&p->p_lock);
#ifdef _LP64
#else
#endif
mutex_enter(&p->p_lock);
}
break;
case PR_OPAGEDATA:
else {
mutex_exit(&p->p_lock);
#ifdef _LP64
#else
#endif
mutex_enter(&p->p_lock);
}
break;
case PR_WATCH:
break;
case PR_LWPSTATUS:
break;
case PR_LWPSINFO:
break;
case PR_LWPUSAGE:
break;
case PR_XREGS:
if (prhasx(p))
else
break;
#if defined(__sparc)
case PR_GWINDOWS:
{
kthread_t *t;
int n;
/*
* If there is no lwp then just make the size zero.
* This can happen if the lwp exits between the VOP_LOOKUP()
* of the /proc/<pid>/lwp/<lwpid>/gwindows file and the
* VOP_GETATTR() of the resulting vnode.
*/
break;
}
/*
* Drop p->p_lock while touching the stack.
* The P_PR_LOCK flag prevents the lwp from
* disappearing while we do this.
*/
mutex_exit(&p->p_lock);
if ((n = prnwindows(ttolwp(t))) == 0)
else
(SPARC_MAXREGWINDOW - n) *
mutex_enter(&p->p_lock);
break;
}
case PR_ASRS:
#ifdef _LP64
if (p->p_model == DATAMODEL_LP64)
else
#endif
break;
#endif
case PR_CTL:
case PR_LWPCTL:
default:
break;
}
return (0);
}
static int
{
int vmode;
proc_t *p;
int error = 0;
return (EROFS);
switch (type) {
case PR_PROCDIR:
break;
case PR_OBJECT:
case PR_FD:
/*
* Disallow write access to the underlying objects.
* Disallow access to underlying non-regular-file fds.
* Disallow access to fds with other than existing open modes.
*/
secpolicy_proc_access(cr) != 0))
return (EACCES);
case PR_PSINFO: /* these files can be read by anyone */
case PR_LPSINFO:
case PR_LWPSINFO:
case PR_LWPDIR:
case PR_LWPIDDIR:
case PR_USAGE:
case PR_LUSAGE:
case PR_LWPUSAGE:
if (p == NULL)
return (ENOENT);
break;
default:
/*
* Except for the world-readable files above,
*/
return (error);
if (p != curproc)
} else {
/*
* Determine if the process's executable is readable.
* We have to drop p->p_lock before the secpolicy
* and VOP operation.
*/
if (secpolicy_proc_access(cr) != 0)
}
if (error)
return (error);
break;
}
/*
* Final access check on the underlying directory vnode.
*/
}
/*
* Visceral revulsion: For compatibility with old /proc,
* allow the /proc/<pid> directory to be opened for writing.
*/
return (error);
}
/*
* Array of lookup functions, indexed by /proc file type.
*/
*pr_lookup_ctdir();
pr_lookup_procdir, /* /proc */
pr_lookup_notdir, /* /proc/self */
pr_lookup_piddir, /* /proc/<pid> */
pr_lookup_notdir, /* /proc/<pid>/as */
pr_lookup_notdir, /* /proc/<pid>/ctl */
pr_lookup_notdir, /* /proc/<pid>/status */
pr_lookup_notdir, /* /proc/<pid>/lstatus */
pr_lookup_notdir, /* /proc/<pid>/psinfo */
pr_lookup_notdir, /* /proc/<pid>/lpsinfo */
pr_lookup_notdir, /* /proc/<pid>/map */
pr_lookup_notdir, /* /proc/<pid>/rmap */
pr_lookup_notdir, /* /proc/<pid>/xmap */
pr_lookup_notdir, /* /proc/<pid>/cred */
pr_lookup_notdir, /* /proc/<pid>/sigact */
pr_lookup_notdir, /* /proc/<pid>/auxv */
#if defined(__x86)
pr_lookup_notdir, /* /proc/<pid>/ldt */
#endif
pr_lookup_notdir, /* /proc/<pid>/usage */
pr_lookup_notdir, /* /proc/<pid>/lusage */
pr_lookup_notdir, /* /proc/<pid>/pagedata */
pr_lookup_notdir, /* /proc/<pid>/watch */
pr_lookup_notdir, /* /proc/<pid>/cwd */
pr_lookup_notdir, /* /proc/<pid>/root */
pr_lookup_fddir, /* /proc/<pid>/fd */
pr_lookup_notdir, /* /proc/<pid>/fd/nn */
pr_lookup_objectdir, /* /proc/<pid>/object */
pr_lookup_notdir, /* /proc/<pid>/object/xxx */
pr_lookup_lwpdir, /* /proc/<pid>/lwp */
pr_lookup_lwpiddir, /* /proc/<pid>/lwp/<lwpid> */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpstatus */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpsinfo */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpusage */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/xregs */
pr_lookup_tmpldir, /* /proc/<pid>/lwp/<lwpid>/templates */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/templates/<id> */
#if defined(__sparc)
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/gwindows */
pr_lookup_notdir, /* /proc/<pid>/lwp/<lwpid>/asrs */
#endif
pr_lookup_notdir, /* /proc/<pid>/priv */
pr_lookup_pathdir, /* /proc/<pid>/path */
pr_lookup_notdir, /* /proc/<pid>/path/xxx */
pr_lookup_ctdir, /* /proc/<pid>/contracts */
pr_lookup_notdir, /* /proc/<pid>/contracts/<ctid> */
pr_lookup_notdir, /* old process file */
pr_lookup_notdir, /* old lwp file */
pr_lookup_notdir, /* old pagedata file */
};
static int
{
int error;
return (0);
}
if (*comp == '\0' ||
return (0);
}
switch (type) {
case PR_CURDIR:
case PR_ROOTDIR:
/* restrict lookup permission to owner or root */
return (error);
/* FALLTHROUGH */
case PR_FD:
direntflags, realpnp));
default:
break;
}
return (error);
/* XXX - Do we need to pass ct, direntflags, or realpnp? */
}
/* ARGSUSED */
static int
{
int error;
} else {
else { /* /proc/<pid>/fd/<n> */
}
}
if (error) {
}
}
return (error);
}
/* ARGSUSED */
static vnode_t *
{
return (NULL);
}
/*
* Find or construct a process vnode for the given pid.
*/
static vnode_t *
{
proc_t *p;
int c;
} else {
pid = 0;
while ((c = *comp++) != '\0') {
if (c < '0' || c > '9')
return (NULL);
return (NULL);
}
}
return (NULL);
}
/* NOTE: we're holding pidlock across the policy call. */
return (NULL);
}
mutex_enter(&p->p_lock);
/*
* If a process vnode already exists and it is not invalid
* and it was created by the current process and it belongs
* to the same /proc mount point as our parent vnode, then
* just use it and discard the newly-allocated prnode.
*/
mutex_exit(&p->p_lock);
return (vp);
}
}
/*
* prgetnode() initialized most of the prnode.
* Finish the job.
*/
/* discard the new prcommon and use the existing prcommon */
pcp->prc_refcnt++;
} else {
/* initialize the new prcommon struct */
}
/*
* Link in the old, invalid directory vnode so we
* can later determine the last close of the file.
*/
/*
* Kludge for old /proc: initialize the PR_PIDFILE as well.
*/
mutex_exit(&p->p_lock);
return (dp);
}
static vnode_t *
{
proc_t *p;
int i;
enum prnodetype type;
for (i = 0; i < NPIDDIRFILES; i++) {
/* Skip "." and ".." */
break;
}
if (i >= NPIDDIRFILES)
return (NULL);
if (p == NULL) {
return (NULL);
}
switch (type) {
case PR_PSINFO:
case PR_USAGE:
break;
default:
return (NULL);
}
}
switch (type) {
case PR_CURDIR:
case PR_ROOTDIR:
return (NULL);
}
/*
* Fill in the prnode so future references will
* be able to find the underlying object's vnode.
*/
break;
default:
break;
}
return (vp);
}
/*
* prgetnode() initialized most of the prnode.
* Finish the job.
*/
/*
* Link new vnode into list of all /proc vnodes for the process.
*/
}
return (vp);
}
static vnode_t *
{
proc_t *p;
return (NULL);
}
return (NULL);
}
/*
* We drop p_lock before grabbing the address space lock
* in order to avoid a deadlock with the clock thread.
* The process will not disappear and its address space
* will not change because it is marked P_PR_LOCK.
*/
mutex_exit(&p->p_lock);
goto out;
}
goto out;
}
do {
/*
* Manufacture a filename for the "object" directory.
*/
char name[64];
continue;
goto out;
}
out:
}
mutex_enter(&p->p_lock);
else {
/*
* Fill in the prnode so future references will
* be able to find the underlying object's vnode.
* Don't link this prnode into the list of all
* prnodes for the process; this is a one-use node.
* Its use is entirely to catch and fail opens for writing.
*/
}
return (vp);
}
/*
* Find or construct an lwp vnode for the given lwpid.
*/
static vnode_t *
{
int want_agent;
proc_t *p;
kthread_t *t;
int tslot;
int c;
tid = 0;
want_agent = 1;
else {
want_agent = 0;
while ((c = *comp++) != '\0') {
if (c < '0' || c > '9')
return (NULL);
return (NULL);
}
}
if (p == NULL) {
return (NULL);
}
if (want_agent) {
else {
}
} else {
else {
}
}
return (NULL);
}
/*
* If an lwp vnode already exists and it is not invalid
* and it was created by the current process and it belongs
* to the same /proc mount point as our parent vnode, then
* just use it and discard the newly-allocated prnode.
*/
return (vp);
}
}
/*
* prgetnode() initialized most of the prnode.
* Finish the job.
*/
/* discard the new prcommon and use the existing prcommon */
pcp->prc_refcnt++;
} else {
/* initialize the new prcommon struct */
pcp->prc_thread = t;
}
/*
* Link in the old, invalid directory vnode so we
* can later determine the last close of the file.
*/
return (vp);
}
static vnode_t *
{
proc_t *p;
int i;
enum prnodetype type;
for (i = 0; i < NLWPIDDIRFILES; i++) {
/* Skip "." and ".." */
break;
}
if (i >= NLWPIDDIRFILES)
return (NULL);
if (p == NULL) {
return (NULL);
}
/*
* Only the lwpsinfo file is present for zombie lwps.
* Nothing is present if the lwp has been reaped.
*/
type != PR_LWPSINFO) {
return (NULL);
}
}
#if defined(__sparc)
/* the asrs file exists only for sparc v9 _LP64 processes */
return (NULL);
}
#endif
return (vp);
}
/*
* prgetnode() initialized most of the prnode.
* Finish the job.
*/
/*
* Link new vnode into list of all /proc vnodes for the process.
*/
}
return (vp);
}
/*
* Lookup one of the process's open files.
*/
static vnode_t *
{
proc_t *p;
int c;
fd = 0;
while ((c = *comp++) != '\0') {
int ofd;
if (c < '0' || c > '9')
return (NULL);
return (NULL);
}
return (NULL);
}
return (NULL);
}
mutex_exit(&p->p_lock);
}
}
mutex_enter(&p->p_lock);
else {
/*
* Fill in the prnode so future references will
* be able to find the underlying object's vnode.
* Don't link this prnode into the list of all
* prnodes for the process; this is a one-use node.
*/
}
return (vp);
}
static vnode_t *
{
proc_t *p;
int c;
char *tmp;
int idx;
/*
* First, check if this is a numeric entry, in which case we have a
* file descriptor.
*/
fd = 0;
while ((c = *tmp++) != '\0') {
int ofd;
if (c < '0' || c > '9') {
type = NAME_UNKNOWN;
break;
}
type = NAME_UNKNOWN;
break;
}
}
/*
* Next, see if it is one of the special values {root, cwd}.
*/
if (type == NAME_UNKNOWN) {
}
/*
* Grab the necessary data from the process
*/
return (NULL);
switch (type) {
case NAME_ROOT:
break;
case NAME_CWD:
break;
default:
return (NULL);
}
}
mutex_exit(&p->p_lock);
/*
* Determine if this is an object entry
*/
if (type == NAME_UNKNOWN) {
/*
* Start with the inode index immediately after the number of
* files.
*/
type = NAME_OBJECT;
} else {
type = NAME_OBJECT;
}
} else {
do {
/*
* Manufacture a filename for the
* "object" directory.
*/
== 0 &&
NULL) == 0) {
char name[64];
continue;
idx++;
&vattr);
break;
}
}
} else {
type = NAME_OBJECT;
}
}
}
switch (type) {
case NAME_FD:
}
}
break;
case NAME_ROOT:
idx = 2;
break;
case NAME_CWD:
idx = 3;
break;
case NAME_OBJECT:
case NAME_UNKNOWN:
/* Nothing to do */
break;
}
mutex_enter(&p->p_lock);
}
return (vp);
}
/*
* Look up one of the process's active templates.
*/
static vnode_t *
{
proc_t *p;
int i;
for (i = 0; i < ct_ntypes; i++)
break;
if (i == ct_ntypes)
return (NULL);
return (NULL);
}
return (NULL);
}
} else {
}
return (vp);
}
/*
* Look up one of the contracts owned by the process.
*/
static vnode_t *
{
proc_t *p;
contract_t *ct;
int c;
while ((c = *comp++) != '\0') {
if (c < '0' || c > '9')
return (NULL);
return (NULL);
}
/*
* Search all contracts; we'll filter below.
*/
return (NULL);
return (NULL);
}
/*
* We only allow lookups of contracts owned by this process, or,
* if we are zsched and this is a zone's procfs, contracts on
* stuff in the zone which are held by processes or contracts
* outside the zone. (see logic in contract_status_common)
*/
return (NULL);
}
return (vp);
}
/*
* Construct an lwp vnode for the old /proc interface.
* We stand on our head to make the /proc plumbing correct.
*/
vnode_t *
{
char comp[12];
proc_t *p;
/*
* Lookup the /proc/<pid>/lwp/<lwpid> directory vnode.
*/
return (NULL);
} else {
return (NULL);
}
return (NULL);
/*
* prgetnode() initialized most of the prnode.
* Finish the job.
*/
/*
* Link new vnode into list of all /proc vnodes for the process.
*/
if (p == NULL) {
} else {
}
return (vp);
}
#if defined(DEBUG)
#else
#define INCREMENT(x)
#define DECREMENT(x)
#endif /* DEBUG */
/*
* New /proc vnode required; allocate it and fill in most of the fields.
*/
prnode_t *
{
switch (type) {
case PR_PIDDIR:
case PR_LWPIDDIR:
/*
* We need a prcommon and a files array for each of these.
*/
/*
* Mode should be read-search by all, but we cannot so long
* as we must support compatibility mode with old /proc.
* Make /proc/<pid> be read by owner only, search by all.
* Make /proc/<pid>/lwp/<lwpid> read-search by all. Also,
* set VDIROPEN on /proc/<pid> so it can be opened for writing.
*/
/* kludge for old /proc interface */
} else {
}
break;
case PR_CURDIR:
case PR_ROOTDIR:
case PR_FDDIR:
case PR_OBJECTDIR:
case PR_PATHDIR:
case PR_CTDIR:
case PR_TMPLDIR:
break;
case PR_CT:
break;
case PR_PATH:
case PR_SELF:
break;
case PR_LWPDIR:
break;
case PR_AS:
case PR_TMPL:
break;
case PR_CTL:
case PR_LWPCTL:
break;
case PR_PIDFILE:
case PR_LWPIDFILE:
break;
case PR_PSINFO:
case PR_LPSINFO:
case PR_LWPSINFO:
case PR_USAGE:
case PR_LUSAGE:
case PR_LWPUSAGE:
break;
default:
break;
}
return (pnp);
}
/*
* Free the storage obtained from prgetnode().
*/
void
{
case PR_PIDDIR:
/* kludge for old /proc interface */
}
/* FALLTHROUGH */
case PR_LWPIDDIR:
/*
* We allocated a prcommon and a files array for each of these.
*/
break;
default:
break;
}
/*
* If there is an underlying vnode, be sure
* to release it after freeing the prnode.
*/
}
}
/*
* Free a prcommon structure, if the reference count reaches zero.
*/
static void
{
if (--pcp->prc_refcnt != 0)
else {
}
}
/*
* Array of readdir functions, indexed by /proc file type.
*/
static int (*pr_readdir_function[PR_NFILES])() = {
pr_readdir_procdir, /* /proc */
pr_readdir_notdir, /* /proc/self */
pr_readdir_piddir, /* /proc/<pid> */
pr_readdir_notdir, /* /proc/<pid>/as */
pr_readdir_notdir, /* /proc/<pid>/ctl */
pr_readdir_notdir, /* /proc/<pid>/status */
pr_readdir_notdir, /* /proc/<pid>/lstatus */
pr_readdir_notdir, /* /proc/<pid>/psinfo */
pr_readdir_notdir, /* /proc/<pid>/lpsinfo */
pr_readdir_notdir, /* /proc/<pid>/map */
pr_readdir_notdir, /* /proc/<pid>/rmap */
pr_readdir_notdir, /* /proc/<pid>/xmap */
pr_readdir_notdir, /* /proc/<pid>/cred */
pr_readdir_notdir, /* /proc/<pid>/sigact */
pr_readdir_notdir, /* /proc/<pid>/auxv */
#if defined(__x86)
pr_readdir_notdir, /* /proc/<pid>/ldt */
#endif
pr_readdir_notdir, /* /proc/<pid>/usage */
pr_readdir_notdir, /* /proc/<pid>/lusage */
pr_readdir_notdir, /* /proc/<pid>/pagedata */
pr_readdir_notdir, /* /proc/<pid>/watch */
pr_readdir_notdir, /* /proc/<pid>/cwd */
pr_readdir_notdir, /* /proc/<pid>/root */
pr_readdir_fddir, /* /proc/<pid>/fd */
pr_readdir_notdir, /* /proc/<pid>/fd/nn */
pr_readdir_objectdir, /* /proc/<pid>/object */
pr_readdir_notdir, /* /proc/<pid>/object/xxx */
pr_readdir_lwpdir, /* /proc/<pid>/lwp */
pr_readdir_lwpiddir, /* /proc/<pid>/lwp/<lwpid> */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpctl */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpstatus */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpsinfo */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/lwpusage */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/xregs */
pr_readdir_tmpldir, /* /proc/<pid>/lwp/<lwpid>/templates */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/templates/<id> */
#if defined(__sparc)
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/gwindows */
pr_readdir_notdir, /* /proc/<pid>/lwp/<lwpid>/asrs */
#endif
pr_readdir_notdir, /* /proc/<pid>/priv */
pr_readdir_pathdir, /* /proc/<pid>/path */
pr_readdir_notdir, /* /proc/<pid>/path/xxx */
pr_readdir_ctdir, /* /proc/<pid>/contracts */
pr_readdir_notdir, /* /proc/<pid>/contracts/<ctid> */
pr_readdir_notdir, /* old process file */
pr_readdir_notdir, /* old lwp file */
pr_readdir_notdir, /* old pagedata file */
};
/* ARGSUSED */
static int
{
/* XXX - Do we need to pass ct and flags? */
}
/* ARGSUSED */
static int
{
return (ENOTDIR);
}
/* ARGSUSED */
static int
{
offset_t n;
return (error);
/*
* Loop until user's request is satisfied or until all processes
* have been examined.
*/
int pslot;
proc_t *p;
/*
* Find next entry. Skip processes not visible where
* this /proc was mounted.
*/
while (n < v.v_proc &&
n++;
/*
* Stop when entire proc table has been examined.
*/
if (n >= v.v_proc) {
eof = 1;
break;
}
if (error)
break;
}
}
/* ARGSUSED */
static int
{
int error;
if (uiop->uio_offset < 0 ||
return (EINVAL);
return (ENOENT);
goto out;
/*
* Loop until user's request is satisfied, omitting some
* files along the way if the process is a zombie.
*/
if (zombie) {
case PR_PIDDIR:
case PR_PROCDIR:
case PR_PSINFO:
case PR_USAGE:
break;
default:
continue;
}
}
else
return (error);
}
out:
if (eofp)
return (0);
}
static void
{
int i, j;
return;
as->a_updatedir = 0;
return;
/*
* Allocate space for the new object directory.
* (This is usually about two times too many entries.)
*/
/* fill in the new directory with desired entries */
nentries = 0;
do {
for (i = 0; i < nentries; i++)
break;
if (i == nentries) {
}
}
return;
}
/*
* Null out all of the defunct entries in the old directory.
*/
nold = 0;
for (j = 0; j < nentries; j++) {
nnew--;
break;
}
}
if (j == nentries)
else
nold++;
}
}
/*
* Reallocate the old directory to have enough
* space for the old and new entries combined.
* Round up to the next multiple of 16.
*/
KM_SLEEP);
}
/*
* Move all new entries to the old directory and
* deallocate the space used by the new directory.
*/
if (nnew) {
for (i = 0, j = 0; i < nentries; i++) {
continue;
continue;
break;
}
}
}
}
/*
* Return the vnode from a slot in the process's object directory.
* The caller must have locked the process's address space.
* The only caller is below, in pr_readdir_objectdir().
*/
static vnode_t *
{
return (NULL);
}
/* ARGSUSED */
static int
{
offset_t n;
int pslot;
proc_t *p;
return (error);
/*
* We drop p_lock before grabbing the address space lock
* in order to avoid a deadlock with the clock thread.
* The process will not disappear and its address space
* will not change because it is marked P_PR_LOCK.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
objdirsize = 0;
}
/*
* Loop until user's request is satisfied or until
* all mapped objects have been examined. Cannot hold
* the address space lock for the following call as
* gfs_readdir_pred() utimately causes a call to uiomove().
*/
char str[64];
/*
* Set the correct size of the directory just
* in case the process has changed it's address
*/
if (as->a_updatedir)
}
/*
* Find next object.
*/
!= 0))) {
n++;
}
/*
* Stop when all objects have been reported.
*/
if (n >= objdirsize) {
eof = 1;
break;
}
else
str, 0);
if (error)
break;
}
mutex_enter(&p->p_lock);
}
/* ARGSUSED */
static int
{
proc_t *p;
int pslot;
int lwpdirsize;
if (p == NULL)
return (ENOENT);
lwpdirsize = p->p_lwpdir_sz;
/*
* Drop p->p_lock so we can safely do uiomove().
* The lwp directory will not change because
* we have the process locked with P_PR_LOCK.
*/
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
/*
* Loop until user's request is satisfied or until all lwps
* have been examined.
*/
/*
* Find next LWP.
*/
while (tslot < lwpdirsize &&
tslot++;
/*
* Stop when all lwps have been reported.
*/
if (tslot >= lwpdirsize) {
eof = 1;
break;
}
if (error)
break;
}
mutex_enter(&p->p_lock);
}
/* ARGSUSED */
static int
{
int error;
int pslot;
int tslot;
if (uiop->uio_offset < 0 ||
return (EINVAL);
return (ENOENT);
goto out;
/*
* Loop until user's request is satisfied, omitting some files
* along the way if the lwp is a zombie and also depending
* on the data model of the process.
*/
if (zombie) {
case PR_LWPIDDIR:
case PR_LWPDIR:
case PR_LWPSINFO:
break;
default:
continue;
}
}
#if defined(__sparc)
/* the asrs file exists only for sparc v9 _LP64 processes */
continue;
#endif
else
return (error);
}
out:
if (eofp)
return (0);
}
/* ARGSUSED */
static int
{
offset_t n;
proc_t *p;
int pslot;
int fddirsize;
return (error);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
fddirsize = 0;
else
/*
* Loop until user's request is satisfied or until
* all file descriptors have been examined.
*/
/*
* Find next fd.
*/
n++;
/*
* Stop when all fds have been reported.
*/
if (n >= fddirsize) {
eof = 1;
break;
}
if (error)
break;
}
mutex_enter(&p->p_lock);
}
/* ARGSUSED */
static int
{
int reclen;
int error = 0;
proc_t *p;
int pslot;
int fddirsize;
if (uiop->uio_offset < 0 ||
return (EINVAL);
return (error);
mutex_exit(&p->p_lock);
objdirsize = 0;
} else {
if (as->a_updatedir)
}
fddirsize = 0;
else
/*
* There are 4 special files in the path directory: ".", "..",
* "root", and "cwd". We handle those specially here.
*/
if (off == 0) { /* "." */
/*
* In this case, we have one of the file descriptors.
*/
continue;
}
/*
* We drop p_lock before grabbing the address space lock
* in order to avoid a deadlock with the clock thread.
* The process will not disappear and its address space
* will not change because it is marked P_PR_LOCK.
*/
}
if (as->a_updatedir) {
}
continue;
continue;
else
} else {
break;
}
/*
* Error if no entries have been returned yet.
*/
break;
}
/*
* Drop the address space lock to do the uiomove().
*/
if (error)
break;
}
mutex_enter(&p->p_lock);
return (error);
}
static int
{
proc_t *p;
offset_t n;
return (error);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
/*
* Check for an active template. Reading a directory's
* contents is already racy, so we don't bother taking
* any locks.
*/
while (n < ct_ntypes &&
n++;
/*
* Stop when all types have been reported.
*/
if (n >= ct_ntypes) {
eof = 1;
break;
}
/*
* The pmkino invocation below will need to be updated
* when we create our fifth contract type.
*/
ct_types[n]->ct_type_name, 0);
if (error)
break;
}
mutex_enter(&p->p_lock);
}
static int
{
proc_t *p;
int pslot;
offset_t n;
return (error);
mutex_exit(&p->p_lock);
mutex_enter(&p->p_lock);
return (error);
}
if (next == -1) {
eof = 1;
break;
}
if (error)
break;
}
mutex_enter(&p->p_lock);
}
/* ARGSUSED */
static int
{
return (0);
}
/*
* Utility: remove a /proc vnode from a linked list, threaded through pr_next.
*/
static void
{
break;
}
}
}
/* ARGSUSED */
static void
{
proc_t *p;
switch (type) {
case PR_OBJECT:
case PR_FD:
case PR_SELF:
case PR_PATH:
/* These are not linked into the usual lists */
return;
default:
break;
}
p = NULL;
mutex_enter(&p->p_lock);
if (p != NULL)
mutex_exit(&p->p_lock);
return;
}
switch (type) {
case PR_PIDFILE:
case PR_LWPIDFILE:
case PR_OPAGEDATA:
break;
default:
break;
}
}
/*
*/
}
if (p != NULL) {
/*
* Remove the vnodes from the lists of
* /proc vnodes for the process.
*/
int slot;
switch (type) {
case PR_PIDDIR:
break;
case PR_LWPIDDIR:
}
break;
default:
break;
}
mutex_exit(&p->p_lock);
}
}
}
}
/* ARGSUSED */
static int
{
return (0);
}
/*
* We use the p_execdir member of proc_t to expand the %d token in core file
* paths (the directory path for the executable that dumped core; see
* coreadm(1M) for details). We'd like gcore(1) to be able to expand %d in
* the same way as core dumping from the kernel, but there's no convenient
* and comprehensible way to export the path name for p_execdir. To solve
* this, we try to find the actual path to the executable that was used. In
* pr_lookup_pathdir(), we mark the a.out path name vnode with the PR_AOUT
* flag, and use that here to indicate that more work is needed beyond the
* call to vnodetopath().
*/
static int
{
proc_t *p;
int ret;
dirent64_t *dp;
char *dbuf;
p = curproc;
mutex_enter(&p->p_lock);
mutex_exit(&p->p_lock);
/*
* If PR_AOUT isn't set, then we looked up the path for the vnode;
* otherwise, we looked up the path for (what we believe to be) the
* containing directory.
*/
return (ret);
}
/*
* Fail if there's a problem locking the process. This will only
* occur if the process is changing so the information we would
* report would already be invalid.
*/
return (EIO);
}
mutex_exit(&p->p_lock);
/*
* If our initial lookup of the directory failed, fall back to
* the path name information for p_exec.
*/
if (ret != 0) {
mutex_enter(&p->p_lock);
return (ret);
}
/*
* We use u_comm as a guess for the last component of the full
* executable path name. If there isn't going to be enough space
* we fall back to using the p_exec so that we can have _an_
* answer even if it's not perfect.
*/
mutex_enter(&p->p_lock);
/*
* Do a forward lookup of our u_comm guess.
*/
return (0);
}
}
} else {
mutex_enter(&p->p_lock);
}
/*
* Try to find a matching vnode by iterating through the directory's
* entries. If that fails, fall back to the path information for
* p_exec.
*/
} else {
}
return (ret);
}
/* ARGSUSED */
static int
{
char *buf;
char idbuf[16];
contract_t *ct;
case PR_SELF:
break;
case PR_OBJECT:
case PR_FD:
case PR_CURDIR:
case PR_ROOTDIR:
ret = 0;
break;
case PR_PATH:
break;
case PR_CT:
break;
default:
break;
}
return (ret);
}
/*ARGSUSED2*/
static int
{
return (1);
return (0);
return (0);
return (1);
return (0);
}
static int
{
}
return (0);
}
/*
* Return the answer requested to poll().
* POLLIN, POLLRDNORM, and POLLOUT are recognized as in fs_poll().
* In addition, these have special meaning for /proc files:
* POLLPRI process or lwp stopped on an event of interest
* POLLERR /proc file descriptor is invalid
* POLLHUP process or lwp has terminated
*/
/*ARGSUSED5*/
static int
{
proc_t *p;
short revents;
int error;
int lockstate;
/*
* Support for old /proc interface.
*/
}
return (0);
}
switch (error) {
case ENOENT: /* process or lwp died */
error = 0;
break;
case EAGAIN: /* invalidated */
error = 0;
break;
}
return (error);
}
/*
* We have the process marked locked (P_PR_LOCK) and we are holding
* its p->p_lock. We want to unmark the process but retain
* exclusive control w.r.t. other /proc controlling processes
* before reacquiring the polling locks.
*
* prunmark() does this for us. It unmarks the process
* but retains p->p_lock so we still have exclusive control.
* We will drop p->p_lock at the end to relinquish control.
*
* We cannot call prunlock() at the end to relinquish control
* because prunlock(), like prunmark(), may drop and reacquire
* p->p_lock and that would lead to a lock order violation
* w.r.t. the polling locks we are about to reacquire.
*/
prunmark(p);
else {
short ev;
/*
* POLLWRNORM (same as POLLOUT) really should not be
* used to indicate that the process or lwp stopped.
* However, USL chose to use POLLWRNORM rather than
* POLLPRI to indicate this, so we just accept either
* requested event to indicate stopped. (grr...)
*/
kthread_t *t;
t = pcp->prc_thread;
thread_lock(t);
} else {
t = prchoose(p); /* returns locked t */
}
thread_unlock(t);
}
}
/*
* Arrange to wake up the polling lwp when
* or when the file descriptor becomes invalid.
*/
}
mutex_exit(&p->p_lock);
return (0);
}
/* in prioctl.c */
caller_context_t *);
/*
* /proc vnode operations vector
*/
const fs_operation_def_t pr_vnodeops_template[] = {
};