Git fork
at reftables-rust 141 lines 2.9 kB view raw
1#define DISABLE_SIGN_COMPARE_WARNINGS 2 3#include "git-compat-util.h" 4#include "strbuf.h" 5#include "unix-socket.h" 6 7#define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5) 8 9static int chdir_len(const char *orig, int len) 10{ 11 char *path = xmemdupz(orig, len); 12 int r = chdir(path); 13 free(path); 14 return r; 15} 16 17struct unix_sockaddr_context { 18 char *orig_dir; 19}; 20 21static void unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx) 22{ 23 if (!ctx->orig_dir) 24 return; 25 /* 26 * If we fail, we can't just return an error, since we have 27 * moved the cwd of the whole process, which could confuse calling 28 * code. We are better off to just die. 29 */ 30 if (chdir(ctx->orig_dir) < 0) 31 die("unable to restore original working directory"); 32 free(ctx->orig_dir); 33} 34 35static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path, 36 struct unix_sockaddr_context *ctx, 37 int disallow_chdir) 38{ 39 int size = strlen(path) + 1; 40 41 ctx->orig_dir = NULL; 42 if (size > sizeof(sa->sun_path)) { 43 const char *slash; 44 const char *dir; 45 struct strbuf cwd = STRBUF_INIT; 46 47 if (disallow_chdir) { 48 errno = ENAMETOOLONG; 49 return -1; 50 } 51 52 slash = find_last_dir_sep(path); 53 if (!slash) { 54 errno = ENAMETOOLONG; 55 return -1; 56 } 57 58 dir = path; 59 path = slash + 1; 60 size = strlen(path) + 1; 61 if (size > sizeof(sa->sun_path)) { 62 errno = ENAMETOOLONG; 63 return -1; 64 } 65 if (strbuf_getcwd(&cwd)) 66 return -1; 67 ctx->orig_dir = strbuf_detach(&cwd, NULL); 68 if (chdir_len(dir, slash - dir) < 0) { 69 FREE_AND_NULL(ctx->orig_dir); 70 return -1; 71 } 72 } 73 74 memset(sa, 0, sizeof(*sa)); 75 sa->sun_family = AF_UNIX; 76 memcpy(sa->sun_path, path, size); 77 return 0; 78} 79 80int unix_stream_connect(const char *path, int disallow_chdir) 81{ 82 int fd = -1, saved_errno; 83 struct sockaddr_un sa; 84 struct unix_sockaddr_context ctx; 85 86 if (unix_sockaddr_init(&sa, path, &ctx, disallow_chdir) < 0) 87 return -1; 88 fd = socket(AF_UNIX, SOCK_STREAM, 0); 89 if (fd < 0) 90 goto fail; 91 92 if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) 93 goto fail; 94 unix_sockaddr_cleanup(&ctx); 95 return fd; 96 97fail: 98 saved_errno = errno; 99 if (fd != -1) 100 close(fd); 101 unix_sockaddr_cleanup(&ctx); 102 errno = saved_errno; 103 return -1; 104} 105 106int unix_stream_listen(const char *path, 107 const struct unix_stream_listen_opts *opts) 108{ 109 int fd = -1, saved_errno; 110 int backlog; 111 struct sockaddr_un sa; 112 struct unix_sockaddr_context ctx; 113 114 unlink(path); 115 116 if (unix_sockaddr_init(&sa, path, &ctx, opts->disallow_chdir) < 0) 117 return -1; 118 fd = socket(AF_UNIX, SOCK_STREAM, 0); 119 if (fd < 0) 120 goto fail; 121 122 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) 123 goto fail; 124 125 backlog = opts->listen_backlog_size; 126 if (backlog <= 0) 127 backlog = DEFAULT_UNIX_STREAM_LISTEN_BACKLOG; 128 if (listen(fd, backlog) < 0) 129 goto fail; 130 131 unix_sockaddr_cleanup(&ctx); 132 return fd; 133 134fail: 135 saved_errno = errno; 136 if (fd != -1) 137 close(fd); 138 unix_sockaddr_cleanup(&ctx); 139 errno = saved_errno; 140 return -1; 141}