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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lint.h" 30 #include "thr_uberdata.h" 31 #include <sys/procset.h> 32 #include <sys/rtpriocntl.h> 33 #include <sys/tspriocntl.h> 34 #include <sys/rt.h> 35 #include <sys/ts.h> 36 #include <alloca.h> 37 #include <spawn.h> 38 39 #define ALL_POSIX_SPAWN_FLAGS \ 40 (POSIX_SPAWN_RESETIDS | \ 41 POSIX_SPAWN_SETPGROUP | \ 42 POSIX_SPAWN_SETSIGDEF | \ 43 POSIX_SPAWN_SETSIGMASK | \ 44 POSIX_SPAWN_SETSCHEDPARAM | \ 45 POSIX_SPAWN_SETSCHEDULER) 46 47 typedef struct { 48 short sa_psflags; /* POSIX_SPAWN_* flags */ 49 pri_t sa_priority; 50 int sa_schedpolicy; 51 pid_t sa_pgroup; 52 sigset_t sa_sigdefault; 53 sigset_t sa_sigmask; 54 } spawn_attr_t; 55 56 typedef struct file_attr { 57 struct file_attr *fa_next; /* circular list of file actions */ 58 struct file_attr *fa_prev; 59 enum {FA_OPEN, FA_CLOSE, FA_DUP2} fa_type; 60 uint_t fa_pathsize; /* size of fa_path[] array */ 61 char *fa_path; /* copied pathname for open() */ 62 int fa_oflag; /* oflag for open() */ 63 mode_t fa_mode; /* mode for open() */ 64 int fa_filedes; /* file descriptor for open()/close() */ 65 int fa_newfiledes; /* new file descriptor for dup2() */ 66 } file_attr_t; 67 68 extern pid_t _vfork(void); 69 #pragma unknown_control_flow(_vfork) 70 extern void *_private_memset(void *, int, size_t); 71 extern int __lwp_sigmask(int, const sigset_t *, sigset_t *); 72 extern int __open(const char *, int, mode_t); 73 extern int __sigaction(int, const struct sigaction *, struct sigaction *); 74 extern int _private_close(int); 75 extern int _private_execve(const char *, char *const *, char *const *); 76 extern int _private_fcntl(int, int, intptr_t); 77 extern int _private_setgid(gid_t); 78 extern int _private_setpgid(pid_t, pid_t); 79 extern int _private_setuid(uid_t); 80 extern int _private_sigismember(sigset_t *, int); 81 extern gid_t _private_getgid(void); 82 extern uid_t _private_getuid(void); 83 extern uid_t _private_geteuid(void); 84 extern void _private_exit(int); 85 86 /* 87 * We call this function rather than priocntl() because we must not call 88 * any function that is exported from libc while in the child of vfork(). 89 * Also, we are not using PC_GETXPARMS or PC_SETXPARMS so we can use 90 * the simple call to __priocntlset() rather than the varargs version. 91 */ 92 static long 93 _private_priocntl(idtype_t idtype, id_t id, int cmd, caddr_t arg) 94 { 95 extern long _private__priocntlset(int, procset_t *, int, caddr_t, ...); 96 procset_t procset; 97 98 setprocset(&procset, POP_AND, idtype, id, P_ALL, 0); 99 return (_private__priocntlset(PC_VERSION, &procset, cmd, arg, 0)); 100 } 101 102 /* 103 * The following two functions are blatently stolen from 104 * sched_setscheduler() and sched_setparam() in librt. 105 * This would be a lot easier if librt were folded into libc. 106 */ 107 static int 108 setscheduler(int policy, pri_t prio) 109 { 110 pcparms_t pcparm; 111 tsinfo_t *tsi; 112 tsparms_t *tsp; 113 int scale; 114 115 switch (policy) { 116 case SCHED_FIFO: 117 case SCHED_RR: 118 if (prio < rt_class.pcc_primin || prio > rt_class.pcc_primax) { 119 errno = EINVAL; 120 return (-1); 121 } 122 pcparm.pc_cid = rt_class.pcc_info.pc_cid; 123 ((rtparms_t *)pcparm.pc_clparms)->rt_pri = prio; 124 ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs = 125 (policy == SCHED_RR ? RT_TQDEF : RT_TQINF); 126 break; 127 128 case SCHED_OTHER: 129 pcparm.pc_cid = ts_class.pcc_info.pc_cid; 130 tsi = (tsinfo_t *)ts_class.pcc_info.pc_clinfo; 131 scale = tsi->ts_maxupri; 132 tsp = (tsparms_t *)pcparm.pc_clparms; 133 tsp->ts_uprilim = tsp->ts_upri = -(scale * prio) / 20; 134 break; 135 136 default: 137 errno = EINVAL; 138 return (-1); 139 } 140 141 return (_private_priocntl(P_PID, P_MYID, 142 PC_SETPARMS, (caddr_t)&pcparm)); 143 } 144 145 static int 146 setparam(pcparms_t *pcparmp, pri_t prio) 147 { 148 tsparms_t *tsp; 149 tsinfo_t *tsi; 150 int scale; 151 152 if (pcparmp->pc_cid == rt_class.pcc_info.pc_cid) { 153 /* SCHED_FIFO or SCHED_RR policy */ 154 if (prio < rt_class.pcc_primin || prio > rt_class.pcc_primax) { 155 errno = EINVAL; 156 return (-1); 157 } 158 ((rtparms_t *)pcparmp->pc_clparms)->rt_tqnsecs = RT_NOCHANGE; 159 ((rtparms_t *)pcparmp->pc_clparms)->rt_pri = prio; 160 } else if (pcparmp->pc_cid == ts_class.pcc_info.pc_cid) { 161 /* SCHED_OTHER policy */ 162 tsi = (tsinfo_t *)ts_class.pcc_info.pc_clinfo; 163 scale = tsi->ts_maxupri; 164 tsp = (tsparms_t *)pcparmp->pc_clparms; 165 tsp->ts_uprilim = tsp->ts_upri = -(scale * prio) / 20; 166 } else { 167 errno = EINVAL; 168 return (-1); 169 } 170 171 return (_private_priocntl(P_PID, P_MYID, 172 PC_SETPARMS, (caddr_t)pcparmp)); 173 } 174 175 static void 176 perform_flag_actions(spawn_attr_t *sap) 177 { 178 int sig; 179 180 if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) { 181 (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask, NULL); 182 } 183 184 if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) { 185 struct sigaction sigdfl; 186 187 (void) _private_memset(&sigdfl, 0, sizeof (sigdfl)); 188 for (sig = 1; sig < NSIG; sig++) { 189 if (_private_sigismember(&sap->sa_sigdefault, sig)) 190 (void) __sigaction(sig, &sigdfl, NULL); 191 } 192 } 193 194 if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) { 195 if (_private_setgid(_private_getgid()) != 0 || 196 _private_setuid(_private_getuid()) != 0) 197 _private_exit(127); 198 } 199 200 if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) { 201 if (_private_setpgid(0, sap->sa_pgroup) != 0) 202 _private_exit(127); 203 } 204 205 if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) { 206 if (setscheduler(sap->sa_schedpolicy, sap->sa_priority) != 0) 207 _private_exit(127); 208 } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) { 209 /* 210 * Get the process's current scheduling parameters, 211 * then modify to set the new priority. 212 */ 213 pcparms_t pcparm; 214 215 pcparm.pc_cid = PC_CLNULL; 216 if (_private_priocntl(P_PID, P_MYID, 217 PC_GETPARMS, (caddr_t)&pcparm) == -1) 218 _private_exit(127); 219 if (setparam(&pcparm, sap->sa_priority) != 0) 220 _private_exit(127); 221 } 222 } 223 224 static void 225 perform_file_actions(file_attr_t *fap) 226 { 227 file_attr_t *froot = fap; 228 int fd; 229 230 do { 231 switch (fap->fa_type) { 232 case FA_OPEN: 233 fd = __open(fap->fa_path, fap->fa_oflag, fap->fa_mode); 234 if (fd < 0) 235 _private_exit(127); 236 if (fd != fap->fa_filedes) { 237 if (_private_fcntl(fd, F_DUP2FD, 238 fap->fa_filedes) < 0) 239 _private_exit(127); 240 (void) _private_close(fd); 241 } 242 break; 243 case FA_CLOSE: 244 if (_private_close(fap->fa_filedes) == -1) 245 _private_exit(127); 246 break; 247 case FA_DUP2: 248 fd = _private_fcntl(fap->fa_filedes, F_DUP2FD, 249 fap->fa_newfiledes); 250 if (fd < 0) 251 _private_exit(127); 252 break; 253 } 254 } while ((fap = fap->fa_next) != froot); 255 } 256 257 /* 258 * For MT safety, do not invoke the dynamic linker after calling vfork(). 259 * If some other thread was in the dynamic linker when this thread's parent 260 * called vfork() then the dynamic linker's lock would still be held here 261 * (with a defunct owner) and we would deadlock ourself if we invoked it. 262 * 263 * Therefore, all of the functions we call here after returning from 264 * _vfork() in the child are not and must never be exported from libc 265 * as global symbols. To do so would risk invoking the dynamic linker. 266 */ 267 268 #pragma weak posix_spawn = _posix_spawn 269 int 270 _posix_spawn( 271 pid_t *pidp, 272 const char *path, 273 const posix_spawn_file_actions_t *file_actions, 274 const posix_spawnattr_t *attrp, 275 char *const argv[], 276 char *const envp[]) 277 { 278 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 279 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 280 pid_t pid; 281 282 if (attrp != NULL && sap == NULL) 283 return (EINVAL); 284 285 switch (pid = _vfork()) { 286 case 0: /* child */ 287 break; 288 case -1: /* parent, failure */ 289 return (errno); 290 default: /* parent, success */ 291 if (pidp != NULL) 292 *pidp = pid; 293 return (0); 294 } 295 296 if (sap != NULL) 297 perform_flag_actions(sap); 298 299 if (fap != NULL) 300 perform_file_actions(fap); 301 302 (void) _private_execve(path, argv, envp); 303 _private_exit(127); 304 return (0); /* not reached */ 305 } 306 307 /* 308 * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c). 309 */ 310 311 extern int __xpg4; /* defined in xpg4.c; 0 if not xpg4-compiled program */ 312 313 static const char * 314 execat(const char *s1, const char *s2, char *si) 315 { 316 int cnt = PATH_MAX + 1; 317 char *s; 318 char c; 319 320 for (s = si; (c = *s1) != '\0' && c != ':'; s1++) { 321 if (cnt > 0) { 322 *s++ = c; 323 cnt--; 324 } 325 } 326 if (si != s && cnt > 0) { 327 *s++ = '/'; 328 cnt--; 329 } 330 for (; (c = *s2) != '\0' && cnt > 0; s2++) { 331 *s++ = c; 332 cnt--; 333 } 334 *s = '\0'; 335 return (*s1? ++s1: NULL); 336 } 337 338 #pragma weak posix_spawnp = _posix_spawnp 339 /* ARGSUSED */ 340 int 341 _posix_spawnp( 342 pid_t *pidp, 343 const char *file, 344 const posix_spawn_file_actions_t *file_actions, 345 const posix_spawnattr_t *attrp, 346 char *const argv[], 347 char *const envp[]) 348 { 349 spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 350 file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 351 const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : ""; 352 int xpg4 = __xpg4; 353 char path[PATH_MAX+4]; 354 const char *cp; 355 pid_t pid; 356 char **newargs; 357 int argc; 358 int i; 359 static const char *sun_path = "/bin/sh"; 360 static const char *xpg4_path = "/usr/xpg4/bin/sh"; 361 static const char *shell = "sh"; 362 363 if (attrp != NULL && sap == NULL) 364 return (EINVAL); 365 366 /* 367 * We may need to invoke the shell with a slightly modified 368 * argv[] array. To do this we need to preallocate the array. 369 * We must call alloca() before calling vfork() because doing 370 * it after vfork() (in the child) would corrupt the parent. 371 */ 372 for (argc = 0; argv[argc] != NULL; argc++) 373 continue; 374 newargs = alloca((argc + 2) * sizeof (char *)); 375 376 switch (pid = _vfork()) { 377 case 0: /* child */ 378 break; 379 case -1: /* parent, failure */ 380 return (errno); 381 default: /* parent, success */ 382 if (pidp != NULL) 383 *pidp = pid; 384 return (0); 385 } 386 387 if (*file == '\0') 388 _private_exit(127); 389 390 if (sap != NULL) 391 perform_flag_actions(sap); 392 393 if (fap != NULL) 394 perform_file_actions(fap); 395 396 if (pathstr == NULL) { 397 /* 398 * XPG4: pathstr is equivalent to _CS_PATH, except that 399 * :/usr/sbin is appended when root, and pathstr must end 400 * with a colon when not root. Keep these paths in sync 401 * with _CS_PATH in confstr.c. Note that pathstr must end 402 * with a colon when not root so that when file doesn't 403 * contain '/', the last call to execat() will result in an 404 * attempt to execv file from the current directory. 405 */ 406 if (_private_geteuid() == 0 || _private_getuid() == 0) { 407 if (!xpg4) 408 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 409 else 410 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 411 "/usr/bin:/opt/SUNWspro/bin:/usr/sbin"; 412 } else { 413 if (!xpg4) 414 pathstr = "/usr/ccs/bin:/usr/bin:"; 415 else 416 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 417 "/usr/bin:/opt/SUNWspro/bin:"; 418 } 419 } 420 421 cp = pathstr; 422 do { 423 cp = execat(cp, file, path); 424 /* 425 * 4025035 and 4038378 426 * if a filename begins with a "-" prepend "./" so that 427 * the shell can't interpret it as an option 428 */ 429 if (*path == '-') { 430 char *s; 431 432 for (s = path; *s != '\0'; s++) 433 continue; 434 for (; s >= path; s--) 435 *(s + 2) = *s; 436 path[0] = '.'; 437 path[1] = '/'; 438 } 439 (void) _private_execve(path, argv, envp); 440 if (errno == ENOEXEC) { 441 newargs[0] = (char *)shell; 442 newargs[1] = path; 443 for (i = 1; i <= argc; i++) 444 newargs[i + 1] = argv[i]; 445 (void) _private_execve(xpg4? xpg4_path : sun_path, 446 newargs, envp); 447 _private_exit(127); 448 } 449 } while (cp); 450 _private_exit(127); 451 return (0); /* not reached */ 452 } 453 454 #pragma weak posix_spawn_file_actions_init = \ 455 _posix_spawn_file_actions_init 456 int 457 _posix_spawn_file_actions_init( 458 posix_spawn_file_actions_t *file_actions) 459 { 460 file_actions->__file_attrp = NULL; 461 return (0); 462 } 463 464 #pragma weak posix_spawn_file_actions_destroy = \ 465 _posix_spawn_file_actions_destroy 466 int 467 _posix_spawn_file_actions_destroy( 468 posix_spawn_file_actions_t *file_actions) 469 { 470 file_attr_t *froot = file_actions->__file_attrp; 471 file_attr_t *fap; 472 file_attr_t *next; 473 474 if ((fap = froot) != NULL) { 475 do { 476 next = fap->fa_next; 477 if (fap-> fa_type == FA_OPEN) 478 lfree(fap->fa_path, fap->fa_pathsize); 479 lfree(fap, sizeof (*fap)); 480 } while ((fap = next) != froot); 481 } 482 file_actions->__file_attrp = NULL; 483 return (0); 484 } 485 486 static void 487 add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap) 488 { 489 file_attr_t *froot = file_actions->__file_attrp; 490 491 if (froot == NULL) { 492 fap->fa_next = fap->fa_prev = fap; 493 file_actions->__file_attrp = fap; 494 } else { 495 fap->fa_next = froot; 496 fap->fa_prev = froot->fa_prev; 497 froot->fa_prev->fa_next = fap; 498 froot->fa_prev = fap; 499 } 500 } 501 502 #pragma weak posix_spawn_file_actions_addopen = \ 503 _posix_spawn_file_actions_addopen 504 int 505 _posix_spawn_file_actions_addopen( 506 posix_spawn_file_actions_t *file_actions, 507 int filedes, 508 const char *path, 509 int oflag, 510 mode_t mode) 511 { 512 file_attr_t *fap; 513 514 if (filedes < 0) 515 return (EBADF); 516 if ((fap = lmalloc(sizeof (*fap))) == NULL) 517 return (ENOMEM); 518 519 fap->fa_pathsize = strlen(path) + 1; 520 if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) { 521 lfree(fap, sizeof (*fap)); 522 return (ENOMEM); 523 } 524 (void) strcpy(fap->fa_path, path); 525 526 fap->fa_type = FA_OPEN; 527 fap->fa_oflag = oflag; 528 fap->fa_mode = mode; 529 fap->fa_filedes = filedes; 530 add_file_attr(file_actions, fap); 531 532 return (0); 533 } 534 535 #pragma weak posix_spawn_file_actions_addclose = \ 536 _posix_spawn_file_actions_addclose 537 int 538 _posix_spawn_file_actions_addclose( 539 posix_spawn_file_actions_t *file_actions, 540 int filedes) 541 { 542 file_attr_t *fap; 543 544 if (filedes < 0) 545 return (EBADF); 546 if ((fap = lmalloc(sizeof (*fap))) == NULL) 547 return (ENOMEM); 548 549 fap->fa_type = FA_CLOSE; 550 fap->fa_filedes = filedes; 551 add_file_attr(file_actions, fap); 552 553 return (0); 554 } 555 556 #pragma weak posix_spawn_file_actions_adddup2 = \ 557 _posix_spawn_file_actions_adddup2 558 int 559 _posix_spawn_file_actions_adddup2( 560 posix_spawn_file_actions_t *file_actions, 561 int filedes, 562 int newfiledes) 563 { 564 file_attr_t *fap; 565 566 if (filedes < 0 || newfiledes < 0) 567 return (EBADF); 568 if ((fap = lmalloc(sizeof (*fap))) == NULL) 569 return (ENOMEM); 570 571 fap->fa_type = FA_DUP2; 572 fap->fa_filedes = filedes; 573 fap->fa_newfiledes = newfiledes; 574 add_file_attr(file_actions, fap); 575 576 return (0); 577 } 578 579 #pragma weak posix_spawnattr_init = \ 580 _posix_spawnattr_init 581 int 582 _posix_spawnattr_init( 583 posix_spawnattr_t *attr) 584 { 585 spawn_attr_t *sap; 586 587 if ((sap = lmalloc(sizeof (*sap))) == NULL) 588 return (ENOMEM); 589 590 /* 591 * Add default stuff here? 592 */ 593 attr->__spawn_attrp = sap; 594 return (0); 595 } 596 597 #pragma weak posix_spawnattr_destroy = \ 598 _posix_spawnattr_destroy 599 int 600 _posix_spawnattr_destroy( 601 posix_spawnattr_t *attr) 602 { 603 spawn_attr_t *sap = attr->__spawn_attrp; 604 605 if (sap == NULL) 606 return (EINVAL); 607 608 /* 609 * deallocate stuff here? 610 */ 611 lfree(sap, sizeof (*sap)); 612 attr->__spawn_attrp = NULL; 613 return (0); 614 } 615 616 #pragma weak posix_spawnattr_setflags = \ 617 _posix_spawnattr_setflags 618 int 619 _posix_spawnattr_setflags( 620 posix_spawnattr_t *attr, 621 short flags) 622 { 623 spawn_attr_t *sap = attr->__spawn_attrp; 624 625 if (sap == NULL || 626 (flags & ~ALL_POSIX_SPAWN_FLAGS)) 627 return (EINVAL); 628 629 if (flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) { 630 /* 631 * Populate ts_class and rt_class. 632 * We will need them in the child of vfork(). 633 */ 634 (void) _map_rtpri_to_gp(0); 635 } 636 637 sap->sa_psflags = flags; 638 return (0); 639 } 640 641 #pragma weak posix_spawnattr_getflags = \ 642 _posix_spawnattr_getflags 643 int 644 _posix_spawnattr_getflags( 645 const posix_spawnattr_t *attr, 646 short *flags) 647 { 648 spawn_attr_t *sap = attr->__spawn_attrp; 649 650 if (sap == NULL) 651 return (EINVAL); 652 653 *flags = sap->sa_psflags; 654 return (0); 655 } 656 657 #pragma weak posix_spawnattr_setpgroup = \ 658 _posix_spawnattr_setpgroup 659 int 660 _posix_spawnattr_setpgroup( 661 posix_spawnattr_t *attr, 662 pid_t pgroup) 663 { 664 spawn_attr_t *sap = attr->__spawn_attrp; 665 666 if (sap == NULL) 667 return (EINVAL); 668 669 sap->sa_pgroup = pgroup; 670 return (0); 671 } 672 673 #pragma weak posix_spawnattr_getpgroup = \ 674 _posix_spawnattr_getpgroup 675 int 676 _posix_spawnattr_getpgroup( 677 const posix_spawnattr_t *attr, 678 pid_t *pgroup) 679 { 680 spawn_attr_t *sap = attr->__spawn_attrp; 681 682 if (sap == NULL) 683 return (EINVAL); 684 685 *pgroup = sap->sa_pgroup; 686 return (0); 687 } 688 689 #pragma weak posix_spawnattr_setschedparam = \ 690 _posix_spawnattr_setschedparam 691 int 692 _posix_spawnattr_setschedparam( 693 posix_spawnattr_t *attr, 694 const struct sched_param *schedparam) 695 { 696 spawn_attr_t *sap = attr->__spawn_attrp; 697 698 if (sap == NULL) 699 return (EINVAL); 700 701 /* 702 * Check validity? 703 */ 704 sap->sa_priority = schedparam->sched_priority; 705 return (0); 706 } 707 708 #pragma weak posix_spawnattr_getschedparam = \ 709 _posix_spawnattr_getschedparam 710 int 711 _posix_spawnattr_getschedparam( 712 const posix_spawnattr_t *attr, 713 struct sched_param *schedparam) 714 { 715 spawn_attr_t *sap = attr->__spawn_attrp; 716 717 if (sap == NULL) 718 return (EINVAL); 719 720 schedparam->sched_priority = sap->sa_priority; 721 return (0); 722 } 723 724 #pragma weak posix_spawnattr_setschedpolicy = \ 725 _posix_spawnattr_setschedpolicy 726 int 727 _posix_spawnattr_setschedpolicy( 728 posix_spawnattr_t *attr, 729 int schedpolicy) 730 { 731 spawn_attr_t *sap = attr->__spawn_attrp; 732 733 if (sap == NULL) 734 return (EINVAL); 735 736 switch (schedpolicy) { 737 case SCHED_OTHER: 738 case SCHED_FIFO: 739 case SCHED_RR: 740 break; 741 default: 742 return (EINVAL); 743 } 744 745 sap->sa_schedpolicy = schedpolicy; 746 return (0); 747 } 748 749 #pragma weak posix_spawnattr_getschedpolicy = \ 750 _posix_spawnattr_getschedpolicy 751 int 752 _posix_spawnattr_getschedpolicy( 753 const posix_spawnattr_t *attr, 754 int *schedpolicy) 755 { 756 spawn_attr_t *sap = attr->__spawn_attrp; 757 758 if (sap == NULL) 759 return (EINVAL); 760 761 *schedpolicy = sap->sa_schedpolicy; 762 return (0); 763 } 764 765 #pragma weak posix_spawnattr_setsigdefault = \ 766 _posix_spawnattr_setsigdefault 767 int 768 _posix_spawnattr_setsigdefault( 769 posix_spawnattr_t *attr, 770 const sigset_t *sigdefault) 771 { 772 spawn_attr_t *sap = attr->__spawn_attrp; 773 774 if (sap == NULL) 775 return (EINVAL); 776 777 sap->sa_sigdefault = *sigdefault; 778 return (0); 779 } 780 781 #pragma weak posix_spawnattr_getsigdefault = \ 782 _posix_spawnattr_getsigdefault 783 int 784 _posix_spawnattr_getsigdefault( 785 const posix_spawnattr_t *attr, 786 sigset_t *sigdefault) 787 { 788 spawn_attr_t *sap = attr->__spawn_attrp; 789 790 if (sap == NULL) 791 return (EINVAL); 792 793 *sigdefault = sap->sa_sigdefault; 794 return (0); 795 } 796 797 #pragma weak posix_spawnattr_setsigmask = \ 798 _posix_spawnattr_setsigmask 799 int 800 _posix_spawnattr_setsigmask( 801 posix_spawnattr_t *attr, 802 const sigset_t *sigmask) 803 { 804 spawn_attr_t *sap = attr->__spawn_attrp; 805 806 if (sap == NULL) 807 return (EINVAL); 808 809 sap->sa_sigmask = *sigmask; 810 return (0); 811 } 812 813 #pragma weak posix_spawnattr_getsigmask = \ 814 _posix_spawnattr_getsigmask 815 int 816 _posix_spawnattr_getsigmask( 817 const posix_spawnattr_t *attr, 818 sigset_t *sigmask) 819 { 820 spawn_attr_t *sap = attr->__spawn_attrp; 821 822 if (sap == NULL) 823 return (EINVAL); 824 825 *sigmask = sap->sa_sigmask; 826 return (0); 827 } 828