1224987Sjonathan/*- 2224987Sjonathan * Copyright (c) 2009 Robert N. M. Watson 3224987Sjonathan * All rights reserved. 4224987Sjonathan * 5224987Sjonathan * This software was developed at the University of Cambridge Computer 6224987Sjonathan * Laboratory with support from a grant from Google, Inc. 7224987Sjonathan * 8224987Sjonathan * Redistribution and use in source and binary forms, with or without 9224987Sjonathan * modification, are permitted provided that the following conditions 10224987Sjonathan * are met: 11224987Sjonathan * 1. Redistributions of source code must retain the above copyright 12224987Sjonathan * notice, this list of conditions and the following disclaimer. 13224987Sjonathan * 2. Redistributions in binary form must reproduce the above copyright 14224987Sjonathan * notice, this list of conditions and the following disclaimer in the 15224987Sjonathan * documentation and/or other materials provided with the distribution. 16224987Sjonathan * 17224987Sjonathan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18224987Sjonathan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19224987Sjonathan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20224987Sjonathan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21224987Sjonathan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22224987Sjonathan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23224987Sjonathan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24224987Sjonathan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25224987Sjonathan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26224987Sjonathan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27224987Sjonathan * SUCH DAMAGE. 28224987Sjonathan */ 29224987Sjonathan 30224987Sjonathan/*- 31224987Sjonathan * FreeBSD process descriptor facility. 32224987Sjonathan * 33224987Sjonathan * Some processes are represented by a file descriptor, which will be used in 34224987Sjonathan * preference to signaling and pids for the purposes of process management, 35224987Sjonathan * and is, in effect, a form of capability. When a process descriptor is 36224987Sjonathan * used with a process, it ceases to be visible to certain traditional UNIX 37224987Sjonathan * process facilities, such as waitpid(2). 38224987Sjonathan * 39224987Sjonathan * Some semantics: 40224987Sjonathan * 41224987Sjonathan * - At most one process descriptor will exist for any process, although 42224987Sjonathan * references to that descriptor may be held from many processes (or even 43224987Sjonathan * be in flight between processes over a local domain socket). 44224987Sjonathan * - Last close on the process descriptor will terminate the process using 45224987Sjonathan * SIGKILL and reparent it to init so that there's a process to reap it 46224987Sjonathan * when it's done exiting. 47224987Sjonathan * - If the process exits before the descriptor is closed, it will not 48224987Sjonathan * generate SIGCHLD on termination, or be picked up by waitpid(). 49224987Sjonathan * - The pdkill(2) system call may be used to deliver a signal to the process 50224987Sjonathan * using its process descriptor. 51224987Sjonathan * - The pdwait4(2) system call may be used to block (or not) on a process 52224987Sjonathan * descriptor to collect termination information. 53224987Sjonathan * 54224987Sjonathan * Open questions: 55224987Sjonathan * 56224987Sjonathan * - How to handle ptrace(2)? 57224987Sjonathan * - Will we want to add a pidtoprocdesc(2) system call to allow process 58224987Sjonathan * descriptors to be created for processes without pfork(2)? 59224987Sjonathan */ 60224987Sjonathan 61224987Sjonathan#include <sys/cdefs.h> 62224987Sjonathan__FBSDID("$FreeBSD$"); 63224987Sjonathan 64224987Sjonathan#include "opt_procdesc.h" 65224987Sjonathan 66224987Sjonathan#include <sys/param.h> 67280258Srwatson#include <sys/capsicum.h> 68224987Sjonathan#include <sys/fcntl.h> 69224987Sjonathan#include <sys/file.h> 70224987Sjonathan#include <sys/filedesc.h> 71224987Sjonathan#include <sys/kernel.h> 72224987Sjonathan#include <sys/lock.h> 73224987Sjonathan#include <sys/mutex.h> 74224987Sjonathan#include <sys/poll.h> 75224987Sjonathan#include <sys/proc.h> 76224987Sjonathan#include <sys/procdesc.h> 77224987Sjonathan#include <sys/resourcevar.h> 78224987Sjonathan#include <sys/stat.h> 79224987Sjonathan#include <sys/sysproto.h> 80224987Sjonathan#include <sys/sysctl.h> 81224987Sjonathan#include <sys/systm.h> 82224987Sjonathan#include <sys/ucred.h> 83224987Sjonathan 84224987Sjonathan#include <security/audit/audit.h> 85224987Sjonathan 86224987Sjonathan#include <vm/uma.h> 87224987Sjonathan 88224987Sjonathan#ifdef PROCDESC 89224987Sjonathan 90224987SjonathanFEATURE(process_descriptors, "Process Descriptors"); 91224987Sjonathan 92224987Sjonathanstatic uma_zone_t procdesc_zone; 93224987Sjonathan 94224987Sjonathanstatic fo_rdwr_t procdesc_read; 95224987Sjonathanstatic fo_rdwr_t procdesc_write; 96224987Sjonathanstatic fo_truncate_t procdesc_truncate; 97224987Sjonathanstatic fo_ioctl_t procdesc_ioctl; 98224987Sjonathanstatic fo_poll_t procdesc_poll; 99224987Sjonathanstatic fo_kqfilter_t procdesc_kqfilter; 100224987Sjonathanstatic fo_stat_t procdesc_stat; 101224987Sjonathanstatic fo_close_t procdesc_close; 102224987Sjonathanstatic fo_chmod_t procdesc_chmod; 103224987Sjonathanstatic fo_chown_t procdesc_chown; 104224987Sjonathan 105224987Sjonathanstatic struct fileops procdesc_ops = { 106224987Sjonathan .fo_read = procdesc_read, 107224987Sjonathan .fo_write = procdesc_write, 108224987Sjonathan .fo_truncate = procdesc_truncate, 109224987Sjonathan .fo_ioctl = procdesc_ioctl, 110224987Sjonathan .fo_poll = procdesc_poll, 111224987Sjonathan .fo_kqfilter = procdesc_kqfilter, 112224987Sjonathan .fo_stat = procdesc_stat, 113224987Sjonathan .fo_close = procdesc_close, 114224987Sjonathan .fo_chmod = procdesc_chmod, 115224987Sjonathan .fo_chown = procdesc_chown, 116254415Skib .fo_sendfile = invfo_sendfile, 117224987Sjonathan .fo_flags = DFLAG_PASSABLE, 118224987Sjonathan}; 119224987Sjonathan 120224987Sjonathan/* 121224987Sjonathan * Initialize with VFS so that process descriptors are available along with 122224987Sjonathan * other file descriptor types. As long as it runs before init(8) starts, 123224987Sjonathan * there shouldn't be a problem. 124224987Sjonathan */ 125224987Sjonathanstatic void 126224987Sjonathanprocdesc_init(void *dummy __unused) 127224987Sjonathan{ 128224987Sjonathan 129224987Sjonathan procdesc_zone = uma_zcreate("procdesc", sizeof(struct procdesc), 130224987Sjonathan NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); 131224987Sjonathan if (procdesc_zone == NULL) 132224987Sjonathan panic("procdesc_init: procdesc_zone not initialized"); 133224987Sjonathan} 134224987SjonathanSYSINIT(vfs, SI_SUB_VFS, SI_ORDER_ANY, procdesc_init, NULL); 135224987Sjonathan 136224987Sjonathan/* 137224987Sjonathan * Return a locked process given a process descriptor, or ESRCH if it has 138224987Sjonathan * died. 139224987Sjonathan */ 140224987Sjonathanint 141255219Spjdprocdesc_find(struct thread *td, int fd, cap_rights_t *rightsp, 142224987Sjonathan struct proc **p) 143224987Sjonathan{ 144224987Sjonathan struct procdesc *pd; 145224987Sjonathan struct file *fp; 146224987Sjonathan int error; 147224987Sjonathan 148255219Spjd error = fget(td, fd, rightsp, &fp); 149224987Sjonathan if (error) 150224987Sjonathan return (error); 151224987Sjonathan if (fp->f_type != DTYPE_PROCDESC) { 152224987Sjonathan error = EBADF; 153224987Sjonathan goto out; 154224987Sjonathan } 155224987Sjonathan pd = fp->f_data; 156224987Sjonathan sx_slock(&proctree_lock); 157224987Sjonathan if (pd->pd_proc != NULL) { 158224987Sjonathan *p = pd->pd_proc; 159224987Sjonathan PROC_LOCK(*p); 160224987Sjonathan } else 161224987Sjonathan error = ESRCH; 162224987Sjonathan sx_sunlock(&proctree_lock); 163224987Sjonathanout: 164224987Sjonathan fdrop(fp, td); 165224987Sjonathan return (error); 166224987Sjonathan} 167224987Sjonathan 168224987Sjonathan/* 169224987Sjonathan * Function to be used by procstat(1) sysctls when returning procdesc 170224987Sjonathan * information. 171224987Sjonathan */ 172224987Sjonathanpid_t 173224987Sjonathanprocdesc_pid(struct file *fp_procdesc) 174224987Sjonathan{ 175224987Sjonathan struct procdesc *pd; 176224987Sjonathan 177224987Sjonathan KASSERT(fp_procdesc->f_type == DTYPE_PROCDESC, 178224987Sjonathan ("procdesc_pid: !procdesc")); 179224987Sjonathan 180224987Sjonathan pd = fp_procdesc->f_data; 181224987Sjonathan return (pd->pd_pid); 182224987Sjonathan} 183224987Sjonathan 184224987Sjonathan/* 185224987Sjonathan * Retrieve the PID associated with a process descriptor. 186224987Sjonathan */ 187224987Sjonathanint 188255219Spjdkern_pdgetpid(struct thread *td, int fd, cap_rights_t *rightsp, pid_t *pidp) 189224987Sjonathan{ 190224987Sjonathan struct file *fp; 191224987Sjonathan int error; 192224987Sjonathan 193255219Spjd error = fget(td, fd, rightsp, &fp); 194224987Sjonathan if (error) 195224987Sjonathan return (error); 196224987Sjonathan if (fp->f_type != DTYPE_PROCDESC) { 197224987Sjonathan error = EBADF; 198224987Sjonathan goto out; 199224987Sjonathan } 200224987Sjonathan *pidp = procdesc_pid(fp); 201224987Sjonathanout: 202224987Sjonathan fdrop(fp, td); 203224987Sjonathan return (error); 204224987Sjonathan} 205224987Sjonathan 206224987Sjonathan/* 207224987Sjonathan * System call to return the pid of a process given its process descriptor. 208224987Sjonathan */ 209224987Sjonathanint 210225617Skmacysys_pdgetpid(struct thread *td, struct pdgetpid_args *uap) 211224987Sjonathan{ 212255219Spjd cap_rights_t rights; 213224987Sjonathan pid_t pid; 214224987Sjonathan int error; 215224987Sjonathan 216224987Sjonathan AUDIT_ARG_FD(uap->fd); 217255219Spjd error = kern_pdgetpid(td, uap->fd, 218255219Spjd cap_rights_init(&rights, CAP_PDGETPID), &pid); 219224987Sjonathan if (error == 0) 220224987Sjonathan error = copyout(&pid, uap->pidp, sizeof(pid)); 221224987Sjonathan return (error); 222224987Sjonathan} 223224987Sjonathan 224224987Sjonathan/* 225224987Sjonathan * When a new process is forked by pdfork(), a file descriptor is allocated 226224987Sjonathan * by the fork code first, then the process is forked, and then we get a 227224987Sjonathan * chance to set up the process descriptor. Failure is not permitted at this 228224987Sjonathan * point, so procdesc_new() must succeed. 229224987Sjonathan */ 230224987Sjonathanvoid 231224987Sjonathanprocdesc_new(struct proc *p, int flags) 232224987Sjonathan{ 233224987Sjonathan struct procdesc *pd; 234224987Sjonathan 235224987Sjonathan pd = uma_zalloc(procdesc_zone, M_WAITOK | M_ZERO); 236224987Sjonathan pd->pd_proc = p; 237224987Sjonathan pd->pd_pid = p->p_pid; 238224987Sjonathan p->p_procdesc = pd; 239224987Sjonathan pd->pd_flags = 0; 240224987Sjonathan if (flags & PD_DAEMON) 241224987Sjonathan pd->pd_flags |= PDF_DAEMON; 242224987Sjonathan PROCDESC_LOCK_INIT(pd); 243224987Sjonathan 244224987Sjonathan /* 245224987Sjonathan * Process descriptors start out with two references: one from their 246224987Sjonathan * struct file, and the other from their struct proc. 247224987Sjonathan */ 248224987Sjonathan refcount_init(&pd->pd_refcount, 2); 249224987Sjonathan} 250224987Sjonathan 251224987Sjonathan/* 252224987Sjonathan * Initialize a file with a process descriptor. 253224987Sjonathan */ 254224987Sjonathanvoid 255224987Sjonathanprocdesc_finit(struct procdesc *pdp, struct file *fp) 256224987Sjonathan{ 257224987Sjonathan 258224987Sjonathan finit(fp, FREAD | FWRITE, DTYPE_PROCDESC, pdp, &procdesc_ops); 259224987Sjonathan} 260224987Sjonathan 261224987Sjonathanstatic void 262224987Sjonathanprocdesc_free(struct procdesc *pd) 263224987Sjonathan{ 264224987Sjonathan 265224987Sjonathan /* 266224987Sjonathan * When the last reference is released, we assert that the descriptor 267224987Sjonathan * has been closed, but not that the process has exited, as we will 268224987Sjonathan * detach the descriptor before the process dies if the descript is 269224987Sjonathan * closed, as we can't wait synchronously. 270224987Sjonathan */ 271224987Sjonathan if (refcount_release(&pd->pd_refcount)) { 272224987Sjonathan KASSERT(pd->pd_proc == NULL, 273224987Sjonathan ("procdesc_free: pd_proc != NULL")); 274224987Sjonathan KASSERT((pd->pd_flags & PDF_CLOSED), 275224987Sjonathan ("procdesc_free: !PDF_CLOSED")); 276224987Sjonathan 277224987Sjonathan PROCDESC_LOCK_DESTROY(pd); 278224987Sjonathan uma_zfree(procdesc_zone, pd); 279224987Sjonathan } 280224987Sjonathan} 281224987Sjonathan 282224987Sjonathan/* 283224987Sjonathan * procdesc_exit() - notify a process descriptor that its process is exiting. 284224987Sjonathan * We use the proctree_lock to ensure that process exit either happens 285224987Sjonathan * strictly before or strictly after a concurrent call to procdesc_close(). 286224987Sjonathan */ 287224987Sjonathanint 288224987Sjonathanprocdesc_exit(struct proc *p) 289224987Sjonathan{ 290224987Sjonathan struct procdesc *pd; 291224987Sjonathan 292224987Sjonathan sx_assert(&proctree_lock, SA_XLOCKED); 293224987Sjonathan PROC_LOCK_ASSERT(p, MA_OWNED); 294224987Sjonathan KASSERT(p->p_procdesc != NULL, ("procdesc_exit: p_procdesc NULL")); 295224987Sjonathan 296224987Sjonathan pd = p->p_procdesc; 297224987Sjonathan 298224987Sjonathan PROCDESC_LOCK(pd); 299224987Sjonathan KASSERT((pd->pd_flags & PDF_CLOSED) == 0 || p->p_pptr == initproc, 300224987Sjonathan ("procdesc_exit: closed && parent not init")); 301224987Sjonathan 302224987Sjonathan pd->pd_flags |= PDF_EXITED; 303224987Sjonathan 304224987Sjonathan /* 305224987Sjonathan * If the process descriptor has been closed, then we have nothing 306224987Sjonathan * to do; return 1 so that init will get SIGCHLD and do the reaping. 307224987Sjonathan * Clean up the procdesc now rather than letting it happen during 308224987Sjonathan * that reap. 309224987Sjonathan */ 310224987Sjonathan if (pd->pd_flags & PDF_CLOSED) { 311224987Sjonathan PROCDESC_UNLOCK(pd); 312224987Sjonathan pd->pd_proc = NULL; 313224987Sjonathan p->p_procdesc = NULL; 314224987Sjonathan procdesc_free(pd); 315224987Sjonathan return (1); 316224987Sjonathan } 317224987Sjonathan if (pd->pd_flags & PDF_SELECTED) { 318224987Sjonathan pd->pd_flags &= ~PDF_SELECTED; 319224987Sjonathan selwakeup(&pd->pd_selinfo); 320224987Sjonathan } 321224987Sjonathan PROCDESC_UNLOCK(pd); 322224987Sjonathan return (0); 323224987Sjonathan} 324224987Sjonathan 325224987Sjonathan/* 326224987Sjonathan * When a process descriptor is reaped, perhaps as a result of close() or 327224987Sjonathan * pdwait4(), release the process's reference on the process descriptor. 328224987Sjonathan */ 329224987Sjonathanvoid 330224987Sjonathanprocdesc_reap(struct proc *p) 331224987Sjonathan{ 332224987Sjonathan struct procdesc *pd; 333224987Sjonathan 334224987Sjonathan sx_assert(&proctree_lock, SA_XLOCKED); 335224987Sjonathan KASSERT(p->p_procdesc != NULL, ("procdesc_reap: p_procdesc == NULL")); 336224987Sjonathan 337224987Sjonathan pd = p->p_procdesc; 338224987Sjonathan pd->pd_proc = NULL; 339239989Spjd p->p_procdesc = NULL; 340224987Sjonathan procdesc_free(pd); 341224987Sjonathan} 342224987Sjonathan 343224987Sjonathan/* 344224987Sjonathan * procdesc_close() - last close on a process descriptor. If the process is 345237277Spjd * still running, terminate with SIGKILL (unless PDF_DAEMON is set) and let 346224987Sjonathan * init(8) clean up the mess; if not, we have to clean up the zombie ourselves. 347224987Sjonathan */ 348224987Sjonathanstatic int 349224987Sjonathanprocdesc_close(struct file *fp, struct thread *td) 350224987Sjonathan{ 351224987Sjonathan struct procdesc *pd; 352224987Sjonathan struct proc *p; 353224987Sjonathan 354224987Sjonathan KASSERT(fp->f_type == DTYPE_PROCDESC, ("procdesc_close: !procdesc")); 355224987Sjonathan 356224987Sjonathan pd = fp->f_data; 357224987Sjonathan fp->f_ops = &badfileops; 358224987Sjonathan fp->f_data = NULL; 359224987Sjonathan 360224987Sjonathan sx_xlock(&proctree_lock); 361224987Sjonathan PROCDESC_LOCK(pd); 362224987Sjonathan pd->pd_flags |= PDF_CLOSED; 363224987Sjonathan PROCDESC_UNLOCK(pd); 364224987Sjonathan p = pd->pd_proc; 365239989Spjd if (p == NULL) { 366224987Sjonathan /* 367239989Spjd * This is the case where process' exit status was already 368239989Spjd * collected and procdesc_reap() was already called. 369239989Spjd */ 370239989Spjd sx_xunlock(&proctree_lock); 371239989Spjd } else if (p->p_state == PRS_ZOMBIE) { 372239989Spjd /* 373224987Sjonathan * If the process is already dead and just awaiting reaping, 374224987Sjonathan * do that now. This will release the process's reference to 375224987Sjonathan * the process descriptor when it calls back into 376224987Sjonathan * procdesc_reap(). 377224987Sjonathan */ 378239989Spjd PROC_LOCK(p); 379224987Sjonathan PROC_SLOCK(p); 380242958Skib proc_reap(curthread, p, NULL, 0); 381224987Sjonathan } else { 382224987Sjonathan /* 383224987Sjonathan * If the process is not yet dead, we need to kill it, but we 384224987Sjonathan * can't wait around synchronously for it to go away, as that 385224987Sjonathan * path leads to madness (and deadlocks). First, detach the 386224987Sjonathan * process from its descriptor so that its exit status will 387224987Sjonathan * be reported normally. 388224987Sjonathan */ 389239989Spjd PROC_LOCK(p); 390224987Sjonathan pd->pd_proc = NULL; 391224987Sjonathan p->p_procdesc = NULL; 392224987Sjonathan procdesc_free(pd); 393224987Sjonathan 394224987Sjonathan /* 395224987Sjonathan * Next, reparent it to init(8) so that there's someone to 396224987Sjonathan * pick up the pieces; finally, terminate with prejudice. 397224987Sjonathan */ 398224987Sjonathan p->p_sigparent = SIGCHLD; 399224987Sjonathan proc_reparent(p, initproc); 400237277Spjd if ((pd->pd_flags & PDF_DAEMON) == 0) 401225617Skmacy kern_psignal(p, SIGKILL); 402224987Sjonathan PROC_UNLOCK(p); 403224987Sjonathan sx_xunlock(&proctree_lock); 404224987Sjonathan } 405224987Sjonathan 406224987Sjonathan /* 407224987Sjonathan * Release the file descriptor's reference on the process descriptor. 408224987Sjonathan */ 409224987Sjonathan procdesc_free(pd); 410224987Sjonathan return (0); 411224987Sjonathan} 412224987Sjonathan 413224987Sjonathanstatic int 414224987Sjonathanprocdesc_read(struct file *fp, struct uio *uio, struct ucred *active_cred, 415224987Sjonathan int flags, struct thread *td) 416224987Sjonathan{ 417224987Sjonathan 418224987Sjonathan return (EOPNOTSUPP); 419224987Sjonathan} 420224987Sjonathan 421224987Sjonathanstatic int 422224987Sjonathanprocdesc_write(struct file *fp, struct uio *uio, struct ucred *active_cred, 423224987Sjonathan int flags, struct thread *td) 424224987Sjonathan{ 425224987Sjonathan 426224987Sjonathan return (EOPNOTSUPP); 427224987Sjonathan} 428224987Sjonathan 429224987Sjonathanstatic int 430224987Sjonathanprocdesc_truncate(struct file *fp, off_t length, struct ucred *active_cred, 431224987Sjonathan struct thread *td) 432224987Sjonathan{ 433224987Sjonathan 434224987Sjonathan return (EOPNOTSUPP); 435224987Sjonathan} 436224987Sjonathan 437224987Sjonathanstatic int 438224987Sjonathanprocdesc_ioctl(struct file *fp, u_long com, void *data, 439224987Sjonathan struct ucred *active_cred, struct thread *td) 440224987Sjonathan{ 441224987Sjonathan 442224987Sjonathan return (EOPNOTSUPP); 443224987Sjonathan} 444224987Sjonathan 445224987Sjonathanstatic int 446224987Sjonathanprocdesc_poll(struct file *fp, int events, struct ucred *active_cred, 447224987Sjonathan struct thread *td) 448224987Sjonathan{ 449224987Sjonathan struct procdesc *pd; 450224987Sjonathan int revents; 451224987Sjonathan 452224987Sjonathan revents = 0; 453224987Sjonathan pd = fp->f_data; 454224987Sjonathan PROCDESC_LOCK(pd); 455224987Sjonathan if (pd->pd_flags & PDF_EXITED) 456224987Sjonathan revents |= POLLHUP; 457224987Sjonathan if (revents == 0) { 458224987Sjonathan selrecord(td, &pd->pd_selinfo); 459224987Sjonathan pd->pd_flags |= PDF_SELECTED; 460224987Sjonathan } 461224987Sjonathan PROCDESC_UNLOCK(pd); 462224987Sjonathan return (revents); 463224987Sjonathan} 464224987Sjonathan 465224987Sjonathanstatic int 466224987Sjonathanprocdesc_kqfilter(struct file *fp, struct knote *kn) 467224987Sjonathan{ 468224987Sjonathan 469224987Sjonathan return (EOPNOTSUPP); 470224987Sjonathan} 471224987Sjonathan 472224987Sjonathanstatic int 473224987Sjonathanprocdesc_stat(struct file *fp, struct stat *sb, struct ucred *active_cred, 474224987Sjonathan struct thread *td) 475224987Sjonathan{ 476224987Sjonathan struct procdesc *pd; 477224987Sjonathan struct timeval pstart; 478224987Sjonathan 479224987Sjonathan /* 480224987Sjonathan * XXXRW: Perhaps we should cache some more information from the 481224987Sjonathan * process so that we can return it reliably here even after it has 482224987Sjonathan * died. For example, caching its credential data. 483224987Sjonathan */ 484224987Sjonathan bzero(sb, sizeof(*sb)); 485224987Sjonathan pd = fp->f_data; 486224987Sjonathan sx_slock(&proctree_lock); 487224987Sjonathan if (pd->pd_proc != NULL) { 488224987Sjonathan PROC_LOCK(pd->pd_proc); 489224987Sjonathan 490224987Sjonathan /* Set birth and [acm] times to process start time. */ 491224987Sjonathan pstart = pd->pd_proc->p_stats->p_start; 492224987Sjonathan timevaladd(&pstart, &boottime); 493224987Sjonathan TIMEVAL_TO_TIMESPEC(&pstart, &sb->st_birthtim); 494224987Sjonathan sb->st_atim = sb->st_birthtim; 495224987Sjonathan sb->st_ctim = sb->st_birthtim; 496224987Sjonathan sb->st_mtim = sb->st_birthtim; 497224987Sjonathan if (pd->pd_proc->p_state != PRS_ZOMBIE) 498224987Sjonathan sb->st_mode = S_IFREG | S_IRWXU; 499224987Sjonathan else 500224987Sjonathan sb->st_mode = S_IFREG; 501224987Sjonathan sb->st_uid = pd->pd_proc->p_ucred->cr_ruid; 502224987Sjonathan sb->st_gid = pd->pd_proc->p_ucred->cr_rgid; 503224987Sjonathan PROC_UNLOCK(pd->pd_proc); 504224987Sjonathan } else 505224987Sjonathan sb->st_mode = S_IFREG; 506224987Sjonathan sx_sunlock(&proctree_lock); 507224987Sjonathan return (0); 508224987Sjonathan} 509224987Sjonathan 510224987Sjonathanstatic int 511224987Sjonathanprocdesc_chmod(struct file *fp, mode_t mode, struct ucred *active_cred, 512224987Sjonathan struct thread *td) 513224987Sjonathan{ 514224987Sjonathan 515224987Sjonathan return (EOPNOTSUPP); 516224987Sjonathan} 517224987Sjonathan 518224987Sjonathanstatic int 519224987Sjonathanprocdesc_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred, 520224987Sjonathan struct thread *td) 521224987Sjonathan{ 522224987Sjonathan 523224987Sjonathan return (EOPNOTSUPP); 524224987Sjonathan} 525224987Sjonathan 526224987Sjonathan#else /* !PROCDESC */ 527224987Sjonathan 528224987Sjonathanint 529225617Skmacysys_pdgetpid(struct thread *td, struct pdgetpid_args *uap) 530224987Sjonathan{ 531224987Sjonathan 532224987Sjonathan return (ENOSYS); 533224987Sjonathan} 534224987Sjonathan 535224987Sjonathan#endif /* PROCDESC */ 536