1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2248 raf * Common Development and Distribution License (the "License"). 6 2248 raf * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 2248 raf 22 0 stevel /* 23 8877 Roger * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #include "lint.h" 28 0 stevel #include "thr_uberdata.h" 29 3086 raf #include <sys/libc_kernel.h> 30 0 stevel #include <sys/procset.h> 31 3235 raf #include <sys/fork.h> 32 8877 Roger #include <dirent.h> 33 0 stevel #include <alloca.h> 34 0 stevel #include <spawn.h> 35 0 stevel 36 0 stevel #define ALL_POSIX_SPAWN_FLAGS \ 37 0 stevel (POSIX_SPAWN_RESETIDS | \ 38 0 stevel POSIX_SPAWN_SETPGROUP | \ 39 0 stevel POSIX_SPAWN_SETSIGDEF | \ 40 0 stevel POSIX_SPAWN_SETSIGMASK | \ 41 0 stevel POSIX_SPAWN_SETSCHEDPARAM | \ 42 3235 raf POSIX_SPAWN_SETSCHEDULER | \ 43 7930 Roger POSIX_SPAWN_SETSIGIGN_NP | \ 44 3235 raf POSIX_SPAWN_NOSIGCHLD_NP | \ 45 7635 Roger POSIX_SPAWN_WAITPID_NP | \ 46 7635 Roger POSIX_SPAWN_NOEXECERR_NP) 47 0 stevel 48 0 stevel typedef struct { 49 6247 raf int sa_psflags; /* POSIX_SPAWN_* flags */ 50 6247 raf int sa_priority; 51 0 stevel int sa_schedpolicy; 52 0 stevel pid_t sa_pgroup; 53 0 stevel sigset_t sa_sigdefault; 54 7930 Roger sigset_t sa_sigignore; 55 0 stevel sigset_t sa_sigmask; 56 0 stevel } spawn_attr_t; 57 0 stevel 58 0 stevel typedef struct file_attr { 59 0 stevel struct file_attr *fa_next; /* circular list of file actions */ 60 0 stevel struct file_attr *fa_prev; 61 8877 Roger enum {FA_OPEN, FA_CLOSE, FA_DUP2, FA_CLOSEFROM} fa_type; 62 8877 Roger int fa_need_dirbuf; /* only consulted in the head action */ 63 8877 Roger char *fa_path; /* copied pathname for open() */ 64 0 stevel uint_t fa_pathsize; /* size of fa_path[] array */ 65 0 stevel int fa_oflag; /* oflag for open() */ 66 0 stevel mode_t fa_mode; /* mode for open() */ 67 0 stevel int fa_filedes; /* file descriptor for open()/close() */ 68 0 stevel int fa_newfiledes; /* new file descriptor for dup2() */ 69 0 stevel } file_attr_t; 70 2248 raf 71 0 stevel extern int __lwp_sigmask(int, const sigset_t *, sigset_t *); 72 0 stevel extern int __sigaction(int, const struct sigaction *, struct sigaction *); 73 8877 Roger 74 8877 Roger #if defined(_LP64) 75 8877 Roger #define __open64 __open 76 8877 Roger #define getdents64 getdents 77 8877 Roger #define dirent64_t dirent_t 78 8877 Roger #else 79 8877 Roger extern int __open64(const char *, int, ...); 80 8877 Roger extern int getdents64(int, dirent64_t *, size_t); 81 8877 Roger #endif 82 8877 Roger 83 8877 Roger /* 84 8877 Roger * Support function: 85 8877 Roger * Close all open file descriptors greater than or equal to lowfd. 86 8877 Roger * This is executed in the child of vfork(), so we must not call 87 8877 Roger * opendir() / readdir() because that would alter the parent's 88 8877 Roger * address space. We use the low-level getdents64() system call. 89 8877 Roger * Return non-zero on error. 90 8877 Roger */ 91 8877 Roger static int 92 8877 Roger spawn_closefrom(int lowfd, void *buf) 93 8877 Roger { 94 8877 Roger int procfd; 95 8877 Roger int fd; 96 8877 Roger int buflen; 97 8877 Roger dirent64_t *dp; 98 8877 Roger dirent64_t *dpend; 99 8877 Roger 100 8877 Roger if (lowfd < 0) 101 8877 Roger lowfd = 0; 102 8877 Roger 103 8877 Roger /* 104 8877 Roger * Close lowfd right away as a hedge against failing 105 8877 Roger * to open the /proc file descriptor directory due 106 8877 Roger * all file descriptors being currently used up. 107 8877 Roger */ 108 8877 Roger (void) __close(lowfd++); 109 8877 Roger 110 8877 Roger if ((procfd = __open64("/proc/self/fd", O_RDONLY, 0)) < 0) { 111 8877 Roger /* 112 8877 Roger * We could not open the /proc file descriptor directory. 113 8877 Roger * Just fail and be done with it. 114 8877 Roger */ 115 8877 Roger return (-1); 116 8877 Roger } 117 8877 Roger 118 8877 Roger for (;;) { 119 8877 Roger /* 120 8877 Roger * Collect a bunch of open file descriptors and close them. 121 8877 Roger * Repeat until the directory is exhausted. 122 8877 Roger */ 123 8877 Roger dp = (dirent64_t *)buf; 124 8877 Roger if ((buflen = getdents64(procfd, dp, DIRBUF)) <= 0) { 125 8877 Roger (void) __close(procfd); 126 8877 Roger break; 127 8877 Roger } 128 8877 Roger dpend = (dirent64_t *)((uintptr_t)buf + buflen); 129 8877 Roger do { 130 8877 Roger /* skip '.', '..' and procfd */ 131 8877 Roger if (dp->d_name[0] != '.' && 132 8877 Roger (fd = atoi(dp->d_name)) != procfd && 133 8877 Roger fd >= lowfd) 134 8877 Roger (void) __close(fd); 135 8877 Roger dp = (dirent64_t *)((uintptr_t)dp + dp->d_reclen); 136 8877 Roger } while (dp < dpend); 137 8877 Roger } 138 8877 Roger 139 8877 Roger return (0); 140 8877 Roger } 141 0 stevel 142 3086 raf static int 143 0 stevel perform_flag_actions(spawn_attr_t *sap) 144 0 stevel { 145 0 stevel int sig; 146 7930 Roger struct sigaction action; 147 0 stevel 148 0 stevel if (sap->sa_psflags & POSIX_SPAWN_SETSIGMASK) { 149 0 stevel (void) __lwp_sigmask(SIG_SETMASK, &sap->sa_sigmask, NULL); 150 0 stevel } 151 0 stevel 152 7930 Roger if (sap->sa_psflags & POSIX_SPAWN_SETSIGIGN_NP) { 153 7930 Roger (void) memset(&action, 0, sizeof (action)); 154 7930 Roger action.sa_handler = SIG_IGN; 155 7930 Roger for (sig = 1; sig < NSIG; sig++) { 156 7930 Roger if (sigismember(&sap->sa_sigignore, sig)) 157 7930 Roger (void) __sigaction(sig, &action, NULL); 158 7930 Roger } 159 7930 Roger } 160 7930 Roger 161 0 stevel if (sap->sa_psflags & POSIX_SPAWN_SETSIGDEF) { 162 7930 Roger (void) memset(&action, 0, sizeof (action)); 163 7930 Roger action.sa_handler = SIG_DFL; 164 0 stevel for (sig = 1; sig < NSIG; sig++) { 165 6515 raf if (sigismember(&sap->sa_sigdefault, sig)) 166 7930 Roger (void) __sigaction(sig, &action, NULL); 167 0 stevel } 168 0 stevel } 169 0 stevel 170 0 stevel if (sap->sa_psflags & POSIX_SPAWN_RESETIDS) { 171 6515 raf if (setgid(getgid()) != 0 || setuid(getuid()) != 0) 172 3086 raf return (errno); 173 0 stevel } 174 0 stevel 175 0 stevel if (sap->sa_psflags & POSIX_SPAWN_SETPGROUP) { 176 6515 raf if (setpgid(0, sap->sa_pgroup) != 0) 177 3086 raf return (errno); 178 0 stevel } 179 0 stevel 180 0 stevel if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDULER) { 181 6247 raf if (setparam(P_LWPID, P_MYID, 182 6247 raf sap->sa_schedpolicy, sap->sa_priority) == -1) 183 3086 raf return (errno); 184 0 stevel } else if (sap->sa_psflags & POSIX_SPAWN_SETSCHEDPARAM) { 185 6247 raf if (setprio(P_LWPID, P_MYID, sap->sa_priority, NULL) == -1) 186 3086 raf return (errno); 187 0 stevel } 188 3086 raf 189 3086 raf return (0); 190 0 stevel } 191 0 stevel 192 3086 raf static int 193 8877 Roger perform_file_actions(file_attr_t *fap, void *dirbuf) 194 0 stevel { 195 0 stevel file_attr_t *froot = fap; 196 0 stevel int fd; 197 0 stevel 198 0 stevel do { 199 0 stevel switch (fap->fa_type) { 200 0 stevel case FA_OPEN: 201 6515 raf fd = __open(fap->fa_path, 202 5891 raf fap->fa_oflag, fap->fa_mode); 203 0 stevel if (fd < 0) 204 3086 raf return (errno); 205 0 stevel if (fd != fap->fa_filedes) { 206 6515 raf if (__fcntl(fd, F_DUP2FD, fap->fa_filedes) < 0) 207 3086 raf return (errno); 208 6515 raf (void) __close(fd); 209 0 stevel } 210 0 stevel break; 211 0 stevel case FA_CLOSE: 212 8877 Roger if (__close(fap->fa_filedes) == -1 && 213 8877 Roger errno != EBADF) /* already closed, no error */ 214 3086 raf return (errno); 215 0 stevel break; 216 0 stevel case FA_DUP2: 217 6515 raf fd = __fcntl(fap->fa_filedes, F_DUP2FD, 218 5891 raf fap->fa_newfiledes); 219 0 stevel if (fd < 0) 220 8877 Roger return (errno); 221 8877 Roger break; 222 8877 Roger case FA_CLOSEFROM: 223 8877 Roger if (spawn_closefrom(fap->fa_filedes, dirbuf)) 224 3086 raf return (errno); 225 0 stevel break; 226 0 stevel } 227 0 stevel } while ((fap = fap->fa_next) != froot); 228 3086 raf 229 3086 raf return (0); 230 3086 raf } 231 3086 raf 232 3235 raf static int 233 3235 raf forkflags(spawn_attr_t *sap) 234 3235 raf { 235 3235 raf int flags = 0; 236 3235 raf 237 3235 raf if (sap != NULL) { 238 3235 raf if (sap->sa_psflags & POSIX_SPAWN_NOSIGCHLD_NP) 239 3235 raf flags |= FORK_NOSIGCHLD; 240 3235 raf if (sap->sa_psflags & POSIX_SPAWN_WAITPID_NP) 241 3235 raf flags |= FORK_WAITPID; 242 3235 raf } 243 3235 raf 244 3235 raf return (flags); 245 3235 raf } 246 3235 raf 247 3086 raf /* 248 3086 raf * set_error() / get_error() are used to guarantee that the local variable 249 3086 raf * 'error' is set correctly in memory on return from vfork() in the parent. 250 3086 raf */ 251 3086 raf 252 3086 raf static int 253 3086 raf set_error(int *errp, int err) 254 3086 raf { 255 3086 raf return (*errp = err); 256 3086 raf } 257 3086 raf 258 3086 raf static int 259 3086 raf get_error(int *errp) 260 3086 raf { 261 3086 raf return (*errp); 262 0 stevel } 263 0 stevel 264 0 stevel /* 265 0 stevel * For MT safety, do not invoke the dynamic linker after calling vfork(). 266 0 stevel * If some other thread was in the dynamic linker when this thread's parent 267 0 stevel * called vfork() then the dynamic linker's lock would still be held here 268 0 stevel * (with a defunct owner) and we would deadlock ourself if we invoked it. 269 0 stevel * 270 0 stevel * Therefore, all of the functions we call here after returning from 271 6812 raf * vforkx() in the child are not and must never be exported from libc 272 0 stevel * as global symbols. To do so would risk invoking the dynamic linker. 273 0 stevel */ 274 0 stevel 275 0 stevel int 276 6812 raf posix_spawn( 277 0 stevel pid_t *pidp, 278 0 stevel const char *path, 279 0 stevel const posix_spawn_file_actions_t *file_actions, 280 0 stevel const posix_spawnattr_t *attrp, 281 0 stevel char *const argv[], 282 0 stevel char *const envp[]) 283 0 stevel { 284 0 stevel spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 285 0 stevel file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 286 8877 Roger void *dirbuf = NULL; 287 3086 raf int error; /* this will be set by the child */ 288 0 stevel pid_t pid; 289 0 stevel 290 0 stevel if (attrp != NULL && sap == NULL) 291 0 stevel return (EINVAL); 292 0 stevel 293 8877 Roger if (fap != NULL && fap->fa_need_dirbuf) { 294 8877 Roger /* 295 8877 Roger * Preallocate the buffer for the call to getdents64() in 296 8877 Roger * spawn_closefrom() since we can't do it in the vfork() child. 297 8877 Roger */ 298 8877 Roger if ((dirbuf = lmalloc(DIRBUF)) == NULL) 299 8877 Roger return (ENOMEM); 300 8877 Roger } 301 8877 Roger 302 6812 raf switch (pid = vforkx(forkflags(sap))) { 303 0 stevel case 0: /* child */ 304 0 stevel break; 305 0 stevel case -1: /* parent, failure */ 306 8877 Roger if (dirbuf) 307 8877 Roger lfree(dirbuf, DIRBUF); 308 0 stevel return (errno); 309 0 stevel default: /* parent, success */ 310 3086 raf /* 311 3086 raf * We don't get here until the child exec()s or exit()s 312 3086 raf */ 313 3086 raf if (pidp != NULL && get_error(&error) == 0) 314 0 stevel *pidp = pid; 315 8877 Roger if (dirbuf) 316 8877 Roger lfree(dirbuf, DIRBUF); 317 3086 raf return (get_error(&error)); 318 0 stevel } 319 0 stevel 320 0 stevel if (sap != NULL) 321 3086 raf if (set_error(&error, perform_flag_actions(sap)) != 0) 322 6515 raf _exit(_EVAPORATE); 323 0 stevel 324 0 stevel if (fap != NULL) 325 8877 Roger if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0) 326 6515 raf _exit(_EVAPORATE); 327 0 stevel 328 3086 raf (void) set_error(&error, 0); 329 6515 raf (void) execve(path, argv, envp); 330 7635 Roger if (sap != NULL && (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) 331 7635 Roger _exit(127); 332 3086 raf (void) set_error(&error, errno); 333 6515 raf _exit(_EVAPORATE); 334 0 stevel return (0); /* not reached */ 335 0 stevel } 336 0 stevel 337 0 stevel /* 338 0 stevel * Much of posix_spawnp() blatently stolen from execvp() (port/gen/execvp.c). 339 0 stevel */ 340 0 stevel 341 5891 raf extern int libc__xpg4; 342 0 stevel 343 0 stevel static const char * 344 0 stevel execat(const char *s1, const char *s2, char *si) 345 0 stevel { 346 0 stevel int cnt = PATH_MAX + 1; 347 0 stevel char *s; 348 0 stevel char c; 349 0 stevel 350 0 stevel for (s = si; (c = *s1) != '\0' && c != ':'; s1++) { 351 0 stevel if (cnt > 0) { 352 0 stevel *s++ = c; 353 0 stevel cnt--; 354 0 stevel } 355 0 stevel } 356 0 stevel if (si != s && cnt > 0) { 357 0 stevel *s++ = '/'; 358 0 stevel cnt--; 359 0 stevel } 360 0 stevel for (; (c = *s2) != '\0' && cnt > 0; s2++) { 361 0 stevel *s++ = c; 362 0 stevel cnt--; 363 0 stevel } 364 0 stevel *s = '\0'; 365 0 stevel return (*s1? ++s1: NULL); 366 0 stevel } 367 0 stevel 368 0 stevel /* ARGSUSED */ 369 0 stevel int 370 6812 raf posix_spawnp( 371 0 stevel pid_t *pidp, 372 0 stevel const char *file, 373 0 stevel const posix_spawn_file_actions_t *file_actions, 374 0 stevel const posix_spawnattr_t *attrp, 375 0 stevel char *const argv[], 376 0 stevel char *const envp[]) 377 0 stevel { 378 0 stevel spawn_attr_t *sap = attrp? attrp->__spawn_attrp : NULL; 379 0 stevel file_attr_t *fap = file_actions? file_actions->__file_attrp : NULL; 380 8877 Roger void *dirbuf = NULL; 381 0 stevel const char *pathstr = (strchr(file, '/') == NULL)? getenv("PATH") : ""; 382 5891 raf int xpg4 = libc__xpg4; 383 7646 Roger int error = 0; /* this will be set by the child */ 384 0 stevel char path[PATH_MAX+4]; 385 0 stevel const char *cp; 386 0 stevel pid_t pid; 387 0 stevel char **newargs; 388 0 stevel int argc; 389 0 stevel int i; 390 0 stevel static const char *sun_path = "/bin/sh"; 391 0 stevel static const char *xpg4_path = "/usr/xpg4/bin/sh"; 392 0 stevel static const char *shell = "sh"; 393 0 stevel 394 0 stevel if (attrp != NULL && sap == NULL) 395 0 stevel return (EINVAL); 396 3086 raf 397 3086 raf if (*file == '\0') 398 3086 raf return (EACCES); 399 0 stevel 400 8877 Roger if (fap != NULL && fap->fa_need_dirbuf) { 401 8877 Roger /* 402 8877 Roger * Preallocate the buffer for the call to getdents64() in 403 8877 Roger * spawn_closefrom() since we can't do it in the vfork() child. 404 8877 Roger */ 405 8877 Roger if ((dirbuf = lmalloc(DIRBUF)) == NULL) 406 8877 Roger return (ENOMEM); 407 8877 Roger } 408 8877 Roger 409 0 stevel /* 410 0 stevel * We may need to invoke the shell with a slightly modified 411 0 stevel * argv[] array. To do this we need to preallocate the array. 412 0 stevel * We must call alloca() before calling vfork() because doing 413 0 stevel * it after vfork() (in the child) would corrupt the parent. 414 0 stevel */ 415 0 stevel for (argc = 0; argv[argc] != NULL; argc++) 416 0 stevel continue; 417 0 stevel newargs = alloca((argc + 2) * sizeof (char *)); 418 0 stevel 419 6812 raf switch (pid = vforkx(forkflags(sap))) { 420 0 stevel case 0: /* child */ 421 0 stevel break; 422 0 stevel case -1: /* parent, failure */ 423 8877 Roger if (dirbuf) 424 8877 Roger lfree(dirbuf, DIRBUF); 425 0 stevel return (errno); 426 0 stevel default: /* parent, success */ 427 3086 raf /* 428 3086 raf * We don't get here until the child exec()s or exit()s 429 3086 raf */ 430 3086 raf if (pidp != NULL && get_error(&error) == 0) 431 0 stevel *pidp = pid; 432 8877 Roger if (dirbuf) 433 8877 Roger lfree(dirbuf, DIRBUF); 434 3086 raf return (get_error(&error)); 435 0 stevel } 436 0 stevel 437 0 stevel if (sap != NULL) 438 3086 raf if (set_error(&error, perform_flag_actions(sap)) != 0) 439 6515 raf _exit(_EVAPORATE); 440 0 stevel 441 0 stevel if (fap != NULL) 442 8877 Roger if (set_error(&error, perform_file_actions(fap, dirbuf)) != 0) 443 6515 raf _exit(_EVAPORATE); 444 0 stevel 445 0 stevel if (pathstr == NULL) { 446 0 stevel /* 447 0 stevel * XPG4: pathstr is equivalent to _CS_PATH, except that 448 0 stevel * :/usr/sbin is appended when root, and pathstr must end 449 0 stevel * with a colon when not root. Keep these paths in sync 450 0 stevel * with _CS_PATH in confstr.c. Note that pathstr must end 451 0 stevel * with a colon when not root so that when file doesn't 452 0 stevel * contain '/', the last call to execat() will result in an 453 0 stevel * attempt to execv file from the current directory. 454 0 stevel */ 455 6515 raf if (geteuid() == 0 || getuid() == 0) { 456 0 stevel if (!xpg4) 457 0 stevel pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 458 0 stevel else 459 0 stevel pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 460 0 stevel "/usr/bin:/opt/SUNWspro/bin:/usr/sbin"; 461 0 stevel } else { 462 0 stevel if (!xpg4) 463 0 stevel pathstr = "/usr/ccs/bin:/usr/bin:"; 464 0 stevel else 465 0 stevel pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 466 0 stevel "/usr/bin:/opt/SUNWspro/bin:"; 467 0 stevel } 468 0 stevel } 469 0 stevel 470 0 stevel cp = pathstr; 471 0 stevel do { 472 0 stevel cp = execat(cp, file, path); 473 0 stevel /* 474 0 stevel * 4025035 and 4038378 475 0 stevel * if a filename begins with a "-" prepend "./" so that 476 0 stevel * the shell can't interpret it as an option 477 0 stevel */ 478 0 stevel if (*path == '-') { 479 0 stevel char *s; 480 0 stevel 481 0 stevel for (s = path; *s != '\0'; s++) 482 0 stevel continue; 483 0 stevel for (; s >= path; s--) 484 0 stevel *(s + 2) = *s; 485 0 stevel path[0] = '.'; 486 0 stevel path[1] = '/'; 487 0 stevel } 488 3086 raf (void) set_error(&error, 0); 489 6515 raf (void) execve(path, argv, envp); 490 3086 raf if (set_error(&error, errno) == ENOEXEC) { 491 0 stevel newargs[0] = (char *)shell; 492 0 stevel newargs[1] = path; 493 0 stevel for (i = 1; i <= argc; i++) 494 0 stevel newargs[i + 1] = argv[i]; 495 3086 raf (void) set_error(&error, 0); 496 6515 raf (void) execve(xpg4? xpg4_path : sun_path, 497 3086 raf newargs, envp); 498 7635 Roger if (sap != NULL && 499 7635 Roger (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) 500 7635 Roger _exit(127); 501 3086 raf (void) set_error(&error, errno); 502 6515 raf _exit(_EVAPORATE); 503 0 stevel } 504 0 stevel } while (cp); 505 7646 Roger 506 7646 Roger if (sap != NULL && 507 7646 Roger (sap->sa_psflags & POSIX_SPAWN_NOEXECERR_NP)) { 508 7646 Roger (void) set_error(&error, 0); 509 7646 Roger _exit(127); 510 7646 Roger } 511 6515 raf _exit(_EVAPORATE); 512 0 stevel return (0); /* not reached */ 513 0 stevel } 514 0 stevel 515 0 stevel int 516 6812 raf posix_spawn_file_actions_init( 517 0 stevel posix_spawn_file_actions_t *file_actions) 518 0 stevel { 519 0 stevel file_actions->__file_attrp = NULL; 520 0 stevel return (0); 521 0 stevel } 522 0 stevel 523 0 stevel int 524 6812 raf posix_spawn_file_actions_destroy( 525 0 stevel posix_spawn_file_actions_t *file_actions) 526 0 stevel { 527 0 stevel file_attr_t *froot = file_actions->__file_attrp; 528 0 stevel file_attr_t *fap; 529 0 stevel file_attr_t *next; 530 0 stevel 531 0 stevel if ((fap = froot) != NULL) { 532 0 stevel do { 533 0 stevel next = fap->fa_next; 534 8877 Roger if (fap->fa_type == FA_OPEN) 535 0 stevel lfree(fap->fa_path, fap->fa_pathsize); 536 0 stevel lfree(fap, sizeof (*fap)); 537 0 stevel } while ((fap = next) != froot); 538 0 stevel } 539 0 stevel file_actions->__file_attrp = NULL; 540 0 stevel return (0); 541 0 stevel } 542 0 stevel 543 0 stevel static void 544 0 stevel add_file_attr(posix_spawn_file_actions_t *file_actions, file_attr_t *fap) 545 0 stevel { 546 0 stevel file_attr_t *froot = file_actions->__file_attrp; 547 0 stevel 548 0 stevel if (froot == NULL) { 549 0 stevel fap->fa_next = fap->fa_prev = fap; 550 8877 Roger file_actions->__file_attrp = froot = fap; 551 0 stevel } else { 552 0 stevel fap->fa_next = froot; 553 0 stevel fap->fa_prev = froot->fa_prev; 554 0 stevel froot->fa_prev->fa_next = fap; 555 0 stevel froot->fa_prev = fap; 556 0 stevel } 557 8877 Roger 558 8877 Roger /* 559 8877 Roger * Once set, __file_attrp no longer changes, so this assignment 560 8877 Roger * always goes into the first element in the list, as required. 561 8877 Roger */ 562 8877 Roger if (fap->fa_type == FA_CLOSEFROM) 563 8877 Roger froot->fa_need_dirbuf = 1; 564 0 stevel } 565 0 stevel 566 0 stevel int 567 6812 raf posix_spawn_file_actions_addopen( 568 0 stevel posix_spawn_file_actions_t *file_actions, 569 0 stevel int filedes, 570 0 stevel const char *path, 571 0 stevel int oflag, 572 0 stevel mode_t mode) 573 0 stevel { 574 0 stevel file_attr_t *fap; 575 0 stevel 576 0 stevel if (filedes < 0) 577 0 stevel return (EBADF); 578 0 stevel if ((fap = lmalloc(sizeof (*fap))) == NULL) 579 0 stevel return (ENOMEM); 580 0 stevel 581 0 stevel fap->fa_pathsize = strlen(path) + 1; 582 0 stevel if ((fap->fa_path = lmalloc(fap->fa_pathsize)) == NULL) { 583 0 stevel lfree(fap, sizeof (*fap)); 584 0 stevel return (ENOMEM); 585 0 stevel } 586 0 stevel (void) strcpy(fap->fa_path, path); 587 0 stevel 588 0 stevel fap->fa_type = FA_OPEN; 589 0 stevel fap->fa_oflag = oflag; 590 0 stevel fap->fa_mode = mode; 591 0 stevel fap->fa_filedes = filedes; 592 0 stevel add_file_attr(file_actions, fap); 593 0 stevel 594 0 stevel return (0); 595 0 stevel } 596 0 stevel 597 0 stevel int 598 6812 raf posix_spawn_file_actions_addclose( 599 0 stevel posix_spawn_file_actions_t *file_actions, 600 0 stevel int filedes) 601 0 stevel { 602 0 stevel file_attr_t *fap; 603 0 stevel 604 0 stevel if (filedes < 0) 605 0 stevel return (EBADF); 606 0 stevel if ((fap = lmalloc(sizeof (*fap))) == NULL) 607 0 stevel return (ENOMEM); 608 0 stevel 609 0 stevel fap->fa_type = FA_CLOSE; 610 0 stevel fap->fa_filedes = filedes; 611 0 stevel add_file_attr(file_actions, fap); 612 0 stevel 613 0 stevel return (0); 614 0 stevel } 615 0 stevel 616 0 stevel int 617 6812 raf posix_spawn_file_actions_adddup2( 618 0 stevel posix_spawn_file_actions_t *file_actions, 619 0 stevel int filedes, 620 0 stevel int newfiledes) 621 0 stevel { 622 0 stevel file_attr_t *fap; 623 0 stevel 624 0 stevel if (filedes < 0 || newfiledes < 0) 625 0 stevel return (EBADF); 626 0 stevel if ((fap = lmalloc(sizeof (*fap))) == NULL) 627 0 stevel return (ENOMEM); 628 0 stevel 629 0 stevel fap->fa_type = FA_DUP2; 630 0 stevel fap->fa_filedes = filedes; 631 0 stevel fap->fa_newfiledes = newfiledes; 632 8877 Roger add_file_attr(file_actions, fap); 633 8877 Roger 634 8877 Roger return (0); 635 8877 Roger } 636 8877 Roger 637 8877 Roger int 638 8877 Roger posix_spawn_file_actions_addclosefrom_np( 639 8877 Roger posix_spawn_file_actions_t *file_actions, 640 8877 Roger int lowfiledes) 641 8877 Roger { 642 8877 Roger file_attr_t *fap; 643 8877 Roger 644 8877 Roger if (lowfiledes < 0) 645 8877 Roger return (EBADF); 646 8877 Roger if ((fap = lmalloc(sizeof (*fap))) == NULL) 647 8877 Roger return (ENOMEM); 648 8877 Roger fap->fa_type = FA_CLOSEFROM; 649 8877 Roger fap->fa_filedes = lowfiledes; 650 0 stevel add_file_attr(file_actions, fap); 651 0 stevel 652 0 stevel return (0); 653 0 stevel } 654 0 stevel 655 0 stevel int 656 6812 raf posix_spawnattr_init( 657 0 stevel posix_spawnattr_t *attr) 658 0 stevel { 659 3235 raf if ((attr->__spawn_attrp = lmalloc(sizeof (posix_spawnattr_t))) == NULL) 660 0 stevel return (ENOMEM); 661 0 stevel /* 662 0 stevel * Add default stuff here? 663 0 stevel */ 664 0 stevel return (0); 665 0 stevel } 666 0 stevel 667 0 stevel int 668 6812 raf posix_spawnattr_destroy( 669 0 stevel posix_spawnattr_t *attr) 670 0 stevel { 671 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 672 0 stevel 673 0 stevel if (sap == NULL) 674 0 stevel return (EINVAL); 675 0 stevel 676 0 stevel /* 677 0 stevel * deallocate stuff here? 678 0 stevel */ 679 0 stevel lfree(sap, sizeof (*sap)); 680 0 stevel attr->__spawn_attrp = NULL; 681 0 stevel return (0); 682 0 stevel } 683 0 stevel 684 0 stevel int 685 6812 raf posix_spawnattr_setflags( 686 0 stevel posix_spawnattr_t *attr, 687 0 stevel short flags) 688 0 stevel { 689 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 690 0 stevel 691 0 stevel if (sap == NULL || 692 0 stevel (flags & ~ALL_POSIX_SPAWN_FLAGS)) 693 0 stevel return (EINVAL); 694 0 stevel 695 0 stevel sap->sa_psflags = flags; 696 0 stevel return (0); 697 0 stevel } 698 0 stevel 699 0 stevel int 700 6812 raf posix_spawnattr_getflags( 701 0 stevel const posix_spawnattr_t *attr, 702 0 stevel short *flags) 703 0 stevel { 704 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 705 0 stevel 706 0 stevel if (sap == NULL) 707 0 stevel return (EINVAL); 708 0 stevel 709 0 stevel *flags = sap->sa_psflags; 710 0 stevel return (0); 711 0 stevel } 712 0 stevel 713 0 stevel int 714 6812 raf posix_spawnattr_setpgroup( 715 0 stevel posix_spawnattr_t *attr, 716 0 stevel pid_t pgroup) 717 0 stevel { 718 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 719 0 stevel 720 0 stevel if (sap == NULL) 721 0 stevel return (EINVAL); 722 0 stevel 723 0 stevel sap->sa_pgroup = pgroup; 724 0 stevel return (0); 725 0 stevel } 726 0 stevel 727 0 stevel int 728 6812 raf posix_spawnattr_getpgroup( 729 0 stevel const posix_spawnattr_t *attr, 730 0 stevel pid_t *pgroup) 731 0 stevel { 732 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 733 0 stevel 734 0 stevel if (sap == NULL) 735 0 stevel return (EINVAL); 736 0 stevel 737 0 stevel *pgroup = sap->sa_pgroup; 738 0 stevel return (0); 739 0 stevel } 740 0 stevel 741 0 stevel int 742 6812 raf posix_spawnattr_setschedparam( 743 0 stevel posix_spawnattr_t *attr, 744 0 stevel const struct sched_param *schedparam) 745 0 stevel { 746 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 747 0 stevel 748 0 stevel if (sap == NULL) 749 0 stevel return (EINVAL); 750 0 stevel 751 0 stevel /* 752 0 stevel * Check validity? 753 0 stevel */ 754 0 stevel sap->sa_priority = schedparam->sched_priority; 755 0 stevel return (0); 756 0 stevel } 757 0 stevel 758 0 stevel int 759 6812 raf posix_spawnattr_getschedparam( 760 0 stevel const posix_spawnattr_t *attr, 761 0 stevel struct sched_param *schedparam) 762 0 stevel { 763 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 764 0 stevel 765 0 stevel if (sap == NULL) 766 0 stevel return (EINVAL); 767 0 stevel 768 0 stevel schedparam->sched_priority = sap->sa_priority; 769 0 stevel return (0); 770 0 stevel } 771 0 stevel 772 0 stevel int 773 6812 raf posix_spawnattr_setschedpolicy( 774 0 stevel posix_spawnattr_t *attr, 775 0 stevel int schedpolicy) 776 0 stevel { 777 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 778 0 stevel 779 6247 raf if (sap == NULL || schedpolicy == SCHED_SYS) 780 0 stevel return (EINVAL); 781 0 stevel 782 6247 raf /* 783 6247 raf * Cache the policy information for later use 784 6247 raf * by the vfork() child of posix_spawn(). 785 6247 raf */ 786 6247 raf if (get_info_by_policy(schedpolicy) == NULL) 787 6247 raf return (errno); 788 0 stevel 789 0 stevel sap->sa_schedpolicy = schedpolicy; 790 0 stevel return (0); 791 0 stevel } 792 0 stevel 793 0 stevel int 794 6812 raf posix_spawnattr_getschedpolicy( 795 0 stevel const posix_spawnattr_t *attr, 796 0 stevel int *schedpolicy) 797 0 stevel { 798 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 799 0 stevel 800 0 stevel if (sap == NULL) 801 0 stevel return (EINVAL); 802 0 stevel 803 0 stevel *schedpolicy = sap->sa_schedpolicy; 804 0 stevel return (0); 805 0 stevel } 806 0 stevel 807 0 stevel int 808 6812 raf posix_spawnattr_setsigdefault( 809 0 stevel posix_spawnattr_t *attr, 810 0 stevel const sigset_t *sigdefault) 811 0 stevel { 812 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 813 0 stevel 814 0 stevel if (sap == NULL) 815 0 stevel return (EINVAL); 816 0 stevel 817 0 stevel sap->sa_sigdefault = *sigdefault; 818 0 stevel return (0); 819 0 stevel } 820 0 stevel 821 0 stevel int 822 6812 raf posix_spawnattr_getsigdefault( 823 0 stevel const posix_spawnattr_t *attr, 824 0 stevel sigset_t *sigdefault) 825 0 stevel { 826 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 827 0 stevel 828 0 stevel if (sap == NULL) 829 0 stevel return (EINVAL); 830 0 stevel 831 0 stevel *sigdefault = sap->sa_sigdefault; 832 0 stevel return (0); 833 0 stevel } 834 0 stevel 835 0 stevel int 836 7930 Roger posix_spawnattr_setsigignore_np( 837 7930 Roger posix_spawnattr_t *attr, 838 7930 Roger const sigset_t *sigignore) 839 7930 Roger { 840 7930 Roger spawn_attr_t *sap = attr->__spawn_attrp; 841 7930 Roger 842 7930 Roger if (sap == NULL) 843 7930 Roger return (EINVAL); 844 7930 Roger 845 7930 Roger sap->sa_sigignore = *sigignore; 846 7930 Roger return (0); 847 7930 Roger } 848 7930 Roger 849 7930 Roger int 850 7930 Roger posix_spawnattr_getsigignore_np( 851 7930 Roger const posix_spawnattr_t *attr, 852 7930 Roger sigset_t *sigignore) 853 7930 Roger { 854 7930 Roger spawn_attr_t *sap = attr->__spawn_attrp; 855 7930 Roger 856 7930 Roger if (sap == NULL) 857 7930 Roger return (EINVAL); 858 7930 Roger 859 7930 Roger *sigignore = sap->sa_sigignore; 860 7930 Roger return (0); 861 7930 Roger } 862 7930 Roger 863 7930 Roger int 864 6812 raf posix_spawnattr_setsigmask( 865 0 stevel posix_spawnattr_t *attr, 866 0 stevel const sigset_t *sigmask) 867 0 stevel { 868 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 869 0 stevel 870 0 stevel if (sap == NULL) 871 0 stevel return (EINVAL); 872 0 stevel 873 0 stevel sap->sa_sigmask = *sigmask; 874 0 stevel return (0); 875 0 stevel } 876 0 stevel 877 0 stevel int 878 6812 raf posix_spawnattr_getsigmask( 879 0 stevel const posix_spawnattr_t *attr, 880 0 stevel sigset_t *sigmask) 881 0 stevel { 882 0 stevel spawn_attr_t *sap = attr->__spawn_attrp; 883 0 stevel 884 0 stevel if (sap == NULL) 885 0 stevel return (EINVAL); 886 0 stevel 887 0 stevel *sigmask = sap->sa_sigmask; 888 0 stevel return (0); 889 0 stevel } 890