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