flock-oracle.c 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. /* Independent system flock(2) oracle; stdin commands produce flushed JSON lines. */
  2. #include <errno.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <sys/file.h>
  7. #include <unistd.h>
  8. static int reply(int fd, int operation) {
  9. const int result = flock(fd, operation);
  10. const int error = result == 0 ? 0 : errno;
  11. if (printf("{\"errno\":%d}\n", error) < 0 || fflush(stdout) == EOF) {
  12. perror("flock-oracle: stdout");
  13. return 1;
  14. }
  15. return 0;
  16. }
  17. int main(int argc, char **argv) {
  18. int operation = LOCK_EX;
  19. if (argc < 2 || argc > 3) {
  20. fprintf(stderr, "usage: flock-oracle <path> [exclusive|shared]\n");
  21. return 1;
  22. }
  23. if (argc == 3) {
  24. if (strcmp(argv[2], "shared") == 0) {
  25. operation = LOCK_SH;
  26. } else if (strcmp(argv[2], "exclusive") != 0) {
  27. fprintf(stderr, "flock-oracle: mode must be exclusive or shared\n");
  28. return 1;
  29. }
  30. }
  31. const int fd = open(argv[1], O_RDWR | O_CREAT, 0600);
  32. if (fd == -1) {
  33. perror("flock-oracle: open");
  34. return 1;
  35. }
  36. int status = 0;
  37. if (puts("{\"ready\":true}") == EOF || fflush(stdout) == EOF) {
  38. perror("flock-oracle: stdout");
  39. status = 1;
  40. goto cleanup;
  41. }
  42. char command[3];
  43. while (fgets(command, sizeof(command), stdin) != NULL) {
  44. if (command[1] != '\n') {
  45. fprintf(stderr, "flock-oracle: commands must be one letter followed by a newline\n");
  46. status = 1;
  47. break;
  48. }
  49. if (command[0] == 'q') break;
  50. if (command[0] != 't' && command[0] != 'u') {
  51. fprintf(stderr, "flock-oracle: expected t, u, or q\n");
  52. status = 1;
  53. break;
  54. }
  55. if (reply(fd, command[0] == 't' ? operation | LOCK_NB : LOCK_UN) != 0) {
  56. status = 1;
  57. break;
  58. }
  59. }
  60. if (ferror(stdin)) {
  61. perror("flock-oracle: stdin");
  62. status = 1;
  63. }
  64. cleanup:
  65. if (close(fd) == -1) {
  66. perror("flock-oracle: close");
  67. status = 1;
  68. }
  69. return status;
  70. }