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