| #ifndef _CRT_SECURE_NO_WARNINGS |
| # define _CRT_SECURE_NO_WARNINGS |
| #endif |
| |
| #if defined(_MSC_VER) && _MSC_VER >= 1928 |
| # pragma warning(disable : 5105) /* macro expansion warning in windows.h */ |
| #endif |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #define MAX_MESSAGE_LENGTH 1023 |
| #define USAGE "Usage: %s <output_file>\n" |
| |
| // Extracts the jobserver details from the MAKEFLAGS environment variable. |
| // |
| // Returns a pointer to either a string of the form "R,W" where R and W are fds |
| // or "fifo:PATH". |
| // |
| // Returns NULL if MAKEFLAGS is not set or does not contain recognized |
| // jobserver flags. |
| char* jobserver_auth(char* message) |
| { |
| const char* jobserver_flags[3] = { "--jobserver-auth=", "--jobserver-fds=", |
| "-J" }; |
| char* start = NULL; |
| char* end; |
| char* result; |
| size_t len; |
| int i; |
| |
| char* makeflags = getenv("MAKEFLAGS"); |
| if (makeflags == NULL) { |
| strncpy(message, "MAKEFLAGS not set", MAX_MESSAGE_LENGTH); |
| return NULL; |
| } |
| |
| fprintf(stdout, "MAKEFLAGS: %s\n", makeflags); |
| |
| for (i = 0; i < 3; i++) { |
| start = strstr(makeflags, jobserver_flags[i]); |
| if (start != NULL) { |
| start += strlen(jobserver_flags[i]); |
| break; |
| } |
| } |
| |
| if (start == NULL) { |
| strncpy(message, "No jobserver flags found", MAX_MESSAGE_LENGTH); |
| return NULL; |
| } |
| |
| // Skip leading white space |
| while (*start == ' ' || *start == '\t') { |
| start++; |
| } |
| |
| end = strchr(start, ' '); |
| if (end == NULL) { |
| end = start + strlen(start); |
| } |
| len = (size_t)(end - start); |
| result = (char*)malloc(len + 1); |
| strncpy(result, start, len); |
| result[len] = '\0'; |
| |
| return result; |
| } |
| |
| #if defined(_WIN32) |
| # include <windows.h> |
| |
| int windows_semaphore(const char* semaphore, char* message) |
| { |
| // Open the semaphore |
| HANDLE hSemaphore = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, semaphore); |
| |
| if (hSemaphore == NULL) { |
| # if defined(_MSC_VER) && _MSC_VER < 1900 |
| sprintf(message, "Error opening semaphore: %s (%ld)\n", semaphore, |
| GetLastError()); |
| # else |
| snprintf(message, MAX_MESSAGE_LENGTH, |
| "Error opening semaphore: %s (%ld)\n", semaphore, GetLastError()); |
| # endif |
| return 1; |
| } |
| |
| strncpy(message, "Success", MAX_MESSAGE_LENGTH); |
| return 0; |
| } |
| #else |
| # include <errno.h> |
| # include <fcntl.h> |
| |
| int test_fd(int read_fd, int write_fd, char* message) |
| { |
| // Detect if the file descriptors are valid |
| int read_good = fcntl(read_fd, F_GETFD) != -1; |
| int read_error = errno; |
| |
| int write_good = fcntl(write_fd, F_GETFD) != -1; |
| int write_error = errno; |
| |
| if (!read_good || !write_good) { |
| snprintf(message, MAX_MESSAGE_LENGTH, |
| "Error opening file descriptors: %d (%s), %d (%s)\n", read_fd, |
| strerror(read_error), write_fd, strerror(write_error)); |
| return 1; |
| } |
| |
| snprintf(message, MAX_MESSAGE_LENGTH, "Success\n"); |
| return 0; |
| } |
| |
| int posix(const char* jobserver, char* message) |
| { |
| int read_fd; |
| int write_fd; |
| |
| // First try to parse as "R,W" file descriptors |
| if (sscanf(jobserver, "%d,%d", &read_fd, &write_fd) == 2) { |
| return test_fd(read_fd, write_fd, message); |
| } |
| |
| // Then try to parse as "fifo:PATH" |
| if (strncmp(jobserver, "fifo:", 5) == 0) { |
| const char* path = jobserver + 5; |
| read_fd = open(path, O_RDONLY); |
| write_fd = open(path, O_WRONLY); |
| return test_fd(read_fd, write_fd, message); |
| } |
| |
| // We don't understand the format |
| snprintf(message, MAX_MESSAGE_LENGTH, "Unrecognized jobserver format: %s\n", |
| jobserver); |
| return 1; |
| } |
| #endif |
| |
| // Takes 1 argument: an outfile to write results to. |
| int main(int argc, char** argv) |
| { |
| char message[MAX_MESSAGE_LENGTH + 1]; |
| char* output_file; |
| FILE* fp; |
| char* jobserver; |
| int result; |
| |
| if (argc != 2) { |
| fprintf(stderr, USAGE, argv[0]); |
| return 2; |
| } |
| |
| output_file = argv[1]; |
| fp = fopen(output_file, "w"); |
| if (fp == NULL) { |
| fprintf(stderr, "Error opening output file: %s\n", output_file); |
| return 2; |
| } |
| |
| jobserver = jobserver_auth(message); |
| if (jobserver == NULL) { |
| fprintf(stderr, "%s\n", message); |
| return 1; |
| } |
| |
| #if defined(_WIN32) |
| result = windows_semaphore(jobserver, message); |
| #else |
| result = posix(jobserver, message); |
| #endif |
| free(jobserver); |
| message[MAX_MESSAGE_LENGTH] = '\0'; |
| |
| return result; |
| } |