1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (c) 2011 by Delphix. All rights reserved.
29 */
30
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>
40
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)
52
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;
62
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;
75
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
83
84 extern const char **_environ;
85
86 /*
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.
93 */
94 static int
spawn_closefrom(int lowfd,void * buf)95 spawn_closefrom(int lowfd, void *buf)
96 {
97 int procfd;
98 int fd;
99 int buflen;
100 dirent64_t *dp;
101 dirent64_t *dpend;
102
103 if (lowfd < 0)
104 lowfd = 0;
105
106 /*
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.
110 */
111 (void) __close(lowfd++);
112
113 if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) {
114 /*
115 * We could not open the /proc file descriptor directory.
116 * Just fail and be done with it.
117 */
118 return (-1);
119 }
120
121 for (;;) {
122 /*
123 * Collect a bunch of open file descriptors and close them.
124 * Repeat until the directory is exhausted.
125 */
126 dp = (dirent64_t *)buf;
127 if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) {
128 (void) __close(procfd);
129 break;
130 }
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);
140 }
141
142 return (0);
143 }
144
145 static int
perform_flag_actions(spawn_attr_t * sap)146 perform_flag_actions(spawn_attr_t *sap)
147 {
148 int sig;
149 struct sigaction action;
150
151 if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) {
152 (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask);
153 }
154
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);
161 }
162 }
163
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);
170 }
171 }
172
173 if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) {
174 if (setgid(getgid()) != 0 || setuid(getuid()) != 0)
175 return (errno);
176 }
177
178 if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) {
179 if (setpgid(0, sap->sa_pgroup) != 0)
180 return (errno);
181 }
182
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);
190 }
191
192 return (0);
193 }
194
195 static int
perform_file_actions(file_attr_t * fap,void * dirbuf)196 perform_file_actions(file_attr_t *fap, void *dirbuf)
197 {
198 file_attr_t *froot = fap;
199 int fd;
200
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);
211 }
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;
228 }
229 } while ((fap = fap->fa_next) != froot);
230
231 return (0);
232 }
233
234 static int
forkflags(spawn_attr_t * sap)235 forkflags(spawn_attr_t *sap)
236 {
237 int flags = 0;
238
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;
244 }
245
246 return (flags);
247 }
248
249 /*
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.
252 */
253
254 static int
set_error(int * errp,int err)255 set_error(int *errp, int err)
256 {
257 return (*errp = err);
258 }
259
260 static int
get_error(int * errp)261 get_error(int *errp)
262 {
263 return (*errp);
264 }
265
266 /*
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.
271 *
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.
275 */
276
277 int
posix_spawn(pid_t * pidp,const char * path,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])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[])
285 {
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;
291
292 if (attrp != NULL && sap == NULL)
293 return (EINVAL);
294
295 if (fap != NULL && fap->fa_need_dirbuf) {
296 /*
297 * Preallocate the buffer for the call to getdents64() in
298 * spawn_closefrom() since we can't do it in the vfork() child.
299 */
300 if ((dirbuf = lmalloc(DIRBUF)) == NULL)
301 return (ENOMEM);
302 }
303
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 */
312 /*
313 * We don't get here until the child exec()s or exit()s
314 */
315 if (pidp != NULL && get_error(&error) == 0)
316 *pidp = pid;
317 if (dirbuf)
318 lfree(dirbuf, DIRBUF);
319 return (get_error(&error));
320 }
321
322 if (sap != NULL)
323 if (set_error(&error, perform_flag_actions(sap)) != 0)
324 _exit(_EVAPORATE);
325
326 if (fap != NULL)
327 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
328 _exit(_EVAPORATE);
329
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 */
337 }
338
339 /*
340 * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c).
341 */
342
343 extern int libc__xpg4;
344
345 static const char *
execat(const char * s1,const char * s2,char * si)346 execat(const char *s1, const char *s2, char *si)
347 {
348 int cnt = PATH_MAX + 1;
349 char *s;
350 char c;
351
352 for (s = si; (c = *s1) != '\0' && c != ':'; s1++) {
353 if (cnt > 0) {
354 *s++ = c;
355 cnt--;
356 }
357 }
358 if (si != s && cnt > 0) {
359 *s++ = '/';
360 cnt--;
361 }
362 for (; (c = *s2) != '\0' && cnt > 0; s2++) {
363 *s++ = c;
364 cnt--;
365 }
366 *s = '\0';
367 return (*s1? ++s1: NULL);
368 }
369
370 /* ARGSUSED */
371 int
posix_spawnp(pid_t * pidp,const char * file,const posix_spawn_file_actions_t * file_actions,const posix_spawnattr_t * attrp,char * const argv[],char * const envp[])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[])
379 {
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;
392
393 if (attrp != NULL && sap == NULL)
394 return (EINVAL);
395
396 if (*file == '\0')
397 return (EACCES);
398
399 if (fap != NULL && fap->fa_need_dirbuf) {
400 /*
401 * Preallocate the buffer for the call to getdents64() in
402 * spawn_closefrom() since we can't do it in the vfork() child.
403 */
404 if ((dirbuf = lmalloc(DIRBUF)) == NULL)
405 return (ENOMEM);
406 }
407
408 /*
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.
413 */
414 for (argc = 0; argv[argc] != NULL; argc++)
415 continue;
416 newargs = alloca((argc + 2) * sizeof (char *));
417
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 */
426 /*
427 * We don't get here until the child exec()s or exit()s
428 */
429 if (pidp != NULL && get_error(&error) == 0)
430 *pidp = pid;
431 if (dirbuf)
432 lfree(dirbuf, DIRBUF);
433 return (get_error(&error));
434 }
435
436 if (sap != NULL)
437 if (set_error(&error, perform_flag_actions(sap)) != 0)
438 _exit(_EVAPORATE);
439
440 if (fap != NULL)
441 if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0)
442 _exit(_EVAPORATE);
443
444 if (pathstr == NULL) {
445 /*
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.
453 */
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:";
466 }
467 }
468
469 cp = pathstr;
470 do {
471 cp = execat(cp, file, path);
472 /*
473 * 4025035 and 4038378
474 * if a filename begins with a "-" prepend "./" so that
475 * the shell can't interpret it as an option
476 */
477 if (*path == '-') {
478 char *s;
479
480 for (s = path; *s != '\0'; s++)
481 continue;
482 for (; s >= path; s--)
483 *(s + 2) = *s;
484 path[0] = '.';
485 path[1] = '/';
486 }
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);
501 }
502 } while (cp);
503
504 if (sap != NULL &&
505 (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) {
506 (void) set_error(&error, 0);
507 _exit(127);
508 }
509 _exit(_EVAPORATE);
510 return (0); /* not reached */
511 }
512
513 int
posix_spawn_file_actions_init(posix_spawn_file_actions_t * file_actions)514 posix_spawn_file_actions_init(
515 posix_spawn_file_actions_t *file_actions)
516 {
517 file_actions->__file_attrp = NULL;
518 return (0);
519 }
520
521 int
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t * file_actions)522 posix_spawn_file_actions_destroy(
523 posix_spawn_file_actions_t *file_actions)
524 {
525 file_attr_t *froot = file_actions->__file_attrp;
526 file_attr_t *fap;
527 file_attr_t *next;
528
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);
536 }
537 file_actions->__file_attrp = NULL;
538 return (0);
539 }
540
541 static void
add_file_attr(posix_spawn_file_actions_t * file_actions,file_attr_t * fap)542 add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap)
543 {
544 file_attr_t *froot = file_actions->__file_attrp;
545
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;
554 }
555
556 /*
557 * Once set, __file_attrp no longer changes, so this assignment
558 * always goes into the first element in the list, as required.
559 */
560 if (fap->fa_type == FA_CLOSEFROM)
561 froot->fa_need_dirbuf = 1;
562 }
563
564 int
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * file_actions,int filedes,const char * path,int oflag,mode_t mode)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)
571 {
572 file_attr_t *fap;
573
574 if (filedes < 0)
575 return (EBADF);
576 if ((fap = lmalloc(sizeof (*fap))) == NULL)
577 return (ENOMEM);
578
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);
583 }
584 (void) strcpy(fap->fa_path, path);
585
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);
591
592 return (0);
593 }
594
595 int
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t * file_actions,int filedes)596 posix_spawn_file_actions_addclose(
597 posix_spawn_file_actions_t *file_actions,
598 int filedes)
599 {
600 file_attr_t *fap;
601
602 if (filedes < 0)
603 return (EBADF);
604 if ((fap = lmalloc(sizeof (*fap))) == NULL)
605 return (ENOMEM);
606
607 fap->fa_type = FA_CLOSE;
608 fap->fa_filedes = filedes;
609 add_file_attr(file_actions, fap);
610
611 return (0);
612 }
613
614 int
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t * file_actions,int filedes,int newfiledes)615 posix_spawn_file_actions_adddup2(
616 posix_spawn_file_actions_t *file_actions,
617 int filedes,
618 int newfiledes)
619 {
620 file_attr_t *fap;
621
622 if (filedes < 0 || newfiledes < 0)
623 return (EBADF);
624 if ((fap = lmalloc(sizeof (*fap))) == NULL)
625 return (ENOMEM);
626
627 fap->fa_type = FA_DUP2;
628 fap->fa_filedes = filedes;
629 fap->fa_newfiledes = newfiledes;
630 add_file_attr(file_actions, fap);
631
632 return (0);
633 }
634
635 int
posix_spawn_file_actions_addclosefrom_np(posix_spawn_file_actions_t * file_actions,int lowfiledes)636 posix_spawn_file_actions_addclosefrom_np(
637 posix_spawn_file_actions_t *file_actions,
638 int lowfiledes)
639 {
640 file_attr_t *fap;
641
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);
649
650 return (0);
651 }
652
653 int
posix_spawnattr_init(posix_spawnattr_t * attr)654 posix_spawnattr_init(
655 posix_spawnattr_t *attr)
656 {
657 if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL)
658 return (ENOMEM);
659 /*
660 * Add default stuff here?
661 */
662 return (0);
663 }
664
665 int
posix_spawnattr_destroy(posix_spawnattr_t * attr)666 posix_spawnattr_destroy(
667 posix_spawnattr_t *attr)
668 {
669 spawn_attr_t *sap = attr->__spawn_attrp;
670
671 if (sap == NULL)
672 return (EINVAL);
673
674 /*
675 * deallocate stuff here?
676 */
677 lfree(sap, sizeof (*sap));
678 attr->__spawn_attrp = NULL;
679 return (0);
680 }
681
682 int
posix_spawnattr_setflags(posix_spawnattr_t * attr,short flags)683 posix_spawnattr_setflags(
684 posix_spawnattr_t *attr,
685 short flags)
686 {
687 spawn_attr_t *sap = attr->__spawn_attrp;
688
689 if (sap == NULL ||
690 (flags & ~ALL_POSIX_SPAWN_FLAGS))
691 return (EINVAL);
692
693 sap->sa_psflags = flags;
694 return (0);
695 }
696
697 int
posix_spawnattr_getflags(const posix_spawnattr_t * attr,short * flags)698 posix_spawnattr_getflags(
699 const posix_spawnattr_t *attr,
700 short *flags)
701 {
702 spawn_attr_t *sap = attr->__spawn_attrp;
703
704 if (sap == NULL)
705 return (EINVAL);
706
707 *flags = sap->sa_psflags;
708 return (0);
709 }
710
711 int
posix_spawnattr_setpgroup(posix_spawnattr_t * attr,pid_t pgroup)712 posix_spawnattr_setpgroup(
713 posix_spawnattr_t *attr,
714 pid_t pgroup)
715 {
716 spawn_attr_t *sap = attr->__spawn_attrp;
717
718 if (sap == NULL)
719 return (EINVAL);
720
721 sap->sa_pgroup = pgroup;
722 return (0);
723 }
724
725 int
posix_spawnattr_getpgroup(const posix_spawnattr_t * attr,pid_t * pgroup)726 posix_spawnattr_getpgroup(
727 const posix_spawnattr_t *attr,
728 pid_t *pgroup)
729 {
730 spawn_attr_t *sap = attr->__spawn_attrp;
731
732 if (sap == NULL)
733 return (EINVAL);
734
735 *pgroup = sap->sa_pgroup;
736 return (0);
737 }
738
739 int
posix_spawnattr_setschedparam(posix_spawnattr_t * attr,const struct sched_param * schedparam)740 posix_spawnattr_setschedparam(
741 posix_spawnattr_t *attr,
742 const struct sched_param *schedparam)
743 {
744 spawn_attr_t *sap = attr->__spawn_attrp;
745
746 if (sap == NULL)
747 return (EINVAL);
748
749 /*
750 * Check validity?
751 */
752 sap->sa_priority = schedparam->sched_priority;
753 return (0);
754 }
755
756 int
posix_spawnattr_getschedparam(const posix_spawnattr_t * attr,struct sched_param * schedparam)757 posix_spawnattr_getschedparam(
758 const posix_spawnattr_t *attr,
759 struct sched_param *schedparam)
760 {
761 spawn_attr_t *sap = attr->__spawn_attrp;
762
763 if (sap == NULL)
764 return (EINVAL);
765
766 schedparam->sched_priority = sap->sa_priority;
767 return (0);
768 }
769
770 int
posix_spawnattr_setschedpolicy(posix_spawnattr_t * attr,int schedpolicy)771 posix_spawnattr_setschedpolicy(
772 posix_spawnattr_t *attr,
773 int schedpolicy)
774 {
775 spawn_attr_t *sap = attr->__spawn_attrp;
776
777 if (sap == NULL || schedpolicy == SCHED_SYS)
778 return (EINVAL);
779
780 /*
781 * Cache the policy information for later use
782 * by the vfork() child of posix_spawn().
783 */
784 if (get_info_by_policy(schedpolicy) == NULL)
785 return (errno);
786
787 sap->sa_schedpolicy = schedpolicy;
788 return (0);
789 }
790
791 int
posix_spawnattr_getschedpolicy(const posix_spawnattr_t * attr,int * schedpolicy)792 posix_spawnattr_getschedpolicy(
793 const posix_spawnattr_t *attr,
794 int *schedpolicy)
795 {
796 spawn_attr_t *sap = attr->__spawn_attrp;
797
798 if (sap == NULL)
799 return (EINVAL);
800
801 *schedpolicy = sap->sa_schedpolicy;
802 return (0);
803 }
804
805 int
posix_spawnattr_setsigdefault(posix_spawnattr_t * attr,const sigset_t * sigdefault)806 posix_spawnattr_setsigdefault(
807 posix_spawnattr_t *attr,
808 const sigset_t *sigdefault)
809 {
810 spawn_attr_t *sap = attr->__spawn_attrp;
811
812 if (sap == NULL)
813 return (EINVAL);
814
815 sap->sa_sigdefault = *sigdefault;
816 return (0);
817 }
818
819 int
posix_spawnattr_getsigdefault(const posix_spawnattr_t * attr,sigset_t * sigdefault)820 posix_spawnattr_getsigdefault(
821 const posix_spawnattr_t *attr,
822 sigset_t *sigdefault)
823 {
824 spawn_attr_t *sap = attr->__spawn_attrp;
825
826 if (sap == NULL)
827 return (EINVAL);
828
829 *sigdefault = sap->sa_sigdefault;
830 return (0);
831 }
832
833 int
posix_spawnattr_setsigignore_np(posix_spawnattr_t * attr,const sigset_t * sigignore)834 posix_spawnattr_setsigignore_np(
835 posix_spawnattr_t *attr,
836 const sigset_t *sigignore)
837 {
838 spawn_attr_t *sap = attr->__spawn_attrp;
839
840 if (sap == NULL)
841 return (EINVAL);
842
843 sap->sa_sigignore = *sigignore;
844 return (0);
845 }
846
847 int
posix_spawnattr_getsigignore_np(const posix_spawnattr_t * attr,sigset_t * sigignore)848 posix_spawnattr_getsigignore_np(
849 const posix_spawnattr_t *attr,
850 sigset_t *sigignore)
851 {
852 spawn_attr_t *sap = attr->__spawn_attrp;
853
854 if (sap == NULL)
855 return (EINVAL);
856
857 *sigignore = sap->sa_sigignore;
858 return (0);
859 }
860
861 int
posix_spawnattr_setsigmask(posix_spawnattr_t * attr,const sigset_t * sigmask)862 posix_spawnattr_setsigmask(
863 posix_spawnattr_t *attr,
864 const sigset_t *sigmask)
865 {
866 spawn_attr_t *sap = attr->__spawn_attrp;
867
868 if (sap == NULL)
869 return (EINVAL);
870
871 sap->sa_sigmask = *sigmask;
872 return (0);
873 }
874
875 int
posix_spawnattr_getsigmask(const posix_spawnattr_t * attr,sigset_t * sigmask)876 posix_spawnattr_getsigmask(
877 const posix_spawnattr_t *attr,
878 sigset_t *sigmask)
879 {
880 spawn_attr_t *sap = attr->__spawn_attrp;
881
882 if (sap == NULL)
883 return (EINVAL);
884
885 *sigmask = sap->sa_sigmask;
886 return (0);
887 }
888
889 /*
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.
894 */
895 int
posix_spawn_pipe_np(pid_t * pidp,int * fdp,const char * cmd,boolean_t write,posix_spawn_file_actions_t * fact,posix_spawnattr_t * attr)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)
899 {
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;
905
906 if (pipe(p) < 0)
907 return (errno);
908
909 if (access(shpath, X_OK)) /* XPG4 Requirement: */
910 shpath = ""; /* force child to fail immediately */
911
912 if (write) {
913 /*
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.
917 */
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;
925 }
926
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);
932 }
933 if (error == 0) {
934 error = posix_spawn_file_actions_addclose(fact,
935 yourside);
936 }
937 }
938
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);
947 }
948
949 *fdp = myside;
950 return (0);
951 }
952