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