]>
Commit | Line | Data |
---|---|---|
41f43b82 PS |
1 | #define DISABLE_SIGN_COMPARE_WARNINGS |
2 | ||
fc7bd51b EN |
3 | #include "git-compat-util.h" |
4 | #include "strbuf.h" | |
e2770979 JK |
5 | #include "unix-socket.h" |
6 | ||
55144ccb JH |
7 | #define DEFAULT_UNIX_STREAM_LISTEN_BACKLOG (5) |
8 | ||
1eb10f40 JK |
9 | static 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 | ||
17 | struct unix_sockaddr_context { | |
d13a0a97 | 18 | char *orig_dir; |
1eb10f40 JK |
19 | }; |
20 | ||
21 | static void unix_sockaddr_cleanup(struct unix_sockaddr_context *ctx) | |
22 | { | |
d13a0a97 | 23 | if (!ctx->orig_dir) |
1eb10f40 JK |
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"); | |
d13a0a97 | 32 | free(ctx->orig_dir); |
1eb10f40 JK |
33 | } |
34 | ||
35 | static int unix_sockaddr_init(struct sockaddr_un *sa, const char *path, | |
77e522ca JH |
36 | struct unix_sockaddr_context *ctx, |
37 | int disallow_chdir) | |
e2770979 JK |
38 | { |
39 | int size = strlen(path) + 1; | |
1eb10f40 | 40 | |
d13a0a97 | 41 | ctx->orig_dir = NULL; |
1eb10f40 | 42 | if (size > sizeof(sa->sun_path)) { |
77e522ca | 43 | const char *slash; |
1eb10f40 | 44 | const char *dir; |
d13a0a97 | 45 | struct strbuf cwd = STRBUF_INIT; |
1eb10f40 | 46 | |
77e522ca JH |
47 | if (disallow_chdir) { |
48 | errno = ENAMETOOLONG; | |
49 | return -1; | |
50 | } | |
51 | ||
52 | slash = find_last_dir_sep(path); | |
1eb10f40 JK |
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 | } | |
d13a0a97 | 65 | if (strbuf_getcwd(&cwd)) |
1eb10f40 | 66 | return -1; |
d13a0a97 | 67 | ctx->orig_dir = strbuf_detach(&cwd, NULL); |
c5fe29f6 PS |
68 | if (chdir_len(dir, slash - dir) < 0) { |
69 | FREE_AND_NULL(ctx->orig_dir); | |
1eb10f40 | 70 | return -1; |
c5fe29f6 | 71 | } |
1eb10f40 JK |
72 | } |
73 | ||
e2770979 JK |
74 | memset(sa, 0, sizeof(*sa)); |
75 | sa->sun_family = AF_UNIX; | |
76 | memcpy(sa->sun_path, path, size); | |
1eb10f40 | 77 | return 0; |
e2770979 JK |
78 | } |
79 | ||
77e522ca | 80 | int unix_stream_connect(const char *path, int disallow_chdir) |
e2770979 | 81 | { |
4f98ce58 | 82 | int fd = -1, saved_errno; |
e2770979 | 83 | struct sockaddr_un sa; |
1eb10f40 | 84 | struct unix_sockaddr_context ctx; |
e2770979 | 85 | |
77e522ca | 86 | if (unix_sockaddr_init(&sa, path, &ctx, disallow_chdir) < 0) |
1eb10f40 | 87 | return -1; |
4f98ce58 JH |
88 | fd = socket(AF_UNIX, SOCK_STREAM, 0); |
89 | if (fd < 0) | |
90 | goto fail; | |
91 | ||
06121a0a JN |
92 | if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) |
93 | goto fail; | |
1eb10f40 | 94 | unix_sockaddr_cleanup(&ctx); |
e2770979 | 95 | return fd; |
06121a0a JN |
96 | |
97 | fail: | |
98 | saved_errno = errno; | |
4f98ce58 JH |
99 | if (fd != -1) |
100 | close(fd); | |
06121a0a | 101 | unix_sockaddr_cleanup(&ctx); |
06121a0a JN |
102 | errno = saved_errno; |
103 | return -1; | |
e2770979 JK |
104 | } |
105 | ||
55144ccb JH |
106 | int unix_stream_listen(const char *path, |
107 | const struct unix_stream_listen_opts *opts) | |
e2770979 | 108 | { |
4f98ce58 | 109 | int fd = -1, saved_errno; |
55144ccb | 110 | int backlog; |
e2770979 | 111 | struct sockaddr_un sa; |
1eb10f40 | 112 | struct unix_sockaddr_context ctx; |
e2770979 | 113 | |
2869b3e5 RS |
114 | unlink(path); |
115 | ||
77e522ca | 116 | if (unix_sockaddr_init(&sa, path, &ctx, opts->disallow_chdir) < 0) |
1eb10f40 | 117 | return -1; |
4f98ce58 JH |
118 | fd = socket(AF_UNIX, SOCK_STREAM, 0); |
119 | if (fd < 0) | |
120 | goto fail; | |
e2770979 | 121 | |
06121a0a JN |
122 | if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) |
123 | goto fail; | |
e2770979 | 124 | |
55144ccb JH |
125 | backlog = opts->listen_backlog_size; |
126 | if (backlog <= 0) | |
127 | backlog = DEFAULT_UNIX_STREAM_LISTEN_BACKLOG; | |
128 | if (listen(fd, backlog) < 0) | |
06121a0a | 129 | goto fail; |
e2770979 | 130 | |
1eb10f40 | 131 | unix_sockaddr_cleanup(&ctx); |
e2770979 | 132 | return fd; |
06121a0a JN |
133 | |
134 | fail: | |
135 | saved_errno = errno; | |
4f98ce58 JH |
136 | if (fd != -1) |
137 | close(fd); | |
06121a0a | 138 | unix_sockaddr_cleanup(&ctx); |
06121a0a JN |
139 | errno = saved_errno; |
140 | return -1; | |
e2770979 | 141 | } |