| 1105 | #endif |
| 1106 | |
| 1107 | static int cbm_subprocess_spawn_posix(cbm_subprocess_t *process) { |
| 1108 | int input_flags = O_RDONLY; |
| 1109 | #ifdef O_CLOEXEC |
| 1110 | input_flags |= O_CLOEXEC; |
| 1111 | #endif |
| 1112 | int input = cbm_posix_fd_at_least_three(open("/dev/null", input_flags)); |
| 1113 | const char *target = process->log_file ? process->log_file : "/dev/null"; |
| 1114 | int output_flags = O_WRONLY | O_CREAT | O_TRUNC; |
| 1115 | #ifdef O_CLOEXEC |
| 1116 | output_flags |= O_CLOEXEC; |
| 1117 | #endif |
| 1118 | #ifdef O_NOFOLLOW |
| 1119 | output_flags |= O_NOFOLLOW; |
| 1120 | #endif |
| 1121 | int output = cbm_posix_fd_at_least_three(open(target, output_flags, 0600)); |
| 1122 | if (input < 0 || output < 0) { |
| 1123 | if (input >= 0) { |
| 1124 | (void)close(input); |
| 1125 | } |
| 1126 | if (output >= 0) { |
| 1127 | (void)close(output); |
| 1128 | } |
| 1129 | return -1; |
| 1130 | } |
| 1131 | struct stat output_status; |
| 1132 | if (fstat(output, &output_status) != 0 || |
| 1133 | (process->log_file && !S_ISREG(output_status.st_mode))) { |
| 1134 | (void)close(input); |
| 1135 | (void)close(output); |
| 1136 | return -1; |
| 1137 | } |
| 1138 | if (process->log_file && fchmod(output, 0600) != 0) { |
| 1139 | (void)close(input); |
| 1140 | (void)close(output); |
| 1141 | return -1; |
| 1142 | } |
| 1143 | |
| 1144 | long max_fd = sysconf(_SC_OPEN_MAX); |
| 1145 | if (max_fd < 0 || max_fd > 1048576L) { |
| 1146 | max_fd = 65536L; |
| 1147 | } |
| 1148 | |
| 1149 | pid_t pid = -1; |
| 1150 | #ifdef __APPLE__ |
| 1151 | int spawn_rc = cbm_posix_spawn_apple(process, input, output, &pid); |
| 1152 | for (int attempt = 0; spawn_rc == CBM_SPAWN_RETRY && attempt < CBM_SPAWN_RETRY_ATTEMPTS; |
| 1153 | attempt++) { |
| 1154 | cbm_spawn_backoff(attempt); |
| 1155 | spawn_rc = cbm_posix_spawn_apple(process, input, output, &pid); |
| 1156 | } |
| 1157 | if (spawn_rc == CBM_SPAWN_RETRY) { |
| 1158 | spawn_rc = -1; /* still exhausted after backoff: a real failure */ |
| 1159 | } |
| 1160 | if (spawn_rc < 0) { |
| 1161 | (void)close(input); |
| 1162 | (void)close(output); |
| 1163 | return -1; |
| 1164 | } |
no test coverage detected