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