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