31
31
#include <string.h>
32
32
#include <fcntl.h>
33
33
#include <pthread.h>
34
-
34
+ #include <dirent.h>
35
35
#include <stdio.h>
36
36
37
+ #if __has_include (< linux /close_range .h > )
38
+ #include <linux/close_range.h>
39
+ #endif
40
+
41
+ #endif // TARGET_OS_WINDOWS
42
+
37
43
#if __has_include (< crt_externs .h > )
38
44
#include <crt_externs.h>
39
45
#elif defined(_WIN32)
@@ -361,91 +367,57 @@ static int _subprocess_addchdir_np(
361
367
#endif
362
368
}
363
369
364
- static int _subprocess_posix_spawn_fallback (
365
- pid_t * _Nonnull pid ,
366
- const char * _Nonnull exec_path ,
367
- const char * _Nullable working_directory ,
368
- const int file_descriptors [_Nonnull],
369
- char * _Nullable const args [_Nonnull],
370
- char * _Nullable const env [_Nullable ],
371
- gid_t * _Nullable process_group_id
372
- ) {
373
- // Setup stdin, stdout, and stderr
374
- posix_spawn_file_actions_t file_actions ;
375
-
376
- int rc = posix_spawn_file_actions_init (& file_actions );
377
- if (rc != 0 ) { return rc ; }
378
- if (file_descriptors [0 ] >= 0 ) {
379
- rc = posix_spawn_file_actions_adddup2 (
380
- & file_actions , file_descriptors [0 ], STDIN_FILENO
381
- );
382
- if (rc != 0 ) { return rc ; }
383
- }
384
- if (file_descriptors [2 ] >= 0 ) {
385
- rc = posix_spawn_file_actions_adddup2 (
386
- & file_actions , file_descriptors [2 ], STDOUT_FILENO
387
- );
388
- if (rc != 0 ) { return rc ; }
389
- }
390
- if (file_descriptors [4 ] >= 0 ) {
391
- rc = posix_spawn_file_actions_adddup2 (
392
- & file_actions , file_descriptors [4 ], STDERR_FILENO
393
- );
394
- if (rc != 0 ) { return rc ; }
395
- }
396
- // Setup working directory
397
- rc = _subprocess_addchdir_np (& file_actions , working_directory );
398
- if (rc != 0 ) {
399
- return rc ;
400
- }
370
+ static int _positive_int_parse (const char * str ) {
371
+ int out = 0 ;
372
+ char c = 0 ;
401
373
402
- // Close parent side
403
- if (file_descriptors [1 ] >= 0 ) {
404
- rc = posix_spawn_file_actions_addclose (& file_actions , file_descriptors [1 ]);
405
- if (rc != 0 ) { return rc ; }
406
- }
407
- if (file_descriptors [3 ] >= 0 ) {
408
- rc = posix_spawn_file_actions_addclose (& file_actions , file_descriptors [3 ]);
409
- if (rc != 0 ) { return rc ; }
374
+ while ((c = * str ++ ) != 0 ) {
375
+ out *= 10 ;
376
+ if (c >= '0' && c <= '9' ) {
377
+ out += c - '0' ;
378
+ } else {
379
+ return -1 ;
380
+ }
410
381
}
411
- if (file_descriptors [5 ] >= 0 ) {
412
- rc = posix_spawn_file_actions_addclose (& file_actions , file_descriptors [5 ]);
413
- if (rc != 0 ) { return rc ; }
382
+ return out ;
383
+ }
384
+
385
+ static int _highest_possibly_open_fd_dir (const char * fd_dir ) {
386
+ int highest_fd_so_far = 0 ;
387
+ DIR * dir_ptr = opendir (fd_dir );
388
+ if (dir_ptr == NULL ) {
389
+ return -1 ;
414
390
}
415
391
416
- // Setup spawnattr
417
- posix_spawnattr_t spawn_attr ;
418
- rc = posix_spawnattr_init (& spawn_attr );
419
- if (rc != 0 ) { return rc ; }
420
- // Masks
421
- sigset_t no_signals ;
422
- sigset_t all_signals ;
423
- sigemptyset (& no_signals );
424
- sigfillset (& all_signals );
425
- rc = posix_spawnattr_setsigmask (& spawn_attr , & no_signals );
426
- if (rc != 0 ) { return rc ; }
427
- rc = posix_spawnattr_setsigdefault (& spawn_attr , & all_signals );
428
- if (rc != 0 ) { return rc ; }
429
- // Flags
430
- short flags = POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF ;
431
- if (process_group_id != NULL ) {
432
- flags |= POSIX_SPAWN_SETPGROUP ;
433
- rc = posix_spawnattr_setpgroup (& spawn_attr , * process_group_id );
434
- if (rc != 0 ) { return rc ; }
392
+ struct dirent * dir_entry = NULL ;
393
+ while ((dir_entry = readdir (dir_ptr )) != NULL ) {
394
+ char * entry_name = dir_entry -> d_name ;
395
+ int number = _positive_int_parse (entry_name );
396
+ if (number > (long )highest_fd_so_far ) {
397
+ highest_fd_so_far = number ;
398
+ }
435
399
}
436
- rc = posix_spawnattr_setflags (& spawn_attr , flags );
437
400
438
- // Spawn!
439
- rc = posix_spawn (
440
- pid , exec_path ,
441
- & file_actions , & spawn_attr ,
442
- args , env
443
- );
444
- posix_spawn_file_actions_destroy (& file_actions );
445
- posix_spawnattr_destroy (& spawn_attr );
446
- return rc ;
401
+ closedir (dir_ptr );
402
+ return highest_fd_so_far ;
403
+ }
404
+
405
+ static int _highest_possibly_open_fd (void ) {
406
+ #if defined(__APPLE__ )
407
+ int hi = _highest_possibly_open_fd_dir ("/dev/fd" );
408
+ if (hi < 0 ) {
409
+ hi = getdtablesize ();
410
+ }
411
+ #elif defined(__linux__ )
412
+ int hi = _highest_possibly_open_fd_dir ("/proc/self/fd" );
413
+ if (hi < 0 ) {
414
+ hi = getdtablesize ();
415
+ }
416
+ #else
417
+ int hi = 1024 ;
418
+ #endif
419
+ return hi ;
447
420
}
448
- #endif // _POSIX_SPAWN
449
421
450
422
int _subprocess_fork_exec (
451
423
pid_t * _Nonnull pid ,
@@ -466,32 +438,6 @@ int _subprocess_fork_exec(
466
438
close(pipefd[1]); \
467
439
_exit(EXIT_FAILURE)
468
440
469
- int require_pre_fork = _subprocess_is_addchdir_np_available () == 0 ||
470
- uid != NULL ||
471
- gid != NULL ||
472
- process_group_id != NULL ||
473
- (number_of_sgroups > 0 && sgroups != NULL ) ||
474
- create_session ||
475
- configurator != NULL ;
476
-
477
- #if _POSIX_SPAWN
478
- // If posix_spawn is available on this platform and
479
- // we do not require prefork, use posix_spawn if possible.
480
- //
481
- // (Glibc's posix_spawn does not support
482
- // `POSIX_SPAWN_SETEXEC` therefore we have to keep
483
- // using fork/exec if `require_pre_fork` is true.
484
- if (require_pre_fork == 0 ) {
485
- return _subprocess_posix_spawn_fallback (
486
- pid , exec_path ,
487
- working_directory ,
488
- file_descriptors ,
489
- args , env ,
490
- process_group_id
491
- );
492
- }
493
- #endif
494
-
495
441
// Setup pipe to catch exec failures from child
496
442
int pipefd [2 ];
497
443
if (pipe (pipefd ) != 0 ) {
@@ -552,8 +498,6 @@ int _subprocess_fork_exec(
552
498
553
499
if (childPid == 0 ) {
554
500
// Child process
555
- close (pipefd [0 ]); // Close unused read end
556
-
557
501
// Reset signal handlers
558
502
for (int signo = 1 ; signo < _SUBPROCESS_SIG_MAX ; signo ++ ) {
559
503
if (signo == SIGKILL || signo == SIGSTOP ) {
@@ -615,41 +559,48 @@ int _subprocess_fork_exec(
615
559
// Bind stdin, stdout, and stderr
616
560
if (file_descriptors [0 ] >= 0 ) {
617
561
rc = dup2 (file_descriptors [0 ], STDIN_FILENO );
618
- if (rc < 0 ) {
619
- write_error_and_exit ;
620
- }
562
+ } else {
563
+ rc = close (STDIN_FILENO );
564
+ }
565
+ if (rc < 0 ) {
566
+ write_error_and_exit ;
621
567
}
568
+
622
569
if (file_descriptors [2 ] >= 0 ) {
623
570
rc = dup2 (file_descriptors [2 ], STDOUT_FILENO );
624
- if (rc < 0 ) {
625
- write_error_and_exit ;
626
- }
571
+ } else {
572
+ rc = close (STDOUT_FILENO );
573
+ }
574
+ if (rc < 0 ) {
575
+ write_error_and_exit ;
627
576
}
577
+
628
578
if (file_descriptors [4 ] >= 0 ) {
629
579
rc = dup2 (file_descriptors [4 ], STDERR_FILENO );
630
- if (rc < 0 ) {
631
- int error = errno ;
632
- write (pipefd [1 ], & error , sizeof (error ));
633
- close (pipefd [1 ]);
634
- _exit (EXIT_FAILURE );
635
- }
636
- }
637
- // Close parent side
638
- if (file_descriptors [1 ] >= 0 ) {
639
- rc = close (file_descriptors [1 ]);
580
+ } else {
581
+ rc = close (STDERR_FILENO );
640
582
}
641
- if (file_descriptors [3 ] >= 0 ) {
642
- rc = close (file_descriptors [3 ]);
643
- }
644
- if (file_descriptors [4 ] >= 0 ) {
645
- rc = close (file_descriptors [4 ]);
583
+ if (rc < 0 ) {
584
+ write_error_and_exit ;
646
585
}
586
+ // Close all other file descriptors
587
+ rc = -1 ;
588
+ errno = ENOSYS ;
589
+ #if __has_include (< linux /close_range .h > )
590
+ // We must NOT close pipefd[1] for writing errors
591
+ rc = close_range (STDERR_FILENO + 1 , pipefd [1 ] - 1 , 0 );
592
+ rc |= close_range (pipefd [1 ] + 1 , ~0U , 0 );
593
+ #endif
647
594
if (rc != 0 ) {
648
- int error = errno ;
649
- write (pipefd [1 ], & error , sizeof (error ));
650
- close (pipefd [1 ]);
651
- _exit (EXIT_FAILURE );
595
+ // close_range failed (or doesn't exist), fall back to close()
596
+ for (int fd = STDERR_FILENO + 1 ; fd < _highest_possibly_open_fd (); fd + + ) {
597
+ // We must NOT close pipefd[1] for writing errors
598
+ if (fd != pipefd [1 ]) {
599
+ close (fd );
600
+ }
601
+ }
652
602
}
603
+
653
604
// Run custom configuratior
654
605
if (configurator != NULL ) {
655
606
configurator ();
0 commit comments