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