diff --git a/lib/libc/gen/exterr_cat_filenames.h b/lib/libc/gen/exterr_cat_filenames.h --- a/lib/libc/gen/exterr_cat_filenames.h +++ b/lib/libc/gen/exterr_cat_filenames.h @@ -8,6 +8,8 @@ [EXTERR_CAT_GEOM] = "geom/geom_subr.c", [EXTERR_CAT_GEOMVFS] = "geom/geom_vfs.c", [EXTERR_CAT_FILEDESC] = "kern/kern_descrip.c", + [EXTERR_CAT_PROCEXIT] = "kern/kern_exit.c", + [EXTERR_CAT_FORK] = "kern/kern_fork.c", [EXTERR_CAT_GENIO] = "kern/sys_generic.c", [EXTERR_CAT_VFSBIO] = "kern/vfs_bio.c", [EXTERR_CAT_INOTIFY] = "kern/vfs_inotify.c", diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys --- a/lib/libsys/Makefile.sys +++ b/lib/libsys/Makefile.sys @@ -495,8 +495,10 @@ MLINKS+=open.2 openat.2 MLINKS+=pathconf.2 fpathconf.2 MLINKS+=pathconf.2 lpathconf.2 -MLINKS+=pdfork.2 pdgetpid.2\ - pdfork.2 pdkill.2 +MLINKS+=pdfork.2 pdgetpid.2 \ + pdfork.2 pdkill.2 \ + pdfork.2 pdrfork.2 \ + pdfork.2 pdwait.2 MLINKS+=pipe.2 pipe2.2 MLINKS+=poll.2 ppoll.2 MLINKS+=rctl_add_rule.2 rctl_get_limits.2 \ diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map --- a/lib/libsys/Symbol.sys.map +++ b/lib/libsys/Symbol.sys.map @@ -389,6 +389,11 @@ setgroups; }; +FBSD_1.9 { + pdrfork; + pdwait; +}; + FBSDprivate_1.0 { /* Add entries in sort(1) order */ __set_error_selector; diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h --- a/lib/libsys/_libsys.h +++ b/lib/libsys/_libsys.h @@ -472,6 +472,8 @@ typedef int (__sys_jail_attach_jd_t)(int); typedef int (__sys_jail_remove_jd_t)(int); typedef int (__sys_kexec_load_t)(uint64_t, u_long, struct kexec_segment *, u_long); +typedef int (__sys_pdrfork_t)(int *, int, int); +typedef int (__sys_pdwait_t)(int, int *, int, struct __wrusage *, struct __siginfo *); _Noreturn void __sys__exit(int rval); int __sys_fork(void); @@ -879,6 +881,8 @@ int __sys_jail_attach_jd(int fd); int __sys_jail_remove_jd(int fd); int __sys_kexec_load(uint64_t entry, u_long nseg, struct kexec_segment * segments, u_long flags); +int __sys_pdrfork(int * fdp, int pdflags, int rfflags); +int __sys_pdwait(int fd, int * status, int options, struct __wrusage * wrusage, struct __siginfo * info); __END_DECLS #endif /* __LIBSYS_H_ */ diff --git a/lib/libsys/pdfork.2 b/lib/libsys/pdfork.2 --- a/lib/libsys/pdfork.2 +++ b/lib/libsys/pdfork.2 @@ -30,24 +30,36 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 14, 2018 +.Dd January 20, 2026 .Dt PDFORK 2 .Os .Sh NAME .Nm pdfork , +.Nm pdrfork , .Nm pdgetpid , -.Nm pdkill +.Nm pdkill , +.Nm pdwait .Nd System calls to manage process descriptors .Sh LIBRARY .Lb libc .Sh SYNOPSIS .In sys/procdesc.h .Ft pid_t -.Fn pdfork "int *fdp" "int flags" +.Fn pdfork "int *fdp" "int pdflags" +.Ft pid_t +.Fn pdrfork "int *fdp" "int pdflags" "int rfflags" .Ft int .Fn pdgetpid "int fd" "pid_t *pidp" .Ft int .Fn pdkill "int fd" "int signum" +.Ft int +.Fo pdwait +.Fa "int fd" +.Fa "int *status" +.Fa "int options" +.Fa "struct __wrusage *wrusage" +.Fa "struct __siginfo *info" +.Fc .Sh DESCRIPTION Process descriptors are special file descriptors that represent processes, and are created using @@ -63,8 +75,9 @@ .Dv SIGCHLD on termination. .Fn pdfork -can accept the flags: -.Bl -tag -width ".Dv PD_DAEMON" +can accept the +.Fa pdflags: +.Bl -tag -width PD_CLOEXEC .It Dv PD_DAEMON Instead of the default terminate-on-close behaviour, allow the process to live until it is explicitly killed with @@ -80,6 +93,33 @@ Set close-on-exec on process descriptor. .El .Pp +The +.Fn pdrfork +system call is a variant of +.Fn pdfork +that also takes the +.Fa rfflags +argument to control sharing of process resources between the caller +and the new process. +Like +.Fn pdfork , +the function writes the process descriptor referencing the created +process into the location pointed to by the +.Fa fdp +argument. +See +.Xr rfork 2 +for a description of the possible +.Fa rfflag +flags. +The +.Fn pdrfork +requires that the +.Va RFPROC +or +.Va RFSPAWN +flag is specified. +.Pp .Fn pdgetpid queries the process ID (PID) in the process descriptor .Fa fd . @@ -91,6 +131,16 @@ .Fa fd , rather than a PID. .Pp +The +.Fn pdwait +function allows the calling thread to wait and retrieve the status information +on the process referenced by the +.Fa fd +process descriptor. +See the description of the +.Xr wait6 +system call for the behavior specification. +.Pp The following system calls also have effects specific to process descriptors: .Pp .Xr fstat 2 @@ -126,15 +176,24 @@ the last reference to the process descriptor, the process will be terminated with the signal .Dv SIGKILL . +The PID of the referenced process is not reused until the process +descriptor is closed, +whether or not the zombie process is reaped by +Fn pdwait , +Xr wait6 , +or similar system calls. .Sh RETURN VALUES .Fn pdfork -returns a PID, 0 or -1, as +and +.Fn pdrfork +return a PID, 0 or -1, as .Xr fork 2 does. .Pp -.Fn pdgetpid +.Fn pdgetpid , +.Fn pdkill , and -.Fn pdkill +.Fn pdwait return 0 on success and -1 on failure. .Sh ERRORS These functions may return the same error numbers as their PID-based equivalents @@ -172,6 +231,12 @@ .Fn pdkill system calls first appeared in .Fx 9.0 . +The +.Fn pdrfork +and +.Fn pdwait +system calls first appeared in +.Fx 16.0 . .Pp Support for process descriptors mode was developed as part of the .Tn TrustedBSD @@ -184,3 +249,11 @@ .An Jonathan Anderson Aq Mt jonathan@FreeBSD.org at the University of Cambridge Computer Laboratory with support from a grant from Google, Inc. +The +.Fn pdrfork +and +.Fn pdwait +functions were developed by +.An Konstantin Belousov Aq Mt kib@FreeBSD.org +with input from +.An Alan Somers Aq Mt asomers@FreeBSD.org . diff --git a/lib/libsys/rfork.2 b/lib/libsys/rfork.2 --- a/lib/libsys/rfork.2 +++ b/lib/libsys/rfork.2 @@ -194,6 +194,7 @@ .Xr fork 2 , .Xr intro 2 , .Xr minherit 2 , +.Xr pdrfork 2 , .Xr vfork 2 , .Xr pthread_create 3 , .Xr rfork_thread 3 diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map --- a/lib/libsys/syscalls.map +++ b/lib/libsys/syscalls.map @@ -819,4 +819,8 @@ __sys_jail_remove_jd; _kexec_load; __sys_kexec_load; + _pdrfork; + __sys_pdrfork; + _pdwait; + __sys_pdwait; }; diff --git a/lib/libsys/wait.2 b/lib/libsys/wait.2 --- a/lib/libsys/wait.2 +++ b/lib/libsys/wait.2 @@ -656,6 +656,7 @@ .El .Sh SEE ALSO .Xr _exit 2 , +.Xr pdwait 2 , .Xr procctl 2 , .Xr ptrace 2 , .Xr sigaction 2 , diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h --- a/sys/bsm/audit_kevents.h +++ b/sys/bsm/audit_kevents.h @@ -664,6 +664,7 @@ #define AUE_TIMERFD 43270 /* FreeBSD/Linux. */ #define AUE_SETCRED 43271 /* FreeBSD-specific. */ #define AUE_INOTIFY 43272 /* FreeBSD/Linux. */ +#define AUE_PDRFORK 43273 /* FreeBSD-specific. */ /* * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -280,6 +280,37 @@ return (error); } +int +freebsd32_pdwait(struct thread *td, struct freebsd32_pdwait_args *uap) +{ + struct __wrusage32 wru32; + struct __wrusage wru, *wrup; + struct __siginfo32 si32; + struct __siginfo si, *sip; + int error, status; + + wrup = uap->wrusage != NULL ? &wru : NULL; + if (uap->info != NULL) { + sip = &si; + bzero(sip, sizeof(*sip)); + } else { + sip = NULL; + } + error = kern_pdwait(td, uap->fd, &status, uap->options, wrup, sip); + if (uap->status != NULL && error == 0) + error = copyout(&status, uap->status, sizeof(status)); + if (uap->wrusage != NULL && error == 0) { + freebsd32_rusage_out(&wru.wru_self, &wru32.wru_self); + freebsd32_rusage_out(&wru.wru_children, &wru32.wru_children); + error = copyout(&wru32, uap->wrusage, sizeof(wru32)); + } + if (uap->info != NULL && error == 0) { + siginfo_to_siginfo32 (&si, &si32); + error = copyout(&si32, uap->info, sizeof(si32)); + } + return (error); +} + #ifdef COMPAT_FREEBSD4 static void copy_statfs(struct statfs *in, struct ostatfs32 *out) diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -699,6 +699,13 @@ char wcred_l_[PADL_(const struct setcred32 *)]; const struct setcred32 * wcred; char wcred_r_[PADR_(const struct setcred32 *)]; char size_l_[PADL_(size_t)]; size_t size; char size_r_[PADR_(size_t)]; }; +struct freebsd32_pdwait_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)]; + char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)]; + char wrusage_l_[PADL_(struct __wrusage32 *)]; struct __wrusage32 * wrusage; char wrusage_r_[PADR_(struct __wrusage32 *)]; + char info_l_[PADL_(struct __siginfo32 *)]; struct __siginfo32 * info; char info_r_[PADR_(struct __siginfo32 *)]; +}; int freebsd32_wait4(struct thread *, struct freebsd32_wait4_args *); int freebsd32_ptrace(struct thread *, struct freebsd32_ptrace_args *); int freebsd32_recvmsg(struct thread *, struct freebsd32_recvmsg_args *); @@ -817,6 +824,7 @@ int freebsd32_timerfd_gettime(struct thread *, struct freebsd32_timerfd_gettime_args *); int freebsd32_timerfd_settime(struct thread *, struct freebsd32_timerfd_settime_args *); int freebsd32_setcred(struct thread *, struct freebsd32_setcred_args *); +int freebsd32_pdwait(struct thread *, struct freebsd32_pdwait_args *); #ifdef COMPAT_43 @@ -1319,6 +1327,7 @@ #define FREEBSD32_SYS_AUE_freebsd32_timerfd_gettime AUE_TIMERFD #define FREEBSD32_SYS_AUE_freebsd32_timerfd_settime AUE_TIMERFD #define FREEBSD32_SYS_AUE_freebsd32_setcred AUE_SETCRED +#define FREEBSD32_SYS_AUE_freebsd32_pdwait AUE_PDWAIT #undef PAD_ #undef PADL_ diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -517,4 +517,6 @@ #define FREEBSD32_SYS_setgroups 596 #define FREEBSD32_SYS_jail_attach_jd 597 #define FREEBSD32_SYS_jail_remove_jd 598 -#define FREEBSD32_SYS_MAXSYSCALL 600 +#define FREEBSD32_SYS_pdrfork 600 +#define FREEBSD32_SYS_freebsd32_pdwait 601 +#define FREEBSD32_SYS_MAXSYSCALL 602 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -605,4 +605,6 @@ "jail_attach_jd", /* 597 = jail_attach_jd */ "jail_remove_jd", /* 598 = jail_remove_jd */ "#599", /* 599 = kexec_load */ + "pdrfork", /* 600 = pdrfork */ + "freebsd32_pdwait", /* 601 = freebsd32_pdwait */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -667,4 +667,6 @@ { .sy_narg = AS(jail_attach_jd_args), .sy_call = (sy_call_t *)sys_jail_attach_jd, .sy_auevent = AUE_JAIL_ATTACH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 597 = jail_attach_jd */ { .sy_narg = AS(jail_remove_jd_args), .sy_call = (sy_call_t *)sys_jail_remove_jd, .sy_auevent = AUE_JAIL_REMOVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 598 = jail_remove_jd */ { .sy_narg = 0, .sy_call = (sy_call_t *)nosys, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_ABSENT }, /* 599 = freebsd32_kexec_load */ + { .sy_narg = AS(pdrfork_args), .sy_call = (sy_call_t *)sys_pdrfork, .sy_auevent = AUE_PDRFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 600 = pdrfork */ + { .sy_narg = AS(freebsd32_pdwait_args), .sy_call = (sy_call_t *)freebsd32_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = freebsd32_pdwait */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3427,6 +3427,26 @@ *n_args = 1; break; } + /* pdrfork */ + case 600: { + struct pdrfork_args *p = params; + uarg[a++] = (intptr_t)p->fdp; /* int * */ + iarg[a++] = p->pdflags; /* int */ + iarg[a++] = p->rfflags; /* int */ + *n_args = 3; + break; + } + /* freebsd32_pdwait */ + case 601: { + struct freebsd32_pdwait_args *p = params; + iarg[a++] = p->fd; /* int */ + uarg[a++] = (intptr_t)p->status; /* int * */ + iarg[a++] = p->options; /* int */ + uarg[a++] = (intptr_t)p->wrusage; /* struct __wrusage32 * */ + uarg[a++] = (intptr_t)p->info; /* struct __siginfo32 * */ + *n_args = 5; + break; + } default: *n_args = 0; break; @@ -9256,6 +9276,44 @@ break; }; break; + /* pdrfork */ + case 600: + switch (ndx) { + case 0: + p = "userland int *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* freebsd32_pdwait */ + case 601: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland int *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland struct __wrusage32 *"; + break; + case 4: + p = "userland struct __siginfo32 *"; + break; + default: + break; + }; + break; default: break; }; @@ -11174,6 +11232,16 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* pdrfork */ + case 600: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_pdwait */ + case 601: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -666,4 +666,6 @@ { .sy_narg = AS(jail_attach_jd_args), .sy_call = (sy_call_t *)sys_jail_attach_jd, .sy_auevent = AUE_JAIL_ATTACH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 597 = jail_attach_jd */ { .sy_narg = AS(jail_remove_jd_args), .sy_call = (sy_call_t *)sys_jail_remove_jd, .sy_auevent = AUE_JAIL_REMOVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 598 = jail_remove_jd */ { .sy_narg = AS(kexec_load_args), .sy_call = (sy_call_t *)sys_kexec_load, .sy_auevent = AUE_NULL, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 599 = kexec_load */ + { .sy_narg = AS(pdrfork_args), .sy_call = (sy_call_t *)sys_pdrfork, .sy_auevent = AUE_PDRFORK, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 600 = pdrfork */ + { .sy_narg = AS(pdwait_args), .sy_call = (sy_call_t *)sys_pdwait, .sy_auevent = AUE_PDWAIT, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 601 = pdwait */ }; diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -34,45 +34,45 @@ * SUCH DAMAGE. */ -#include #include "opt_ddb.h" #include "opt_ktrace.h" -#include +#define EXTERR_CATEGORY EXTERR_CAT_PROCEXIT #include -#include +#include /* for acct_process() function prototype */ #include #include +#include +#include +#include #include #include -#include #include +#include #include #include #include -#include -#include -#include -#include -#include +#include #include #include #include -#include #include +#include +#include +#include +#include #include #include #include -#include -#include -#include /* for acct_process() function prototype */ -#include -#include -#include -#include #include +#include +#include #include +#include #include +#include +#include +#include #ifdef KTRACE #include #endif @@ -906,6 +906,33 @@ return (error); } +int +sys_pdwait(struct thread *td, struct pdwait_args *uap) +{ + struct __wrusage wru, *wrup; + siginfo_t si, *sip; + int error, status; + + wrup = uap->wrusage != NULL ? &wru : NULL; + + if (uap->info != NULL) { + sip = &si; + bzero(sip, sizeof(*sip)); + } else { + sip = NULL; + } + + error = kern_pdwait(td, uap->fd, &status, uap->options, wrup, sip); + + if (uap->status != NULL && error == 0) + error = copyout(&status, uap->status, sizeof(status)); + if (uap->wrusage != NULL && error == 0) + error = copyout(&wru, uap->wrusage, sizeof(wru)); + if (uap->info != NULL && error == 0) + error = copyout(&si, uap->info, sizeof(si)); + return (error); +} + /* * Reap the remains of a zombie process and optionally return status and * rusage. Asserts and will release both the proctree_lock and the process @@ -924,9 +951,9 @@ q = td->td_proc; - if (status) + if (status != NULL) *status = KW_EXITCODE(p->p_xexit, p->p_xsig); - if (options & WNOWAIT) { + if ((options & WNOWAIT) != 0) { /* * Only poll, returning the status. Caller does not wish to * release the proc struct just yet. @@ -979,10 +1006,10 @@ leavepgrp(p); if (p->p_procdesc != NULL) procdesc_reap(p); + else + proc_id_clear(PROC_ID_PID, p->p_pid); sx_xunlock(&proctree_lock); - proc_id_clear(PROC_ID_PID, p->p_pid); - PROC_LOCK(p); knlist_detach(p->p_klist); p->p_klist = NULL; @@ -1042,13 +1069,75 @@ atomic_add_int(&nprocs, -1); } +static void +wait_fill_siginfo(struct proc *p, siginfo_t *siginfo) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + + if (siginfo == NULL) + return; + + bzero(siginfo, sizeof(*siginfo)); + siginfo->si_errno = 0; + + /* + * SUSv4 requires that the si_signo value is always + * SIGCHLD. Obey it despite the rfork(2) interface allows to + * request other signal for child exit notification. + */ + siginfo->si_signo = SIGCHLD; + + /* + * This is still a rough estimate. We will fix the cases + * TRAPPED, STOPPED, and CONTINUED later. + */ + if (WCOREDUMP(p->p_xsig)) { + siginfo->si_code = CLD_DUMPED; + siginfo->si_status = WTERMSIG(p->p_xsig); + } else if (WIFSIGNALED(p->p_xsig)) { + siginfo->si_code = CLD_KILLED; + siginfo->si_status = WTERMSIG(p->p_xsig); + } else { + siginfo->si_code = CLD_EXITED; + siginfo->si_status = p->p_xexit; + } + + siginfo->si_pid = p->p_pid; + siginfo->si_uid = p->p_ucred->cr_uid; + + /* + * The si_addr field would be useful additional detail, but + * apparently the PC value may be lost when we reach this + * point. bzero() above sets siginfo->si_addr to NULL. + */ +} + +static void +wait_fill_wrusage(struct proc *p, struct __wrusage *wrusage) +{ + struct rusage *rup; + + PROC_LOCK_ASSERT(p, MA_OWNED); + + if (wrusage == NULL) + return; + + rup = &wrusage->wru_self; + *rup = p->p_ru; + PROC_STATLOCK(p); + calcru(p, &rup->ru_utime, &rup->ru_stime); + PROC_STATUNLOCK(p); + + rup = &wrusage->wru_children; + *rup = p->p_stats->p_cru; + calccru(p, &rup->ru_utime, &rup->ru_stime); +} + static int proc_to_reap(struct thread *td, struct proc *p, idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo, int check_only) { - struct rusage *rup; - sx_assert(&proctree_lock, SA_XLOCKED); PROC_LOCK(p); @@ -1114,7 +1203,7 @@ return (0); } - if (((options & WEXITED) == 0) && (p->p_state == PRS_ZOMBIE)) { + if ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) { PROC_UNLOCK(p); return (0); } @@ -1133,60 +1222,14 @@ return (0); } - if (siginfo != NULL) { - bzero(siginfo, sizeof(*siginfo)); - siginfo->si_errno = 0; - - /* - * SUSv4 requires that the si_signo value is always - * SIGCHLD. Obey it despite the rfork(2) interface - * allows to request other signal for child exit - * notification. - */ - siginfo->si_signo = SIGCHLD; - - /* - * This is still a rough estimate. We will fix the - * cases TRAPPED, STOPPED, and CONTINUED later. - */ - if (WCOREDUMP(p->p_xsig)) { - siginfo->si_code = CLD_DUMPED; - siginfo->si_status = WTERMSIG(p->p_xsig); - } else if (WIFSIGNALED(p->p_xsig)) { - siginfo->si_code = CLD_KILLED; - siginfo->si_status = WTERMSIG(p->p_xsig); - } else { - siginfo->si_code = CLD_EXITED; - siginfo->si_status = p->p_xexit; - } - - siginfo->si_pid = p->p_pid; - siginfo->si_uid = p->p_ucred->cr_uid; - - /* - * The si_addr field would be useful additional - * detail, but apparently the PC value may be lost - * when we reach this point. bzero() above sets - * siginfo->si_addr to NULL. - */ - } + wait_fill_siginfo(p, siginfo); /* * There should be no reason to limit resources usage info to * exited processes only. A snapshot about any resources used * by a stopped process may be exactly what is needed. */ - if (wrusage != NULL) { - rup = &wrusage->wru_self; - *rup = p->p_ru; - PROC_STATLOCK(p); - calcru(p, &rup->ru_utime, &rup->ru_stime); - PROC_STATUNLOCK(p); - - rup = &wrusage->wru_children; - *rup = p->p_stats->p_cru; - calccru(p, &rup->ru_utime, &rup->ru_stime); - } + wait_fill_wrusage(p, wrusage); if (p->p_state == PRS_ZOMBIE && !check_only) { proc_reap(td, p, status, options); @@ -1267,10 +1310,85 @@ } if (status != NULL) *status = cont ? SIGCONT : W_STOPCODE(p->p_xsig); - td->td_retval[0] = p->p_pid; PROC_UNLOCK(p); } +static int +wait6_checkopt(int options) +{ + /* If we don't know the option, just return. */ + if ((options & ~(WUNTRACED | WNOHANG | WCONTINUED | WNOWAIT | + WEXITED | WTRAPPED | WLINUXCLONE)) != 0) + return (EXTERROR(EINVAL, "Unknown options %#jx", options)); + if ((options & (WEXITED | WUNTRACED | WCONTINUED | WTRAPPED)) == 0) { + /* + * We will be unable to find any matching processes, + * because there are no known events to look for. + * Prefer to return error instead of blocking + * indefinitely. + */ + return (EXTERROR(EINVAL, + "Cannot match processes %#jx", options)); + } + return (0); +} + +/* + * Checks and reports status for alive process, according to the + * options. Returns true if the process fits one of the requested + * options and its status was updated in siginfo. + * + * If the process was reported (the function result is true), both the + * process and proctree locks are unlocked. + */ +static bool +wait6_check_alive(struct thread *td, int options, struct proc *p, int *status, + siginfo_t *siginfo) +{ + bool report; + + PROC_LOCK_ASSERT(p, MA_OWNED); + sx_assert(&proctree_lock, SA_XLOCKED); + + if ((options & WTRAPPED) != 0 && (p->p_flag & P_TRACED) != 0) { + PROC_SLOCK(p); + report = ((p->p_flag & (P_STOPPED_TRACE | P_STOPPED_SIG)) && + p->p_suspcount == p->p_numthreads && + (p->p_flag & P_WAITED) == 0); + PROC_SUNLOCK(p); + if (report) { + CTR4(KTR_PTRACE, + "wait: returning trapped pid %d status %#x (xstat %d) xthread %d", + p->p_pid, W_STOPCODE(p->p_xsig), p->p_xsig, + p->p_xthread != NULL ? + p->p_xthread->td_tid : -1); + report_alive_proc(td, p, siginfo, status, + options, CLD_TRAPPED); + return (true); + } + } + + if ((options & WUNTRACED) != 0 && (p->p_flag & P_STOPPED_SIG) != 0) { + PROC_SLOCK(p); + report = (p->p_suspcount == p->p_numthreads && + ((p->p_flag & P_WAITED) == 0)); + PROC_SUNLOCK(p); + if (report) { + report_alive_proc(td, p, siginfo, status, options, + CLD_STOPPED); + return (true); + } + } + + if ((options & WCONTINUED) != 0 && (p->p_flag & P_CONTINUED) != 0) { + report_alive_proc(td, p, siginfo, status, options, + CLD_CONTINUED); + return (true); + } + + return (false); +} + int kern_wait6(struct thread *td, idtype_t idtype, id_t id, int *status, int options, struct __wrusage *wrusage, siginfo_t *siginfo) @@ -1278,7 +1396,6 @@ struct proc *p, *q; pid_t pid; int error, nfound, ret; - bool report; AUDIT_ARG_VALUE((int)idtype); /* XXX - This is likely wrong! */ AUDIT_ARG_PID((pid_t)id); /* XXX - This may be wrong! */ @@ -1293,20 +1410,9 @@ idtype = P_PGID; } - /* If we don't know the option, just return. */ - if ((options & ~(WUNTRACED | WNOHANG | WCONTINUED | WNOWAIT | - WEXITED | WTRAPPED | WLINUXCLONE)) != 0) - return (EINVAL); - if ((options & (WEXITED | WUNTRACED | WCONTINUED | WTRAPPED)) == 0) { - /* - * We will be unable to find any matching processes, - * because there are no known events to look for. - * Prefer to return error instead of blocking - * indefinitely. - */ - return (EINVAL); - } - + error = wait6_checkopt(options); + if (error != 0) + return (error); loop: if (q->p_flag & P_STATCHILD) { PROC_LOCK(q); @@ -1342,44 +1448,11 @@ nfound++; PROC_LOCK_ASSERT(p, MA_OWNED); - if ((options & WTRAPPED) != 0 && - (p->p_flag & P_TRACED) != 0) { - PROC_SLOCK(p); - report = - ((p->p_flag & (P_STOPPED_TRACE | P_STOPPED_SIG)) && - p->p_suspcount == p->p_numthreads && - (p->p_flag & P_WAITED) == 0); - PROC_SUNLOCK(p); - if (report) { - CTR4(KTR_PTRACE, - "wait: returning trapped pid %d status %#x " - "(xstat %d) xthread %d", - p->p_pid, W_STOPCODE(p->p_xsig), p->p_xsig, - p->p_xthread != NULL ? - p->p_xthread->td_tid : -1); - report_alive_proc(td, p, siginfo, status, - options, CLD_TRAPPED); - return (0); - } - } - if ((options & WUNTRACED) != 0 && - (p->p_flag & P_STOPPED_SIG) != 0) { - PROC_SLOCK(p); - report = (p->p_suspcount == p->p_numthreads && - ((p->p_flag & P_WAITED) == 0)); - PROC_SUNLOCK(p); - if (report) { - report_alive_proc(td, p, siginfo, status, - options, CLD_STOPPED); - return (0); - } - } - if ((options & WCONTINUED) != 0 && - (p->p_flag & P_CONTINUED) != 0) { - report_alive_proc(td, p, siginfo, status, options, - CLD_CONTINUED); + if (wait6_check_alive(td, options, p, status, siginfo)) { + td->td_retval[0] = p->p_pid; return (0); } + PROC_UNLOCK(p); } @@ -1412,24 +1485,102 @@ sx_xunlock(&proctree_lock); return (ECHILD); } - if (options & WNOHANG) { + if ((options & WNOHANG) != 0) { sx_xunlock(&proctree_lock); td->td_retval[0] = 0; return (0); } PROC_LOCK(q); - if (q->p_flag & P_STATCHILD) { + if ((q->p_flag & P_STATCHILD) != 0) { q->p_flag &= ~P_STATCHILD; PROC_UNLOCK(q); goto loop_locked; } sx_xunlock(&proctree_lock); error = msleep(q, &q->p_mtx, PWAIT | PCATCH | PDROP, "wait", 0); - if (error) + if (error != 0) return (error); goto loop; } +int +kern_pdwait(struct thread *td, int fd, int *status, + int options, struct __wrusage *wrusage, siginfo_t *siginfo) +{ + struct proc *p; + struct file *fp; + struct procdesc *pd; + int error; + + AUDIT_ARG_FD(fd); + AUDIT_ARG_VALUE(options); + + error = wait6_checkopt(options); + if (error != 0) + return (error); + + error = fget(td, fd, &cap_pdwait_rights, &fp); + if (error != 0) + return (error); + if (fp->f_type != DTYPE_PROCDESC) { + error = EINVAL; + goto exit_unlocked; + } + pd = fp->f_data; + + for (;;) { + sx_xlock(&proctree_lock); + p = pd->pd_proc; + if (p == NULL) { + error = ESRCH; + goto exit_tree_locked; + } + PROC_LOCK(p); + + error = p_canwait(td, p); + if (error != 0) + break; + if ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) { + error = ESRCH; + break; + } + + wait_fill_siginfo(p, siginfo); + wait_fill_wrusage(p, wrusage); + + if (p->p_state == PRS_ZOMBIE) { + proc_reap(td, p, status, options); + goto exit_unlocked; + } + + if (wait6_check_alive(td, options, p, status, siginfo)) + goto exit_unlocked; + + if (p->p_state == PRS_ZOMBIE) { + if (status != NULL) + *status = KW_EXITCODE(p->p_xexit, p->p_xsig); + break; + } + if ((options & WNOHANG) != 0) { + error = EWOULDBLOCK; + break; + } + + PROC_UNLOCK(p); + error = sx_sleep(&p->p_procdesc, &proctree_lock, + PWAIT | PCATCH | PDROP, "pdwait", 0); + if (error != 0) + return (error); + } + + PROC_UNLOCK(p); +exit_tree_locked: + sx_xunlock(&proctree_lock); +exit_unlocked: + fdrop(fp, td); + return (error); +} + void proc_add_orphan(struct proc *child, struct proc *parent) { diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -34,20 +34,22 @@ * SUCH DAMAGE. */ -#include #include "opt_ktrace.h" #include "opt_kstack_pages.h" -#include +#define EXTERR_CATEGORY EXTERR_CAT_FORK #include +#include #include -#include #include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -60,17 +62,15 @@ #include #include #include +#include +#include +#include #include +#include +#include #include #include -#include -#include -#include #include -#include -#include -#include -#include #include #include @@ -166,10 +166,11 @@ /* Don't allow kernel-only flags. */ if ((uap->flags & RFKERNELONLY) != 0) - return (EINVAL); + return (EXTERROR(EINVAL, "Kernel-only flags %#jx", uap->flags)); /* RFSPAWN must not appear with others */ if ((uap->flags & RFSPAWN) != 0 && uap->flags != RFSPAWN) - return (EINVAL); + return (EXTERROR(EINVAL, "RFSPAWN must be the only flag %#jx", + uap->flags)); AUDIT_ARG_FFLAGS(uap->flags); bzero(&fr, sizeof(fr)); @@ -188,6 +189,48 @@ return (error); } +int +sys_pdrfork(struct thread *td, struct pdrfork_args *uap) +{ + struct fork_req fr; + int error, fd, pid; + + bzero(&fr, sizeof(fr)); + fd = -1; + + AUDIT_ARG_FFLAGS(uap->pdflags); + AUDIT_ARG_CMD(uap->rfflags); + + if ((uap->rfflags & (RFSTOPPED | RFHIGHPID)) != 0) + return (EXTERROR(EINVAL, + "Kernel-only flags %#jx", uap->rfflags)); + + /* RFSPAWN must not appear with others */ + if ((uap->rfflags & RFSPAWN) != 0) { + if (uap->rfflags != RFSPAWN) + return (EXTERROR(EINVAL, + "RFSPAWN must be the only flag %#jx", + uap->rfflags)); + fr.fr_flags = RFFDG | RFPROC | RFPPWAIT | RFMEM | RFPROCDESC; + fr.fr_flags2 = FR2_DROPSIG_CAUGHT; + } else { + fr.fr_flags = uap->rfflags; + } + + fr.fr_pidp = &pid; + fr.fr_pd_fd = &fd; + fr.fr_pd_flags = uap->pdflags; + error = fork1(td, &fr); + if (error == 0) { + td->td_retval[0] = pid; + td->td_retval[1] = 0; + if ((fr.fr_flags & (RFPROC | RFPROCDESC)) == + (RFPROC | RFPROCDESC) || uap->rfflags == RFSPAWN) + error = copyout(&fd, uap->fdp, sizeof(fd)); + } + return (error); +} + int __exclusive_cache_line nprocs = 1; /* process 0 */ int lastpid = 0; SYSCTL_INT(_kern, OID_AUTO, lastpid, CTLFLAG_RD, &lastpid, 0, @@ -871,34 +914,32 @@ else MPASS(fr->fr_procp == NULL); - /* Check for the undefined or unimplemented flags. */ if ((flags & ~(RFFLAGS | RFTSIGFLAGS(RFTSIGMASK))) != 0) - return (EINVAL); + return (EXTERROR(EINVAL, + "Undef or unimplemented flags %#jx", flags)); - /* Signal value requires RFTSIGZMB. */ if ((flags & RFTSIGFLAGS(RFTSIGMASK)) != 0 && (flags & RFTSIGZMB) == 0) - return (EINVAL); + return (EXTERROR(EINVAL, + "Signal value requires RFTSIGZMB", flags)); - /* Can't copy and clear. */ - if ((flags & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) - return (EINVAL); + if ((flags & (RFFDG | RFCFDG)) == (RFFDG | RFCFDG)) + return (EXTERROR(EINVAL, "Can not copy and clear")); - /* Check the validity of the signal number. */ if ((flags & RFTSIGZMB) != 0 && (u_int)RFTSIGNUM(flags) > _SIG_MAXSIG) - return (EINVAL); + return (EXTERROR(EINVAL, "Invalid signal", RFTSIGNUM(flags))); if ((flags & RFPROCDESC) != 0) { - /* Can't not create a process yet get a process descriptor. */ if ((flags & RFPROC) == 0) - return (EINVAL); + return (EXTERROR(EINVAL, + "Can not not create a process yet get a process descriptor")); - /* Must provide a place to put a procdesc if creating one. */ if (fr->fr_pd_fd == NULL) - return (EINVAL); + return (EXTERROR(EINVAL, + "Must provide a place to put a procdesc if creating one")); - /* Check if we are using supported flags. */ if ((fr->fr_pd_flags & ~PD_ALLOWED_AT_FORK) != 0) - return (EINVAL); + return (EXTERROR(EINVAL, + "Invallid pdflags at fork %#jx", fr->fr_pd_flags)); } p1 = td->td_proc; diff --git a/sys/kern/subr_capability.c b/sys/kern/subr_capability.c --- a/sys/kern/subr_capability.c +++ b/sys/kern/subr_capability.c @@ -90,6 +90,7 @@ const cap_rights_t cap_mknodat_rights = CAP_RIGHTS_INITIALIZER(CAP_MKNODAT); const cap_rights_t cap_pdgetpid_rights = CAP_RIGHTS_INITIALIZER(CAP_PDGETPID); const cap_rights_t cap_pdkill_rights = CAP_RIGHTS_INITIALIZER(CAP_PDKILL); +const cap_rights_t cap_pdwait_rights = CAP_RIGHTS_INITIALIZER(CAP_PDWAIT); const cap_rights_t cap_pread_rights = CAP_RIGHTS_INITIALIZER(CAP_PREAD); const cap_rights_t cap_pwrite_rights = CAP_RIGHTS_INITIALIZER(CAP_PWRITE); const cap_rights_t cap_read_rights = CAP_RIGHTS_INITIALIZER(CAP_READ); diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c --- a/sys/kern/sys_procdesc.c +++ b/sys/kern/sys_procdesc.c @@ -75,6 +75,7 @@ #include #include #include +#include #include #include #include @@ -270,6 +271,9 @@ KASSERT((pd->pd_flags & PDF_CLOSED), ("procdesc_free: !PDF_CLOSED")); + if (pd->pd_pid != -1) + proc_id_clear(PROC_ID_PID, pd->pd_pid); + knlist_destroy(&pd->pd_selinfo.si_note); PROCDESC_LOCK_DESTROY(pd); free(pd, M_PROCDESC); @@ -318,6 +322,9 @@ } KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT); PROCDESC_UNLOCK(pd); + + /* Wakeup all waiters for this procdesc' process exit. */ + wakeup(&p->p_procdesc); return (0); } @@ -389,6 +396,7 @@ */ pd->pd_proc = NULL; p->p_procdesc = NULL; + pd->pd_pid = -1; procdesc_free(pd); /* diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -605,4 +605,6 @@ "jail_attach_jd", /* 597 = jail_attach_jd */ "jail_remove_jd", /* 598 = jail_remove_jd */ "kexec_load", /* 599 = kexec_load */ + "pdrfork", /* 600 = pdrfork */ + "pdwait", /* 601 = pdwait */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -3402,4 +3402,23 @@ u_long flags ); } + +600 AUE_PDRFORK STD|CAPENABLED { + int pdrfork( + _Out_ int *fdp, + int pdflags, + int rfflags + ); + } + +601 AUE_PDWAIT STD|CAPENABLED { + int pdwait( + int fd, + _Out_opt_ int *status, + int options, + _Out_opt_ _Contains_long_ struct __wrusage *wrusage, + _Out_opt_ _Contains_long_ptr_ struct __siginfo *info + ); + } + ; vim: syntax=off diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3524,6 +3524,26 @@ *n_args = 4; break; } + /* pdrfork */ + case 600: { + struct pdrfork_args *p = params; + uarg[a++] = (intptr_t)p->fdp; /* int * */ + iarg[a++] = p->pdflags; /* int */ + iarg[a++] = p->rfflags; /* int */ + *n_args = 3; + break; + } + /* pdwait */ + case 601: { + struct pdwait_args *p = params; + iarg[a++] = p->fd; /* int */ + uarg[a++] = (intptr_t)p->status; /* int * */ + iarg[a++] = p->options; /* int */ + uarg[a++] = (intptr_t)p->wrusage; /* struct __wrusage * */ + uarg[a++] = (intptr_t)p->info; /* struct __siginfo * */ + *n_args = 5; + break; + } default: *n_args = 0; break; @@ -9430,6 +9450,44 @@ break; }; break; + /* pdrfork */ + case 600: + switch (ndx) { + case 0: + p = "userland int *"; + break; + case 1: + p = "int"; + break; + case 2: + p = "int"; + break; + default: + break; + }; + break; + /* pdwait */ + case 601: + switch (ndx) { + case 0: + p = "int"; + break; + case 1: + p = "userland int *"; + break; + case 2: + p = "int"; + break; + case 3: + p = "userland struct __wrusage *"; + break; + case 4: + p = "userland struct __siginfo *"; + break; + default: + break; + }; + break; default: break; }; @@ -11443,6 +11501,16 @@ if (ndx == 0 || ndx == 1) p = "int"; break; + /* pdrfork */ + case 600: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* pdwait */ + case 601: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c --- a/sys/security/audit/audit_bsm.c +++ b/sys/security/audit/audit_bsm.c @@ -1115,6 +1115,16 @@ } break; + case AUE_PDWAIT: + if (ARG_IS_VALID(kar, ARG_FFLAGS)) { + tok = au_to_arg32(1, "flags", ar->ar_arg_fflags); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_FD)) { + tok = au_to_arg32(1, "fd", ar->ar_arg_fd); + kau_write(rec, tok); + } + case AUE_IOCTL: if (ARG_IS_VALID(kar, ARG_CMD)) { tok = au_to_arg32(2, "cmd", ar->ar_arg_cmd); @@ -1365,6 +1375,24 @@ kau_write(rec, tok); } break; + case AUE_PDRFORK: + if (ARG_IS_VALID(kar, ARG_PID)) { + tok = au_to_arg32(0, "child PID", ar->ar_arg_pid); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_CMD)) { + tok = au_to_arg32(2, "fflags", ar->ar_arg_cmd); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_FFLAGS)) { + tok = au_to_arg32(2, "flags", ar->ar_arg_fflags); + kau_write(rec, tok); + } + if (ARG_IS_VALID(kar, ARG_FD)) { + tok = au_to_arg32(1, "fd", ar->ar_arg_fd); + kau_write(rec, tok); + } + break; case AUE_PDGETPID: if (ARG_IS_VALID(kar, ARG_FD)) { tok = au_to_arg32(1, "fd", ar->ar_arg_fd); diff --git a/sys/sys/caprights.h b/sys/sys/caprights.h --- a/sys/sys/caprights.h +++ b/sys/sys/caprights.h @@ -92,6 +92,7 @@ extern const cap_rights_t cap_no_rights; extern const cap_rights_t cap_pdgetpid_rights; extern const cap_rights_t cap_pdkill_rights; +extern const cap_rights_t cap_pdwait_rights; extern const cap_rights_t cap_pread_rights; extern const cap_rights_t cap_pwrite_rights; extern const cap_rights_t cap_read_rights; diff --git a/sys/sys/exterr_cat.h b/sys/sys/exterr_cat.h --- a/sys/sys/exterr_cat.h +++ b/sys/sys/exterr_cat.h @@ -37,6 +37,8 @@ #define EXTERR_CAT_GEOM 12 #define EXTERR_CAT_FUSE_VFS 13 #define EXTERR_CAT_FUSE_DEVICE 14 +#define EXTERR_CAT_FORK 15 +#define EXTERR_CAT_PROCEXIT 16 #endif diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h --- a/sys/sys/procdesc.h +++ b/sys/sys/procdesc.h @@ -122,9 +122,14 @@ * Process descriptor system calls. */ __BEGIN_DECLS +struct __wrusage; +struct __siginfo; + pid_t pdfork(int *, int); +pid_t pdrfork(int *, int, int); int pdkill(int, int); int pdgetpid(int, pid_t *); +int pdwait(int, int *, int, struct __wrusage *, struct __siginfo *); __END_DECLS #endif /* _KERNEL */ diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -538,4 +538,6 @@ #define SYS_jail_attach_jd 597 #define SYS_jail_remove_jd 598 #define SYS_kexec_load 599 -#define SYS_MAXSYSCALL 600 +#define SYS_pdrfork 600 +#define SYS_pdwait 601 +#define SYS_MAXSYSCALL 602 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -441,4 +441,6 @@ setgroups.o \ jail_attach_jd.o \ jail_remove_jd.o \ - kexec_load.o + kexec_load.o \ + pdrfork.o \ + pdwait.o diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -286,6 +286,8 @@ off_t len); int kern_fspacectl(struct thread *td, int fd, int cmd, const struct spacectl_range *, int flags, struct spacectl_range *); +int kern_pdwait(struct thread *td, int fd, int *status, + int options, struct __wrusage *wrusage, siginfo_t *sip); int kern_procctl(struct thread *td, enum idtype idtype, id_t id, int com, void *data); int kern_pread(struct thread *td, int fd, void *buf, size_t nbyte, diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -1913,6 +1913,18 @@ char segments_l_[PADL_(struct kexec_segment *)]; struct kexec_segment * segments; char segments_r_[PADR_(struct kexec_segment *)]; char flags_l_[PADL_(u_long)]; u_long flags; char flags_r_[PADR_(u_long)]; }; +struct pdrfork_args { + char fdp_l_[PADL_(int *)]; int * fdp; char fdp_r_[PADR_(int *)]; + char pdflags_l_[PADL_(int)]; int pdflags; char pdflags_r_[PADR_(int)]; + char rfflags_l_[PADL_(int)]; int rfflags; char rfflags_r_[PADR_(int)]; +}; +struct pdwait_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char status_l_[PADL_(int *)]; int * status; char status_r_[PADR_(int *)]; + char options_l_[PADL_(int)]; int options; char options_r_[PADR_(int)]; + char wrusage_l_[PADL_(struct __wrusage *)]; struct __wrusage * wrusage; char wrusage_r_[PADR_(struct __wrusage *)]; + char info_l_[PADL_(struct __siginfo *)]; struct __siginfo * info; char info_r_[PADR_(struct __siginfo *)]; +}; int sys__exit(struct thread *, struct _exit_args *); int sys_fork(struct thread *, struct fork_args *); int sys_read(struct thread *, struct read_args *); @@ -2320,6 +2332,8 @@ int sys_jail_attach_jd(struct thread *, struct jail_attach_jd_args *); int sys_jail_remove_jd(struct thread *, struct jail_remove_jd_args *); int sys_kexec_load(struct thread *, struct kexec_load_args *); +int sys_pdrfork(struct thread *, struct pdrfork_args *); +int sys_pdwait(struct thread *, struct pdwait_args *); #ifdef COMPAT_43 @@ -3319,6 +3333,8 @@ #define SYS_AUE_jail_attach_jd AUE_JAIL_ATTACH #define SYS_AUE_jail_remove_jd AUE_JAIL_REMOVE #define SYS_AUE_kexec_load AUE_NULL +#define SYS_AUE_pdrfork AUE_PDRFORK +#define SYS_AUE_pdwait AUE_PDWAIT #undef PAD_ #undef PADL_