THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
2.4KB

  1. #include "cache.h"
  2. #include "unix-socket.h"
  3. static int unix_stream_socket(void)
  4. {
  5. int fd = socket(AF_UNIX, SOCK_STREAM, 0);
  6. if (fd < 0)
  7. die_errno("unable to create socket");
  8. return fd;
  9. }
  10. static int chdir_len(const char *orig, int len)
  11. {
  12. char *path = xmemdupz(orig, len);
  13. int r = chdir(path);
  14. free(path);
  15. return r;
  16. }
  17. struct unix_sockaddr_context {
  18. char *orig_dir;
  19. };
  20. static void unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx)
  21. {
  22. if (!ctx->orig_dir)
  23. return;
  24. /*
  25. * If we fail, we can't just return an error, since we have
  26. * moved the cwd of the whole process, which could confuse calling
  27. * code. We are better off to just die.
  28. */
  29. if (chdir(ctx->orig_dir) < 0)
  30. die("unable to restore original working directory");
  31. free(ctx->orig_dir);
  32. }
  33. static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path,
  34. struct unix_sockaddr_context *ctx)
  35. {
  36. int size = strlen(path) + 1;
  37. ctx->orig_dir = NULL;
  38. if (size > sizeof(sa->sun_path)) {
  39. const char *slash = find_last_dir_sep(path);
  40. const char *dir;
  41. struct strbuf cwd = STRBUF_INIT;
  42. if (!slash) {
  43. errno = ENAMETOOLONG;
  44. return -1;
  45. }
  46. dir = path;
  47. path = slash + 1;
  48. size = strlen(path) + 1;
  49. if (size > sizeof(sa->sun_path)) {
  50. errno = ENAMETOOLONG;
  51. return -1;
  52. }
  53. if (strbuf_getcwd(&cwd))
  54. return -1;
  55. ctx->orig_dir = strbuf_detach(&cwd, NULL);
  56. if (chdir_len(dir, slash - dir) < 0)
  57. return -1;
  58. }
  59. memset(sa, 0, sizeof(*sa));
  60. sa->sun_family = AF_UNIX;
  61. memcpy(sa->sun_path, path, size);
  62. return 0;
  63. }
  64. int unix_stream_connect(const char *path)
  65. {
  66. int fd, saved_errno;
  67. struct sockaddr_un sa;
  68. struct unix_sockaddr_context ctx;
  69. if (unix_sockaddr_init(&sa, path, &ctx) < 0)
  70. return -1;
  71. fd = unix_stream_socket();
  72. if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
  73. goto fail;
  74. unix_sockaddr_cleanup(&ctx);
  75. return fd;
  76. fail:
  77. saved_errno = errno;
  78. unix_sockaddr_cleanup(&ctx);
  79. close(fd);
  80. errno = saved_errno;
  81. return -1;
  82. }
  83. int unix_stream_listen(const char *path)
  84. {
  85. int fd, saved_errno;
  86. struct sockaddr_un sa;
  87. struct unix_sockaddr_context ctx;
  88. unlink(path);
  89. if (unix_sockaddr_init(&sa, path, &ctx) < 0)
  90. return -1;
  91. fd = unix_stream_socket();
  92. if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0)
  93. goto fail;
  94. if (listen(fd, 5) < 0)
  95. goto fail;
  96. unix_sockaddr_cleanup(&ctx);
  97. return fd;
  98. fail:
  99. saved_errno = errno;
  100. unix_sockaddr_cleanup(&ctx);
  101. close(fd);
  102. errno = saved_errno;
  103. return -1;
  104. }