posix_spawn.c revision 287292
1179838Sdavidxu/*- 2179840Sed * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 3179838Sdavidxu * All rights reserved. 4179838Sdavidxu * 5179838Sdavidxu * Redistribution and use in source and binary forms, with or without 6179838Sdavidxu * modification, are permitted provided that the following conditions 7179838Sdavidxu * are met: 8179838Sdavidxu * 1. Redistributions of source code must retain the above copyright 9179838Sdavidxu * notice, this list of conditions and the following disclaimer. 10179838Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright 11179838Sdavidxu * notice, this list of conditions and the following disclaimer in the 12179838Sdavidxu * documentation and/or other materials provided with the distribution. 13179838Sdavidxu * 14179838Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15179838Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16179838Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17179838Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18179838Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19179838Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20179838Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21179838Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22179838Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23179838Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24179838Sdavidxu * SUCH DAMAGE. 25179838Sdavidxu */ 26179838Sdavidxu 27179838Sdavidxu#include <sys/cdefs.h> 28179838Sdavidxu__FBSDID("$FreeBSD: head/lib/libc/gen/posix_spawn.c 287292 2015-08-29 14:25:01Z kib $"); 29179838Sdavidxu 30179838Sdavidxu#include "namespace.h" 31179838Sdavidxu#include <sys/queue.h> 32223907Sjilles#include <sys/wait.h> 33179838Sdavidxu 34179838Sdavidxu#include <errno.h> 35179838Sdavidxu#include <fcntl.h> 36179838Sdavidxu#include <sched.h> 37179838Sdavidxu#include <spawn.h> 38179838Sdavidxu#include <signal.h> 39179838Sdavidxu#include <stdlib.h> 40179838Sdavidxu#include <string.h> 41179838Sdavidxu#include <unistd.h> 42179838Sdavidxu#include "un-namespace.h" 43179947Sed#include "libc_private.h" 44179838Sdavidxu 45179838Sdavidxuextern char **environ; 46179838Sdavidxu 47179838Sdavidxustruct __posix_spawnattr { 48179838Sdavidxu short sa_flags; 49179838Sdavidxu pid_t sa_pgroup; 50179838Sdavidxu struct sched_param sa_schedparam; 51179838Sdavidxu int sa_schedpolicy; 52179838Sdavidxu sigset_t sa_sigdefault; 53179838Sdavidxu sigset_t sa_sigmask; 54179838Sdavidxu}; 55179838Sdavidxu 56179838Sdavidxustruct __posix_spawn_file_actions { 57179838Sdavidxu STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list; 58179838Sdavidxu}; 59179838Sdavidxu 60179838Sdavidxutypedef struct __posix_spawn_file_actions_entry { 61179838Sdavidxu STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list; 62179838Sdavidxu enum { FAE_OPEN, FAE_DUP2, FAE_CLOSE } fae_action; 63179838Sdavidxu 64179838Sdavidxu int fae_fildes; 65179838Sdavidxu union { 66179838Sdavidxu struct { 67179838Sdavidxu char *path; 68179838Sdavidxu#define fae_path fae_data.open.path 69179838Sdavidxu int oflag; 70179838Sdavidxu#define fae_oflag fae_data.open.oflag 71179838Sdavidxu mode_t mode; 72179838Sdavidxu#define fae_mode fae_data.open.mode 73179838Sdavidxu } open; 74179838Sdavidxu struct { 75179838Sdavidxu int newfildes; 76179838Sdavidxu#define fae_newfildes fae_data.dup2.newfildes 77179838Sdavidxu } dup2; 78179838Sdavidxu } fae_data; 79179838Sdavidxu} posix_spawn_file_actions_entry_t; 80179838Sdavidxu 81179838Sdavidxu/* 82179838Sdavidxu * Spawn routines 83179838Sdavidxu */ 84179838Sdavidxu 85179838Sdavidxustatic int 86179838Sdavidxuprocess_spawnattr(const posix_spawnattr_t sa) 87179838Sdavidxu{ 88179838Sdavidxu struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL }; 89179838Sdavidxu int i; 90179838Sdavidxu 91179838Sdavidxu /* 92179838Sdavidxu * POSIX doesn't really describe in which order everything 93179838Sdavidxu * should be set. We'll just set them in the order in which they 94179838Sdavidxu * are mentioned. 95179838Sdavidxu */ 96179838Sdavidxu 97179838Sdavidxu /* Set process group */ 98179838Sdavidxu if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) { 99179838Sdavidxu if (setpgid(0, sa->sa_pgroup) != 0) 100179838Sdavidxu return (errno); 101179838Sdavidxu } 102179838Sdavidxu 103179838Sdavidxu /* Set scheduler policy */ 104179838Sdavidxu if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) { 105179838Sdavidxu if (sched_setscheduler(0, sa->sa_schedpolicy, 106179838Sdavidxu &sa->sa_schedparam) != 0) 107179838Sdavidxu return (errno); 108179838Sdavidxu } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) { 109179838Sdavidxu if (sched_setparam(0, &sa->sa_schedparam) != 0) 110179838Sdavidxu return (errno); 111179838Sdavidxu } 112179866Sdavidxu 113179866Sdavidxu /* Reset user ID's */ 114179866Sdavidxu if (sa->sa_flags & POSIX_SPAWN_RESETIDS) { 115179866Sdavidxu if (setegid(getgid()) != 0) 116179866Sdavidxu return (errno); 117179866Sdavidxu if (seteuid(getuid()) != 0) 118179866Sdavidxu return (errno); 119179866Sdavidxu } 120179866Sdavidxu 121287292Skib /* 122287292Skib * Set signal masks/defaults. 123287292Skib * Use unwrapped syscall, libthr is in undefined state after vfork(). 124287292Skib */ 125179866Sdavidxu if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) { 126287292Skib __libc_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL); 127179866Sdavidxu } 128179866Sdavidxu 129179866Sdavidxu if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) { 130179866Sdavidxu for (i = 1; i <= _SIG_MAXSIG; i++) { 131179866Sdavidxu if (sigismember(&sa->sa_sigdefault, i)) 132287292Skib if (__libc_sigaction(i, &sigact, NULL) != 0) 133179866Sdavidxu return (errno); 134179866Sdavidxu } 135179866Sdavidxu } 136179866Sdavidxu 137179838Sdavidxu return (0); 138179838Sdavidxu} 139179838Sdavidxu 140179838Sdavidxustatic int 141179838Sdavidxuprocess_file_actions_entry(posix_spawn_file_actions_entry_t *fae) 142179838Sdavidxu{ 143179838Sdavidxu int fd; 144179838Sdavidxu 145179838Sdavidxu switch (fae->fae_action) { 146179838Sdavidxu case FAE_OPEN: 147179838Sdavidxu /* Perform an open(), make it use the right fd */ 148179838Sdavidxu fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode); 149179838Sdavidxu if (fd < 0) 150179838Sdavidxu return (errno); 151179838Sdavidxu if (fd != fae->fae_fildes) { 152179838Sdavidxu if (_dup2(fd, fae->fae_fildes) == -1) 153179838Sdavidxu return (errno); 154179838Sdavidxu if (_close(fd) != 0) { 155179838Sdavidxu if (errno == EBADF) 156179838Sdavidxu return (EBADF); 157179838Sdavidxu } 158179838Sdavidxu } 159179838Sdavidxu if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1) 160179838Sdavidxu return (errno); 161179838Sdavidxu break; 162179838Sdavidxu case FAE_DUP2: 163179838Sdavidxu /* Perform a dup2() */ 164179838Sdavidxu if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1) 165179838Sdavidxu return (errno); 166179838Sdavidxu if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1) 167179838Sdavidxu return (errno); 168179838Sdavidxu break; 169179838Sdavidxu case FAE_CLOSE: 170222511Sjilles /* Perform a close(), do not fail if already closed */ 171222511Sjilles (void)_close(fae->fae_fildes); 172179838Sdavidxu break; 173179838Sdavidxu } 174179838Sdavidxu return (0); 175179838Sdavidxu} 176179838Sdavidxu 177179838Sdavidxustatic int 178179838Sdavidxuprocess_file_actions(const posix_spawn_file_actions_t fa) 179179838Sdavidxu{ 180179838Sdavidxu posix_spawn_file_actions_entry_t *fae; 181179838Sdavidxu int error; 182179838Sdavidxu 183179838Sdavidxu /* Replay all file descriptor modifications */ 184179838Sdavidxu STAILQ_FOREACH(fae, &fa->fa_list, fae_list) { 185179838Sdavidxu error = process_file_actions_entry(fae); 186179838Sdavidxu if (error) 187179838Sdavidxu return (error); 188179838Sdavidxu } 189223576Sed return (0); 190179838Sdavidxu} 191179838Sdavidxu 192179838Sdavidxustatic int 193179838Sdavidxudo_posix_spawn(pid_t *pid, const char *path, 194179838Sdavidxu const posix_spawn_file_actions_t *fa, 195179838Sdavidxu const posix_spawnattr_t *sa, 196179838Sdavidxu char * const argv[], char * const envp[], int use_env_path) 197179838Sdavidxu{ 198179838Sdavidxu pid_t p; 199179838Sdavidxu volatile int error = 0; 200223576Sed 201179838Sdavidxu p = vfork(); 202179838Sdavidxu switch (p) { 203179838Sdavidxu case -1: 204179838Sdavidxu return (errno); 205179838Sdavidxu case 0: 206179838Sdavidxu if (sa != NULL) { 207179838Sdavidxu error = process_spawnattr(*sa); 208179838Sdavidxu if (error) 209179838Sdavidxu _exit(127); 210179838Sdavidxu } 211179838Sdavidxu if (fa != NULL) { 212179838Sdavidxu error = process_file_actions(*fa); 213179838Sdavidxu if (error) 214179838Sdavidxu _exit(127); 215179838Sdavidxu } 216179838Sdavidxu if (use_env_path) 217179947Sed _execvpe(path, argv, envp != NULL ? envp : environ); 218179838Sdavidxu else 219179838Sdavidxu _execve(path, argv, envp != NULL ? envp : environ); 220179838Sdavidxu error = errno; 221179838Sdavidxu _exit(127); 222179838Sdavidxu default: 223223907Sjilles if (error != 0) 224223907Sjilles _waitpid(p, NULL, WNOHANG); 225223907Sjilles else if (pid != NULL) 226179838Sdavidxu *pid = p; 227179838Sdavidxu return (error); 228179838Sdavidxu } 229179838Sdavidxu} 230179838Sdavidxu 231179838Sdavidxuint 232179838Sdavidxuposix_spawn(pid_t *pid, const char *path, 233179838Sdavidxu const posix_spawn_file_actions_t *fa, 234179838Sdavidxu const posix_spawnattr_t *sa, 235179838Sdavidxu char * const argv[], char * const envp[]) 236179838Sdavidxu{ 237179838Sdavidxu return do_posix_spawn(pid, path, fa, sa, argv, envp, 0); 238179838Sdavidxu} 239179838Sdavidxu 240179838Sdavidxuint 241179838Sdavidxuposix_spawnp(pid_t *pid, const char *path, 242179838Sdavidxu const posix_spawn_file_actions_t *fa, 243179838Sdavidxu const posix_spawnattr_t *sa, 244179838Sdavidxu char * const argv[], char * const envp[]) 245179838Sdavidxu{ 246179838Sdavidxu return do_posix_spawn(pid, path, fa, sa, argv, envp, 1); 247179838Sdavidxu} 248179838Sdavidxu 249179838Sdavidxu/* 250179838Sdavidxu * File descriptor actions 251179838Sdavidxu */ 252179838Sdavidxu 253179838Sdavidxuint 254179838Sdavidxuposix_spawn_file_actions_init(posix_spawn_file_actions_t *ret) 255179838Sdavidxu{ 256179838Sdavidxu posix_spawn_file_actions_t fa; 257179838Sdavidxu 258179838Sdavidxu fa = malloc(sizeof(struct __posix_spawn_file_actions)); 259179838Sdavidxu if (fa == NULL) 260179838Sdavidxu return (-1); 261179838Sdavidxu 262179838Sdavidxu STAILQ_INIT(&fa->fa_list); 263179838Sdavidxu *ret = fa; 264179838Sdavidxu return (0); 265179838Sdavidxu} 266179838Sdavidxu 267179838Sdavidxuint 268179838Sdavidxuposix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa) 269179838Sdavidxu{ 270179838Sdavidxu posix_spawn_file_actions_entry_t *fae; 271179838Sdavidxu 272179838Sdavidxu while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) { 273179838Sdavidxu /* Remove file action entry from the queue */ 274179838Sdavidxu STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list); 275179838Sdavidxu 276179838Sdavidxu /* Deallocate file action entry */ 277179838Sdavidxu if (fae->fae_action == FAE_OPEN) 278179838Sdavidxu free(fae->fae_path); 279179838Sdavidxu free(fae); 280179838Sdavidxu } 281179838Sdavidxu 282179838Sdavidxu free(*fa); 283179838Sdavidxu return (0); 284179838Sdavidxu} 285179838Sdavidxu 286179838Sdavidxuint 287179838Sdavidxuposix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa, 288179838Sdavidxu int fildes, const char * __restrict path, int oflag, mode_t mode) 289179838Sdavidxu{ 290179838Sdavidxu posix_spawn_file_actions_entry_t *fae; 291179838Sdavidxu int error; 292179838Sdavidxu 293179838Sdavidxu if (fildes < 0) 294179838Sdavidxu return (EBADF); 295179838Sdavidxu 296179838Sdavidxu /* Allocate object */ 297179838Sdavidxu fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 298179838Sdavidxu if (fae == NULL) 299179838Sdavidxu return (errno); 300179838Sdavidxu 301179838Sdavidxu /* Set values and store in queue */ 302179838Sdavidxu fae->fae_action = FAE_OPEN; 303179838Sdavidxu fae->fae_path = strdup(path); 304179838Sdavidxu if (fae->fae_path == NULL) { 305179838Sdavidxu error = errno; 306179838Sdavidxu free(fae); 307179838Sdavidxu return (error); 308179838Sdavidxu } 309179838Sdavidxu fae->fae_fildes = fildes; 310179838Sdavidxu fae->fae_oflag = oflag; 311179838Sdavidxu fae->fae_mode = mode; 312179838Sdavidxu 313179838Sdavidxu STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 314179838Sdavidxu return (0); 315179838Sdavidxu} 316179838Sdavidxu 317179838Sdavidxuint 318179838Sdavidxuposix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, 319179838Sdavidxu int fildes, int newfildes) 320179838Sdavidxu{ 321179838Sdavidxu posix_spawn_file_actions_entry_t *fae; 322179838Sdavidxu 323179838Sdavidxu if (fildes < 0 || newfildes < 0) 324179838Sdavidxu return (EBADF); 325179838Sdavidxu 326179838Sdavidxu /* Allocate object */ 327179838Sdavidxu fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 328179838Sdavidxu if (fae == NULL) 329179838Sdavidxu return (errno); 330179838Sdavidxu 331179838Sdavidxu /* Set values and store in queue */ 332179838Sdavidxu fae->fae_action = FAE_DUP2; 333179838Sdavidxu fae->fae_fildes = fildes; 334179838Sdavidxu fae->fae_newfildes = newfildes; 335179838Sdavidxu 336179838Sdavidxu STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 337179838Sdavidxu return (0); 338179838Sdavidxu} 339179838Sdavidxu 340179841Sdavidxuint 341179841Sdavidxuposix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, 342179838Sdavidxu int fildes) 343179838Sdavidxu{ 344179838Sdavidxu posix_spawn_file_actions_entry_t *fae; 345179838Sdavidxu 346179838Sdavidxu if (fildes < 0) 347179838Sdavidxu return (EBADF); 348179838Sdavidxu 349179838Sdavidxu /* Allocate object */ 350179838Sdavidxu fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 351179838Sdavidxu if (fae == NULL) 352179838Sdavidxu return (errno); 353179838Sdavidxu 354179838Sdavidxu /* Set values and store in queue */ 355179838Sdavidxu fae->fae_action = FAE_CLOSE; 356179838Sdavidxu fae->fae_fildes = fildes; 357179838Sdavidxu 358179838Sdavidxu STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 359179838Sdavidxu return (0); 360179838Sdavidxu} 361179838Sdavidxu 362179838Sdavidxu/* 363179838Sdavidxu * Spawn attributes 364179838Sdavidxu */ 365179838Sdavidxu 366179838Sdavidxuint 367179838Sdavidxuposix_spawnattr_init(posix_spawnattr_t *ret) 368179838Sdavidxu{ 369179838Sdavidxu posix_spawnattr_t sa; 370179838Sdavidxu 371179838Sdavidxu sa = calloc(1, sizeof(struct __posix_spawnattr)); 372179838Sdavidxu if (sa == NULL) 373179838Sdavidxu return (errno); 374179838Sdavidxu 375179838Sdavidxu /* Set defaults as specified by POSIX, cleared above */ 376179838Sdavidxu *ret = sa; 377179838Sdavidxu return (0); 378179838Sdavidxu} 379179838Sdavidxu 380179838Sdavidxuint 381179838Sdavidxuposix_spawnattr_destroy(posix_spawnattr_t *sa) 382179838Sdavidxu{ 383179838Sdavidxu free(*sa); 384179838Sdavidxu return (0); 385179838Sdavidxu} 386179838Sdavidxu 387179838Sdavidxuint 388179838Sdavidxuposix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa, 389179838Sdavidxu short * __restrict flags) 390179838Sdavidxu{ 391179838Sdavidxu *flags = (*sa)->sa_flags; 392179838Sdavidxu return (0); 393179838Sdavidxu} 394179838Sdavidxu 395179838Sdavidxuint 396179838Sdavidxuposix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa, 397179838Sdavidxu pid_t * __restrict pgroup) 398179838Sdavidxu{ 399179838Sdavidxu *pgroup = (*sa)->sa_pgroup; 400179838Sdavidxu return (0); 401179838Sdavidxu} 402179838Sdavidxu 403179838Sdavidxuint 404179838Sdavidxuposix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa, 405179838Sdavidxu struct sched_param * __restrict schedparam) 406179838Sdavidxu{ 407179838Sdavidxu *schedparam = (*sa)->sa_schedparam; 408179838Sdavidxu return (0); 409179838Sdavidxu} 410179838Sdavidxu 411179838Sdavidxuint 412179838Sdavidxuposix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa, 413179838Sdavidxu int * __restrict schedpolicy) 414179838Sdavidxu{ 415179838Sdavidxu *schedpolicy = (*sa)->sa_schedpolicy; 416179838Sdavidxu return (0); 417179838Sdavidxu} 418179838Sdavidxu 419179838Sdavidxuint 420179838Sdavidxuposix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa, 421179838Sdavidxu sigset_t * __restrict sigdefault) 422179838Sdavidxu{ 423179838Sdavidxu *sigdefault = (*sa)->sa_sigdefault; 424179838Sdavidxu return (0); 425179838Sdavidxu} 426179838Sdavidxu 427179838Sdavidxuint 428179838Sdavidxuposix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa, 429179838Sdavidxu sigset_t * __restrict sigmask) 430179838Sdavidxu{ 431179838Sdavidxu *sigmask = (*sa)->sa_sigmask; 432179838Sdavidxu return (0); 433179838Sdavidxu} 434179838Sdavidxu 435179838Sdavidxuint 436179838Sdavidxuposix_spawnattr_setflags(posix_spawnattr_t *sa, short flags) 437179838Sdavidxu{ 438179838Sdavidxu (*sa)->sa_flags = flags; 439179838Sdavidxu return (0); 440179838Sdavidxu} 441179838Sdavidxu 442179838Sdavidxuint 443179838Sdavidxuposix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup) 444179838Sdavidxu{ 445179838Sdavidxu (*sa)->sa_pgroup = pgroup; 446179838Sdavidxu return (0); 447179838Sdavidxu} 448179838Sdavidxu 449179838Sdavidxuint 450184203Srdivackyposix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa, 451179838Sdavidxu const struct sched_param * __restrict schedparam) 452179838Sdavidxu{ 453179838Sdavidxu (*sa)->sa_schedparam = *schedparam; 454179838Sdavidxu return (0); 455179838Sdavidxu} 456179838Sdavidxu 457179838Sdavidxuint 458179838Sdavidxuposix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy) 459179838Sdavidxu{ 460179838Sdavidxu (*sa)->sa_schedpolicy = schedpolicy; 461179838Sdavidxu return (0); 462179838Sdavidxu} 463179838Sdavidxu 464179838Sdavidxuint 465179838Sdavidxuposix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa, 466179838Sdavidxu const sigset_t * __restrict sigdefault) 467179838Sdavidxu{ 468179838Sdavidxu (*sa)->sa_sigdefault = *sigdefault; 469179838Sdavidxu return (0); 470179838Sdavidxu} 471179838Sdavidxu 472179838Sdavidxuint 473179838Sdavidxuposix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa, 474179838Sdavidxu const sigset_t * __restrict sigmask) 475179838Sdavidxu{ 476179838Sdavidxu (*sa)->sa_sigmask = *sigmask; 477179838Sdavidxu return (0); 478179838Sdavidxu} 479