Files
cmake/Tests/RunCMake/detect_jobserver.c
T

205 lines
5.1 KiB
C

#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 [--present|--absent] <output_file>\n"
// Extracts --jobserver-auth=<string> or --jobserver-fds=<string> from
// MAKEFLAGS. The returned pointer points to the start of <string> Returns NULL
// if MAKEFLAGS is not set or does not contain --jobserver-auth or
// --jobserver-fds
char* jobserver_auth(char* message)
{
const char* jobserver_auth = "--jobserver-auth=";
const char* jobserver_fds = "--jobserver-fds=";
char* auth;
char* fds;
char* start;
char* end;
char* result;
size_t len;
char* makeflags = getenv("MAKEFLAGS");
if (makeflags == NULL) {
strncpy(message, "MAKEFLAGS not set", MAX_MESSAGE_LENGTH);
return NULL;
}
// write MAKEFLAGS to stdout for debugging
fprintf(stdout, "MAKEFLAGS: %s\n", makeflags);
auth = strstr(makeflags, jobserver_auth);
fds = strstr(makeflags, jobserver_fds);
if (auth == NULL && fds == NULL) {
strncpy(message, "No jobserver found", MAX_MESSAGE_LENGTH);
return NULL;
} else if (auth != NULL) {
start = auth + strlen(jobserver_auth);
} else {
start = fds + strlen(jobserver_fds);
}
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;
const char* path;
// 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) {
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 2 arguments:
// Either --present or --absent to indicate we expect the jobserver to be
// "present and valid", or "absent or invalid"
//
// if `--present` is passed, the exit code will be 0 if the jobserver is
// present, 1 if it is absent if `--absent` is passed, the exit code will be 0
// if the jobserver is absent, 1 if it is present in either case, if there is
// some fatal error (e.g the output file cannot be opened), the exit code will
// be 2
int main(int argc, char** argv)
{
char message[MAX_MESSAGE_LENGTH + 1];
char* output_file;
FILE* fp;
int expecting_present;
int expecting_absent;
char* jobserver;
int result;
if (argc != 3) {
fprintf(stderr, USAGE, argv[0]);
return 2;
}
expecting_present = strcmp(argv[1], "--present") == 0;
expecting_absent = strcmp(argv[1], "--absent") == 0;
if (!expecting_present && !expecting_absent) {
fprintf(stderr, USAGE, argv[0]);
return 2;
}
output_file = argv[2];
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) {
if (expecting_absent) {
fprintf(stdout, "Success\n");
return 0;
}
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;
if (result == 0 && expecting_present) {
fprintf(stdout, "Success\n");
return 0;
}
if (result == 1 && expecting_absent) {
fprintf(stdout, "Success\n");
return 0;
}
fprintf(stderr, "%s\n", message);
return 1;
}