1/*- 2 * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h>
|
133 return (errno); 134 } 135 } 136 137 return (0); 138} 139 140static int 141process_file_actions_entry(posix_spawn_file_actions_entry_t *fae) 142{ 143 int fd; 144 145 switch (fae->fae_action) { 146 case FAE_OPEN: 147 /* Perform an open(), make it use the right fd */ 148 fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode); 149 if (fd < 0) 150 return (errno); 151 if (fd != fae->fae_fildes) { 152 if (_dup2(fd, fae->fae_fildes) == -1) 153 return (errno); 154 if (_close(fd) != 0) { 155 if (errno == EBADF) 156 return (EBADF); 157 } 158 } 159 if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1) 160 return (errno); 161 break; 162 case FAE_DUP2: 163 /* Perform a dup2() */ 164 if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1) 165 return (errno); 166 if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1) 167 return (errno); 168 break; 169 case FAE_CLOSE: 170 /* Perform a close(), do not fail if already closed */ 171 (void)_close(fae->fae_fildes); 172 break; 173 } 174 return (0); 175} 176 177static int 178process_file_actions(const posix_spawn_file_actions_t fa) 179{ 180 posix_spawn_file_actions_entry_t *fae; 181 int error; 182 183 /* Replay all file descriptor modifications */ 184 STAILQ_FOREACH(fae, &fa->fa_list, fae_list) { 185 error = process_file_actions_entry(fae); 186 if (error) 187 return (error); 188 } 189 return (0); 190} 191 192static int 193do_posix_spawn(pid_t *pid, const char *path, 194 const posix_spawn_file_actions_t *fa, 195 const posix_spawnattr_t *sa, 196 char * const argv[], char * const envp[], int use_env_path) 197{ 198 pid_t p; 199 volatile int error = 0; 200 201 p = vfork(); 202 switch (p) { 203 case -1: 204 return (errno); 205 case 0: 206 if (sa != NULL) { 207 error = process_spawnattr(*sa); 208 if (error) 209 _exit(127); 210 } 211 if (fa != NULL) { 212 error = process_file_actions(*fa); 213 if (error) 214 _exit(127); 215 } 216 if (use_env_path) 217 _execvpe(path, argv, envp != NULL ? envp : environ); 218 else 219 _execve(path, argv, envp != NULL ? envp : environ); 220 error = errno; 221 _exit(127); 222 default: 223 if (error != 0) 224 _waitpid(p, NULL, WNOHANG); 225 else if (pid != NULL) 226 *pid = p; 227 return (error); 228 } 229} 230 231int 232posix_spawn(pid_t *pid, const char *path, 233 const posix_spawn_file_actions_t *fa, 234 const posix_spawnattr_t *sa, 235 char * const argv[], char * const envp[]) 236{ 237 return do_posix_spawn(pid, path, fa, sa, argv, envp, 0); 238} 239 240int 241posix_spawnp(pid_t *pid, const char *path, 242 const posix_spawn_file_actions_t *fa, 243 const posix_spawnattr_t *sa, 244 char * const argv[], char * const envp[]) 245{ 246 return do_posix_spawn(pid, path, fa, sa, argv, envp, 1); 247} 248 249/* 250 * File descriptor actions 251 */ 252 253int 254posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret) 255{ 256 posix_spawn_file_actions_t fa; 257 258 fa = malloc(sizeof(struct __posix_spawn_file_actions)); 259 if (fa == NULL) 260 return (-1); 261 262 STAILQ_INIT(&fa->fa_list); 263 *ret = fa; 264 return (0); 265} 266 267int 268posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa) 269{ 270 posix_spawn_file_actions_entry_t *fae; 271 272 while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) { 273 /* Remove file action entry from the queue */ 274 STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list); 275 276 /* Deallocate file action entry */ 277 if (fae->fae_action == FAE_OPEN) 278 free(fae->fae_path); 279 free(fae); 280 } 281 282 free(*fa); 283 return (0); 284} 285 286int 287posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa, 288 int fildes, const char * __restrict path, int oflag, mode_t mode) 289{ 290 posix_spawn_file_actions_entry_t *fae; 291 int error; 292 293 if (fildes < 0) 294 return (EBADF); 295 296 /* Allocate object */ 297 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 298 if (fae == NULL) 299 return (errno); 300 301 /* Set values and store in queue */ 302 fae->fae_action = FAE_OPEN; 303 fae->fae_path = strdup(path); 304 if (fae->fae_path == NULL) { 305 error = errno; 306 free(fae); 307 return (error); 308 } 309 fae->fae_fildes = fildes; 310 fae->fae_oflag = oflag; 311 fae->fae_mode = mode; 312 313 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 314 return (0); 315} 316 317int 318posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, 319 int fildes, int newfildes) 320{ 321 posix_spawn_file_actions_entry_t *fae; 322 323 if (fildes < 0 || newfildes < 0) 324 return (EBADF); 325 326 /* Allocate object */ 327 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 328 if (fae == NULL) 329 return (errno); 330 331 /* Set values and store in queue */ 332 fae->fae_action = FAE_DUP2; 333 fae->fae_fildes = fildes; 334 fae->fae_newfildes = newfildes; 335 336 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 337 return (0); 338} 339 340int 341posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, 342 int fildes) 343{ 344 posix_spawn_file_actions_entry_t *fae; 345 346 if (fildes < 0) 347 return (EBADF); 348 349 /* Allocate object */ 350 fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); 351 if (fae == NULL) 352 return (errno); 353 354 /* Set values and store in queue */ 355 fae->fae_action = FAE_CLOSE; 356 fae->fae_fildes = fildes; 357 358 STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); 359 return (0); 360} 361 362/* 363 * Spawn attributes 364 */ 365 366int 367posix_spawnattr_init(posix_spawnattr_t *ret) 368{ 369 posix_spawnattr_t sa; 370 371 sa = calloc(1, sizeof(struct __posix_spawnattr)); 372 if (sa == NULL) 373 return (errno); 374 375 /* Set defaults as specified by POSIX, cleared above */ 376 *ret = sa; 377 return (0); 378} 379 380int 381posix_spawnattr_destroy(posix_spawnattr_t *sa) 382{ 383 free(*sa); 384 return (0); 385} 386 387int 388posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa, 389 short * __restrict flags) 390{ 391 *flags = (*sa)->sa_flags; 392 return (0); 393} 394 395int 396posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa, 397 pid_t * __restrict pgroup) 398{ 399 *pgroup = (*sa)->sa_pgroup; 400 return (0); 401} 402 403int 404posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa, 405 struct sched_param * __restrict schedparam) 406{ 407 *schedparam = (*sa)->sa_schedparam; 408 return (0); 409} 410 411int 412posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa, 413 int * __restrict schedpolicy) 414{ 415 *schedpolicy = (*sa)->sa_schedpolicy; 416 return (0); 417} 418 419int 420posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa, 421 sigset_t * __restrict sigdefault) 422{ 423 *sigdefault = (*sa)->sa_sigdefault; 424 return (0); 425} 426 427int 428posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa, 429 sigset_t * __restrict sigmask) 430{ 431 *sigmask = (*sa)->sa_sigmask; 432 return (0); 433} 434 435int 436posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags) 437{ 438 (*sa)->sa_flags = flags; 439 return (0); 440} 441 442int 443posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup) 444{ 445 (*sa)->sa_pgroup = pgroup; 446 return (0); 447} 448 449int 450posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa, 451 const struct sched_param * __restrict schedparam) 452{ 453 (*sa)->sa_schedparam = *schedparam; 454 return (0); 455} 456 457int 458posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy) 459{ 460 (*sa)->sa_schedpolicy = schedpolicy; 461 return (0); 462} 463 464int 465posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa, 466 const sigset_t * __restrict sigdefault) 467{ 468 (*sa)->sa_sigdefault = *sigdefault; 469 return (0); 470} 471 472int 473posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa, 474 const sigset_t * __restrict sigmask) 475{ 476 (*sa)->sa_sigmask = *sigmask; 477 return (0); 478}
|