5855 fix __RESTRICT_KYWD to support the correct keyword with c++
[illumos-gate.git] / usr / src / lib / libc / port / threads / spawn.c
blobf578896bece271678209febd3701e4c76f33b7fd
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright (c) 2011 by Delphix. All rights reserved.
31 #include "lint.h"
32 #include "thr_uberdata.h"
33 #include <sys/libc_kernel.h>
34 #include <sys/procset.h>
35 #include <sys/fork.h>
36 #include <dirent.h>
37 #include <alloca.h>
38 #include <spawn.h>
39 #include <paths.h>
41 #define ALL_POSIX_SPAWN_FLAGS \
42 (POSIX_SPAWN_RESETIDS | \
43 POSIX_SPAWN_SETPGROUP | \
44 POSIX_SPAWN_SETSIGDEF | \
45 POSIX_SPAWN_SETSIGMASK | \
46 POSIX_SPAWN_SETSCHEDPARAM | \
47 POSIX_SPAWN_SETSCHEDULER | \
48 POSIX_SPAWN_SETSIGIGN_NP | \
49 POSIX_SPAWN_NOSIGCHLD_NP | \
50 POSIX_SPAWN_WAITPID_NP | \
51 POSIX_SPAWN_NOEXECERR_NP)
53 typedef struct {
54 int sa_psflags; /* POSIX_SPAWN_* flags */
55 int sa_priority;
56 int sa_schedpolicy;
57 pid_t sa_pgroup;
58 sigset_t sa_sigdefault;
59 sigset_t sa_sigignore;
60 sigset_t sa_sigmask;
61 } spawn_attr_t;
63 typedef struct file_attr {
64 struct file_attr *fa_next; /* circular list of file actions */
65 struct file_attr *fa_prev;
66 enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type;
67 int fa_need_dirbuf; /* only consulted in the head action */
68 char *fa_path; /* copied pathname for open() */
69 uint_t fa_pathsize; /* size of fa_path[] array */
70 int fa_oflag; /* oflag for open() */
71 mode_t fa_mode; /* mode for open() */
72 int fa_filedes; /* file descriptor for open()/close() */
73 int fa_newfiledes; /* new file descriptor for dup2() */
74 } file_attr_t;
76 #if defined(_LP64)
77 #define __open64 __open
78 #define getdents64 getdents
79 #define dirent64_t dirent_t
80 #else
81 extern int getdents64(int, dirent64_t *, size_t);
82 #endif
84 extern const char **_environ;
87 * Support function:
88 * Close all open file descriptors greater than or equal to lowfd.
89 * This is executed in the child of vfork(), so we must not call
90 * opendir() / readdir() because that would alter the parent's
91 * address space. We use the low-level getdents64() system call.
92 * Return non-zero on error.
94 static int
95 spawn_closefrom(int lowfd, void *buf)
97 int procfd;
98 int fd;
99 int buflen;
100 dirent64_t *dp;
101 dirent64_t *dpend;
103 if (lowfd < 0)
104 lowfd = 0;
107 * Close lowfd right away as a hedge against failing
108 * to open the /proc file descriptor directory due
109 * all file descriptors being currently used up.
111 (void) __close(lowfd++);
113 if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
115 * We could not open the /proc file descriptor directory.
116 * Just fail and be done with it.
118 return (-1);
121 for (;;) {
123 * Collect a bunch of open file descriptors and close them.
124 * Repeat until the directory is exhausted.
126 dp = (dirent64_t *)buf;
127 if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
128 (void) __close(procfd);
129 break;
131 dpend = (dirent64_t *)((uintptr_t)buf + buflen);
132 do {
133 /* skip '.', '..' and procfd */
134 if (dp->d_name[0] != '.' &&
135 (fd = atoi(dp->d_name)) != procfd &&
136 fd >= lowfd)
137 (void) __close(fd);
138 dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen);
139 } while (dp < dpend);
142 return (0);
145 static int
146 perform_flag_actions(spawn_attr_t *sap)
148 int sig;
149 struct sigaction action;
151 if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
152 (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask);
155 if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) {
156 (void) memset(&action, 0, sizeof (action));
157 action.sa_handler = SIG_IGN;
158 for (sig = 1; sig < NSIG; sig++) {
159 if (sigismember(&sap->sa_sigignore, sig))
160 (void) __sigaction(sig, &action, NULL);
164 if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) {
165 (void) memset(&action, 0, sizeof (action));
166 action.sa_handler = SIG_DFL;
167 for (sig = 1; sig < NSIG; sig++) {
168 if (sigismember(&sap->sa_sigdefault, sig))
169 (void) __sigaction(sig, &action, NULL);
173 if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
174 if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
175 return (errno);
178 if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
179 if (setpgid(0, sap->sa_pgroup) != 0)
180 return (errno);
183 if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) {
184 if (setparam(P_LWPID, P_MYID,
185 sap->sa_schedpolicy, sap->sa_priority) == -1)
186 return (errno);
187 } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) {
188 if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1)
189 return (errno);
192 return (0);
195 static int
196 perform_file_actions(file_attr_t *fap, void *dirbuf)
198 file_attr_t *froot = fap;
199 int fd;
201 do {
202 switch (fap->fa_type) {
203 case FA_OPEN:
204 fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode);
205 if (fd < 0)
206 return (errno);
207 if (fd != fap->fa_filedes) {
208 if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0)
209 return (errno);
210 (void) __close(fd);
212 break;
213 case FA_CLOSE:
214 if (__close(fap->fa_filedes) == -1 &&
215 errno != EBADF) /* already closed, no error */
216 return (errno);
217 break;
218 case FA_DUP2:
219 fd = __fcntl(fap->fa_filedes, F_DUP2FD,
220 fap->fa_newfiledes);
221 if (fd < 0)
222 return (errno);
223 break;
224 case FA_CLOSEFROM:
225 if (spawn_closefrom(fap->fa_filedes, dirbuf))
226 return (errno);
227 break;
229 } while ((fap = fap->fa_next) != froot);
231 return (0);
234 static int
235 forkflags(spawn_attr_t *sap)
237 int flags = 0;
239 if (sap != NULL) {
240 if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP)
241 flags |= FORK_NOSIGCHLD;
242 if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP)
243 flags |= FORK_WAITPID;
246 return (flags);
250 * set_error() / get_error() are used to guarantee that the local variable
251 * 'error' is set correctly in memory on return from vfork() in the parent.
254 static int
255 set_error(int *errp, int err)
257 return (*errp = err);
260 static int
261 get_error(int *errp)
263 return (*errp);
267 * For MT safety, do not invoke the dynamic linker after calling vfork().
268 * If some other thread was in the dynamic linker when this thread's parent
269 * called vfork() then the dynamic linker's lock would still be held here
270 * (with a defunct owner) and we would deadlock ourself if we invoked it.
272 * Therefore, all of the functions we call here after returning from
273 * vforkx() in the child are not and must never be exported from libc
274 * as global symbols. To do so would risk invoking the dynamic linker.
278 posix_spawn(
279 pid_t *pidp,
280 const char *path,
281 const posix_spawn_file_actions_t *file_actions,
282 const posix_spawnattr_t *attrp,
283 char *const *argv,
284 char *const *envp)
286 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
287 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
288 void *dirbuf = NULL;
289 int error; /* this will be set by the child */
290 pid_t pid;
292 if (attrp != NULL && sap == NULL)
293 return (EINVAL);
295 if (fap != NULL && fap->fa_need_dirbuf) {
297 * Preallocate the buffer for the call to getdents64() in
298 * spawn_closefrom() since we can't do it in the vfork() child.
300 if ((dirbuf = lmalloc(DIRBUF)) == NULL)
301 return (ENOMEM);
304 switch (pid = vforkx(forkflags(sap))) {
305 case 0: /* child */
306 break;
307 case -1: /* parent, failure */
308 if (dirbuf)
309 lfree(dirbuf, DIRBUF);
310 return (errno);
311 default: /* parent, success */
313 * We don't get here until the child exec()s or exit()s
315 if (pidp != NULL && get_error(&error) == 0)
316 *pidp = pid;
317 if (dirbuf)
318 lfree(dirbuf, DIRBUF);
319 return (get_error(&error));
322 if (sap != NULL)
323 if (set_error(&error, perform_flag_actions(sap)) != 0)
324 _exit(_EVAPORATE);
326 if (fap != NULL)
327 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
328 _exit(_EVAPORATE);
330 (void) set_error(&error, 0);
331 (void) execve(path, argv, envp);
332 if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
333 _exit(127);
334 (void) set_error(&error, errno);
335 _exit(_EVAPORATE);
336 return (0); /* not reached */
340 * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
343 extern int libc__xpg4;
345 static const char *
346 execat(const char *s1, const char *s2, char *si)
348 int cnt = PATH_MAX + 1;
349 char *s;
350 char c;
352 for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
353 if (cnt > 0) {
354 *s++ = c;
355 cnt--;
358 if (si != s && cnt > 0) {
359 *s++ = '/';
360 cnt--;
362 for (; (c = *s2) != '\0' && cnt > 0; s2++) {
363 *s++ = c;
364 cnt--;
366 *s = '\0';
367 return (*s1? ++s1: NULL);
370 /* ARGSUSED */
372 posix_spawnp(
373 pid_t *pidp,
374 const char *file,
375 const posix_spawn_file_actions_t *file_actions,
376 const posix_spawnattr_t *attrp,
377 char *const *argv,
378 char *const *envp)
380 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL;
381 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL;
382 void *dirbuf = NULL;
383 const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : "";
384 int xpg4 = libc__xpg4;
385 int error = 0; /* this will be set by the child */
386 char path[PATH_MAX+4];
387 const char *cp;
388 pid_t pid;
389 char **newargs;
390 int argc;
391 int i;
393 if (attrp != NULL && sap == NULL)
394 return (EINVAL);
396 if (*file == '\0')
397 return (EACCES);
399 if (fap != NULL && fap->fa_need_dirbuf) {
401 * Preallocate the buffer for the call to getdents64() in
402 * spawn_closefrom() since we can't do it in the vfork() child.
404 if ((dirbuf = lmalloc(DIRBUF)) == NULL)
405 return (ENOMEM);
409 * We may need to invoke the shell with a slightly modified
410 * argv[] array. To do this we need to preallocate the array.
411 * We must call alloca() before calling vfork() because doing
412 * it after vfork() (in the child) would corrupt the parent.
414 for (argc = 0; argv[argc] != NULL; argc++)
415 continue;
416 newargs = alloca((argc + 2) * sizeof (char *));
418 switch (pid = vforkx(forkflags(sap))) {
419 case 0: /* child */
420 break;
421 case -1: /* parent, failure */
422 if (dirbuf)
423 lfree(dirbuf, DIRBUF);
424 return (errno);
425 default: /* parent, success */
427 * We don't get here until the child exec()s or exit()s
429 if (pidp != NULL && get_error(&error) == 0)
430 *pidp = pid;
431 if (dirbuf)
432 lfree(dirbuf, DIRBUF);
433 return (get_error(&error));
436 if (sap != NULL)
437 if (set_error(&error, perform_flag_actions(sap)) != 0)
438 _exit(_EVAPORATE);
440 if (fap != NULL)
441 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
442 _exit(_EVAPORATE);
444 if (pathstr == NULL) {
446 * XPG4: pathstr is equivalent to _CS_PATH, except that
447 * :/usr/sbin is appended when root, and pathstr must end
448 * with a colon when not root. Keep these paths in sync
449 * with _CS_PATH in confstr.c. Note that pathstr must end
450 * with a colon when not root so that when file doesn't
451 * contain '/', the last call to execat() will result in an
452 * attempt to execv file from the current directory.
454 if (geteuid() == 0 || getuid() == 0) {
455 if (!xpg4)
456 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin";
457 else
458 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
459 "/usr/bin:/opt/SUNWspro/bin:/usr/sbin";
460 } else {
461 if (!xpg4)
462 pathstr = "/usr/ccs/bin:/usr/bin:";
463 else
464 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:"
465 "/usr/bin:/opt/SUNWspro/bin:";
469 cp = pathstr;
470 do {
471 cp = execat(cp, file, path);
473 * 4025035 and 4038378
474 * if a filename begins with a "-" prepend "./" so that
475 * the shell can't interpret it as an option
477 if (*path == '-') {
478 char *s;
480 for (s = path; *s != '\0'; s++)
481 continue;
482 for (; s >= path; s--)
483 *(s + 2) = *s;
484 path[0] = '.';
485 path[1] = '/';
487 (void) set_error(&error, 0);
488 (void) execve(path, argv, envp);
489 if (set_error(&error, errno) == ENOEXEC) {
490 newargs[0] = "sh";
491 newargs[1] = path;
492 for (i = 1; i <= argc; i++)
493 newargs[i + 1] = argv[i];
494 (void) set_error(&error, 0);
495 (void) execve(_PATH_BSHELL, newargs, envp);
496 if (sap != NULL &&
497 (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP))
498 _exit(127);
499 (void) set_error(&error, errno);
500 _exit(_EVAPORATE);
502 } while (cp);
504 if (sap != NULL &&
505 (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
506 (void) set_error(&error, 0);
507 _exit(127);
509 _exit(_EVAPORATE);
510 return (0); /* not reached */
514 posix_spawn_file_actions_init(
515 posix_spawn_file_actions_t *file_actions)
517 file_actions->__file_attrp = NULL;
518 return (0);
522 posix_spawn_file_actions_destroy(
523 posix_spawn_file_actions_t *file_actions)
525 file_attr_t *froot = file_actions->__file_attrp;
526 file_attr_t *fap;
527 file_attr_t *next;
529 if ((fap = froot) != NULL) {
530 do {
531 next = fap->fa_next;
532 if (fap->fa_type == FA_OPEN)
533 lfree(fap->fa_path, fap->fa_pathsize);
534 lfree(fap, sizeof (*fap));
535 } while ((fap = next) != froot);
537 file_actions->__file_attrp = NULL;
538 return (0);
541 static void
542 add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
544 file_attr_t *froot = file_actions->__file_attrp;
546 if (froot == NULL) {
547 fap->fa_next = fap->fa_prev = fap;
548 file_actions->__file_attrp = froot = fap;
549 } else {
550 fap->fa_next = froot;
551 fap->fa_prev = froot->fa_prev;
552 froot->fa_prev->fa_next = fap;
553 froot->fa_prev = fap;
557 * Once set, __file_attrp no longer changes, so this assignment
558 * always goes into the first element in the list, as required.
560 if (fap->fa_type == FA_CLOSEFROM)
561 froot->fa_need_dirbuf = 1;
565 posix_spawn_file_actions_addopen(
566 posix_spawn_file_actions_t *file_actions,
567 int filedes,
568 const char *path,
569 int oflag,
570 mode_t mode)
572 file_attr_t *fap;
574 if (filedes < 0)
575 return (EBADF);
576 if ((fap = lmalloc(sizeof (*fap))) == NULL)
577 return (ENOMEM);
579 fap->fa_pathsize = strlen(path) + 1;
580 if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) {
581 lfree(fap, sizeof (*fap));
582 return (ENOMEM);
584 (void) strcpy(fap->fa_path, path);
586 fap->fa_type = FA_OPEN;
587 fap->fa_oflag = oflag;
588 fap->fa_mode = mode;
589 fap->fa_filedes = filedes;
590 add_file_attr(file_actions, fap);
592 return (0);
596 posix_spawn_file_actions_addclose(
597 posix_spawn_file_actions_t *file_actions,
598 int filedes)
600 file_attr_t *fap;
602 if (filedes < 0)
603 return (EBADF);
604 if ((fap = lmalloc(sizeof (*fap))) == NULL)
605 return (ENOMEM);
607 fap->fa_type = FA_CLOSE;
608 fap->fa_filedes = filedes;
609 add_file_attr(file_actions, fap);
611 return (0);
615 posix_spawn_file_actions_adddup2(
616 posix_spawn_file_actions_t *file_actions,
617 int filedes,
618 int newfiledes)
620 file_attr_t *fap;
622 if (filedes < 0 || newfiledes < 0)
623 return (EBADF);
624 if ((fap = lmalloc(sizeof (*fap))) == NULL)
625 return (ENOMEM);
627 fap->fa_type = FA_DUP2;
628 fap->fa_filedes = filedes;
629 fap->fa_newfiledes = newfiledes;
630 add_file_attr(file_actions, fap);
632 return (0);
636 posix_spawn_file_actions_addclosefrom_np(
637 posix_spawn_file_actions_t *file_actions,
638 int lowfiledes)
640 file_attr_t *fap;
642 if (lowfiledes < 0)
643 return (EBADF);
644 if ((fap = lmalloc(sizeof (*fap))) == NULL)
645 return (ENOMEM);
646 fap->fa_type = FA_CLOSEFROM;
647 fap->fa_filedes = lowfiledes;
648 add_file_attr(file_actions, fap);
650 return (0);
654 posix_spawnattr_init(
655 posix_spawnattr_t *attr)
657 if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
658 return (ENOMEM);
660 * Add default stuff here?
662 return (0);
666 posix_spawnattr_destroy(
667 posix_spawnattr_t *attr)
669 spawn_attr_t *sap = attr->__spawn_attrp;
671 if (sap == NULL)
672 return (EINVAL);
675 * deallocate stuff here?
677 lfree(sap, sizeof (*sap));
678 attr->__spawn_attrp = NULL;
679 return (0);
683 posix_spawnattr_setflags(
684 posix_spawnattr_t *attr,
685 short flags)
687 spawn_attr_t *sap = attr->__spawn_attrp;
689 if (sap == NULL ||
690 (flags & ~ALL_POSIX_SPAWN_FLAGS))
691 return (EINVAL);
693 sap->sa_psflags = flags;
694 return (0);
698 posix_spawnattr_getflags(
699 const posix_spawnattr_t *attr,
700 short *flags)
702 spawn_attr_t *sap = attr->__spawn_attrp;
704 if (sap == NULL)
705 return (EINVAL);
707 *flags = sap->sa_psflags;
708 return (0);
712 posix_spawnattr_setpgroup(
713 posix_spawnattr_t *attr,
714 pid_t pgroup)
716 spawn_attr_t *sap = attr->__spawn_attrp;
718 if (sap == NULL)
719 return (EINVAL);
721 sap->sa_pgroup = pgroup;
722 return (0);
726 posix_spawnattr_getpgroup(
727 const posix_spawnattr_t *attr,
728 pid_t *pgroup)
730 spawn_attr_t *sap = attr->__spawn_attrp;
732 if (sap == NULL)
733 return (EINVAL);
735 *pgroup = sap->sa_pgroup;
736 return (0);
740 posix_spawnattr_setschedparam(
741 posix_spawnattr_t *attr,
742 const struct sched_param *schedparam)
744 spawn_attr_t *sap = attr->__spawn_attrp;
746 if (sap == NULL)
747 return (EINVAL);
750 * Check validity?
752 sap->sa_priority = schedparam->sched_priority;
753 return (0);
757 posix_spawnattr_getschedparam(
758 const posix_spawnattr_t *attr,
759 struct sched_param *schedparam)
761 spawn_attr_t *sap = attr->__spawn_attrp;
763 if (sap == NULL)
764 return (EINVAL);
766 schedparam->sched_priority = sap->sa_priority;
767 return (0);
771 posix_spawnattr_setschedpolicy(
772 posix_spawnattr_t *attr,
773 int schedpolicy)
775 spawn_attr_t *sap = attr->__spawn_attrp;
777 if (sap == NULL || schedpolicy == SCHED_SYS)
778 return (EINVAL);
781 * Cache the policy information for later use
782 * by the vfork() child of posix_spawn().
784 if (get_info_by_policy(schedpolicy) == NULL)
785 return (errno);
787 sap->sa_schedpolicy = schedpolicy;
788 return (0);
792 posix_spawnattr_getschedpolicy(
793 const posix_spawnattr_t *attr,
794 int *schedpolicy)
796 spawn_attr_t *sap = attr->__spawn_attrp;
798 if (sap == NULL)
799 return (EINVAL);
801 *schedpolicy = sap->sa_schedpolicy;
802 return (0);
806 posix_spawnattr_setsigdefault(
807 posix_spawnattr_t *attr,
808 const sigset_t *sigdefault)
810 spawn_attr_t *sap = attr->__spawn_attrp;
812 if (sap == NULL)
813 return (EINVAL);
815 sap->sa_sigdefault = *sigdefault;
816 return (0);
820 posix_spawnattr_getsigdefault(
821 const posix_spawnattr_t *attr,
822 sigset_t *sigdefault)
824 spawn_attr_t *sap = attr->__spawn_attrp;
826 if (sap == NULL)
827 return (EINVAL);
829 *sigdefault = sap->sa_sigdefault;
830 return (0);
834 posix_spawnattr_setsigignore_np(
835 posix_spawnattr_t *attr,
836 const sigset_t *sigignore)
838 spawn_attr_t *sap = attr->__spawn_attrp;
840 if (sap == NULL)
841 return (EINVAL);
843 sap->sa_sigignore = *sigignore;
844 return (0);
848 posix_spawnattr_getsigignore_np(
849 const posix_spawnattr_t *attr,
850 sigset_t *sigignore)
852 spawn_attr_t *sap = attr->__spawn_attrp;
854 if (sap == NULL)
855 return (EINVAL);
857 *sigignore = sap->sa_sigignore;
858 return (0);
862 posix_spawnattr_setsigmask(
863 posix_spawnattr_t *attr,
864 const sigset_t *sigmask)
866 spawn_attr_t *sap = attr->__spawn_attrp;
868 if (sap == NULL)
869 return (EINVAL);
871 sap->sa_sigmask = *sigmask;
872 return (0);
876 posix_spawnattr_getsigmask(
877 const posix_spawnattr_t *attr,
878 sigset_t *sigmask)
880 spawn_attr_t *sap = attr->__spawn_attrp;
882 if (sap == NULL)
883 return (EINVAL);
885 *sigmask = sap->sa_sigmask;
886 return (0);
890 * Spawn a process to run "sh -c <cmd>". Return the child's pid (in
891 * *pidp), and a file descriptor (in *fdp) for reading or writing to the
892 * child process, depending on the 'write' argument.
893 * Return 0 on success; otherwise return an error code.
896 posix_spawn_pipe_np(pid_t *pidp, int *fdp,
897 const char *cmd, boolean_t write,
898 posix_spawn_file_actions_t *fact, posix_spawnattr_t *attr)
900 int p[2];
901 int myside, yourside, stdio;
902 const char *shpath = _PATH_BSHELL;
903 const char *argvec[4] = { "sh", "-c", cmd, NULL };
904 int error;
906 if (pipe(p) < 0)
907 return (errno);
909 if (access(shpath, X_OK)) /* XPG4 Requirement: */
910 shpath = ""; /* force child to fail immediately */
912 if (write) {
914 * Data is read from p[0] and written to p[1].
915 * 'stdio' is the fd in the child process that should be
916 * connected to the pipe.
918 myside = p[1];
919 yourside = p[0];
920 stdio = STDIN_FILENO;
921 } else {
922 myside = p[0];
923 yourside = p[1];
924 stdio = STDOUT_FILENO;
927 error = posix_spawn_file_actions_addclose(fact, myside);
928 if (yourside != stdio) {
929 if (error == 0) {
930 error = posix_spawn_file_actions_adddup2(fact,
931 yourside, stdio);
933 if (error == 0) {
934 error = posix_spawn_file_actions_addclose(fact,
935 yourside);
939 if (error)
940 return (error);
941 error = posix_spawn(pidp, shpath, fact, attr,
942 (char *const *)argvec, (char *const *)_environ);
943 (void) close(yourside);
944 if (error) {
945 (void) close(myside);
946 return (error);
949 *fdp = myside;
950 return (0);