detect_jobserver.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. #ifndef _CRT_SECURE_NO_WARNINGS
  2. # define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #if defined(_MSC_VER) && _MSC_VER >= 1928
  5. # pragma warning(disable : 5105) /* macro expansion warning in windows.h */
  6. #endif
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #define MAX_MESSAGE_LENGTH 1023
  11. #define USAGE "Usage: %s <output_file>\n"
  12. // Extracts the jobserver details from the MAKEFLAGS environment variable.
  13. //
  14. // Returns a pointer to either a string of the form "R,W" where R and W are fds
  15. // or "fifo:PATH".
  16. //
  17. // Returns NULL if MAKEFLAGS is not set or does not contain recognized
  18. // jobserver flags.
  19. char* jobserver_auth(char* message)
  20. {
  21. const char* jobserver_flags[3] = { "--jobserver-auth=", "--jobserver-fds=",
  22. "-J" };
  23. char* start = NULL;
  24. char* end;
  25. char* result;
  26. size_t len;
  27. int i;
  28. char* makeflags = getenv("MAKEFLAGS");
  29. if (makeflags == NULL) {
  30. strncpy(message, "MAKEFLAGS not set", MAX_MESSAGE_LENGTH);
  31. return NULL;
  32. }
  33. fprintf(stdout, "MAKEFLAGS: %s\n", makeflags);
  34. for (i = 0; i < 3; i++) {
  35. start = strstr(makeflags, jobserver_flags[i]);
  36. if (start != NULL) {
  37. start += strlen(jobserver_flags[i]);
  38. break;
  39. }
  40. }
  41. if (start == NULL) {
  42. strncpy(message, "No jobserver flags found", MAX_MESSAGE_LENGTH);
  43. return NULL;
  44. }
  45. // Skip leading white space
  46. while (*start == ' ' || *start == '\t') {
  47. start++;
  48. }
  49. end = strchr(start, ' ');
  50. if (end == NULL) {
  51. end = start + strlen(start);
  52. }
  53. len = (size_t)(end - start);
  54. result = (char*)malloc(len + 1);
  55. strncpy(result, start, len);
  56. result[len] = '\0';
  57. return result;
  58. }
  59. #if defined(_WIN32)
  60. # include <windows.h>
  61. int windows_semaphore(const char* semaphore, char* message)
  62. {
  63. // Open the semaphore
  64. HANDLE hSemaphore = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, semaphore);
  65. if (hSemaphore == NULL) {
  66. # if defined(_MSC_VER) && _MSC_VER < 1900
  67. sprintf(message, "Error opening semaphore: %s (%ld)\n", semaphore,
  68. GetLastError());
  69. # else
  70. snprintf(message, MAX_MESSAGE_LENGTH,
  71. "Error opening semaphore: %s (%ld)\n", semaphore, GetLastError());
  72. # endif
  73. return 1;
  74. }
  75. strncpy(message, "Success", MAX_MESSAGE_LENGTH);
  76. return 0;
  77. }
  78. #else
  79. # include <errno.h>
  80. # include <fcntl.h>
  81. int test_fd(int read_fd, int write_fd, char* message)
  82. {
  83. // Detect if the file descriptors are valid
  84. int read_good = fcntl(read_fd, F_GETFD) != -1;
  85. int read_error = errno;
  86. int write_good = fcntl(write_fd, F_GETFD) != -1;
  87. int write_error = errno;
  88. if (!read_good || !write_good) {
  89. snprintf(message, MAX_MESSAGE_LENGTH,
  90. "Error opening file descriptors: %d (%s), %d (%s)\n", read_fd,
  91. strerror(read_error), write_fd, strerror(write_error));
  92. return 1;
  93. }
  94. snprintf(message, MAX_MESSAGE_LENGTH, "Success\n");
  95. return 0;
  96. }
  97. int posix(const char* jobserver, char* message)
  98. {
  99. int read_fd;
  100. int write_fd;
  101. const char* path;
  102. // First try to parse as "R,W" file descriptors
  103. if (sscanf(jobserver, "%d,%d", &read_fd, &write_fd) == 2) {
  104. return test_fd(read_fd, write_fd, message);
  105. }
  106. // Then try to parse as "fifo:PATH"
  107. if (strncmp(jobserver, "fifo:", 5) == 0) {
  108. path = jobserver + 5;
  109. read_fd = open(path, O_RDONLY);
  110. write_fd = open(path, O_WRONLY);
  111. return test_fd(read_fd, write_fd, message);
  112. }
  113. // We don't understand the format
  114. snprintf(message, MAX_MESSAGE_LENGTH, "Unrecognized jobserver format: %s\n",
  115. jobserver);
  116. return 1;
  117. }
  118. #endif
  119. // Takes 1 argument: an outfile to write results to.
  120. int main(int argc, char** argv)
  121. {
  122. char message[MAX_MESSAGE_LENGTH + 1];
  123. char* output_file;
  124. FILE* fp;
  125. char* jobserver;
  126. int result;
  127. if (argc != 2) {
  128. fprintf(stderr, USAGE, argv[0]);
  129. return 2;
  130. }
  131. output_file = argv[1];
  132. fp = fopen(output_file, "w");
  133. if (fp == NULL) {
  134. fprintf(stderr, "Error opening output file: %s\n", output_file);
  135. return 2;
  136. }
  137. jobserver = jobserver_auth(message);
  138. if (jobserver == NULL) {
  139. fprintf(stderr, "%s\n", message);
  140. return 1;
  141. }
  142. #if defined(_WIN32)
  143. result = windows_semaphore(jobserver, message);
  144. #else
  145. result = posix(jobserver, message);
  146. #endif
  147. free(jobserver);
  148. message[MAX_MESSAGE_LENGTH] = '\0';
  149. return result;
  150. }