]> git.ipfire.org Git - thirdparty/git.git/blame - unix-stream-server.c
reftable: read reftable files
[thirdparty/git.git] / unix-stream-server.c
CommitLineData
9fd19027
JH
1#include "cache.h"
2#include "lockfile.h"
3#include "unix-socket.h"
4#include "unix-stream-server.h"
5
6#define DEFAULT_LOCK_TIMEOUT (100)
7
8/*
9 * Try to connect to a unix domain socket at `path` (if it exists) and
10 * see if there is a server listening.
11 *
12 * We don't know if the socket exists, whether a server died and
13 * failed to cleanup, or whether we have a live server listening, so
14 * we "poke" it.
15 *
16 * We immediately hangup without sending/receiving any data because we
17 * don't know anything about the protocol spoken and don't want to
18 * block while writing/reading data. It is sufficient to just know
19 * that someone is listening.
20 */
21static int is_another_server_alive(const char *path,
22 const struct unix_stream_listen_opts *opts)
23{
24 int fd = unix_stream_connect(path, opts->disallow_chdir);
25 if (fd >= 0) {
26 close(fd);
27 return 1;
28 }
29
30 return 0;
31}
32
33int unix_ss_create(const char *path,
34 const struct unix_stream_listen_opts *opts,
35 long timeout_ms,
36 struct unix_ss_socket **new_server_socket)
37{
38 struct lock_file lock = LOCK_INIT;
39 int fd_socket;
40 struct unix_ss_socket *server_socket;
41
42 *new_server_socket = NULL;
43
44 if (timeout_ms < 0)
45 timeout_ms = DEFAULT_LOCK_TIMEOUT;
46
47 /*
48 * Create a lock at "<path>.lock" if we can.
49 */
50 if (hold_lock_file_for_update_timeout(&lock, path, 0, timeout_ms) < 0)
51 return -1;
52
53 /*
54 * If another server is listening on "<path>" give up. We do not
55 * want to create a socket and steal future connections from them.
56 */
57 if (is_another_server_alive(path, opts)) {
58 rollback_lock_file(&lock);
59 errno = EADDRINUSE;
60 return -2;
61 }
62
63 /*
64 * Create and bind to a Unix domain socket at "<path>".
65 */
66 fd_socket = unix_stream_listen(path, opts);
67 if (fd_socket < 0) {
68 int saved_errno = errno;
69 rollback_lock_file(&lock);
70 errno = saved_errno;
71 return -1;
72 }
73
74 server_socket = xcalloc(1, sizeof(*server_socket));
75 server_socket->path_socket = strdup(path);
76 server_socket->fd_socket = fd_socket;
77 lstat(path, &server_socket->st_socket);
78
79 *new_server_socket = server_socket;
80
81 /*
82 * Always rollback (just delete) "<path>.lock" because we already created
83 * "<path>" as a socket and do not want to commit_lock to do the atomic
84 * rename trick.
85 */
86 rollback_lock_file(&lock);
87
88 return 0;
89}
90
91void unix_ss_free(struct unix_ss_socket *server_socket)
92{
93 if (!server_socket)
94 return;
95
96 if (server_socket->fd_socket >= 0) {
97 if (!unix_ss_was_stolen(server_socket))
98 unlink(server_socket->path_socket);
99 close(server_socket->fd_socket);
100 }
101
102 free(server_socket->path_socket);
103 free(server_socket);
104}
105
106int unix_ss_was_stolen(struct unix_ss_socket *server_socket)
107{
108 struct stat st_now;
109
110 if (!server_socket)
111 return 0;
112
113 if (lstat(server_socket->path_socket, &st_now) == -1)
114 return 1;
115
116 if (st_now.st_ino != server_socket->st_socket.st_ino)
117 return 1;
118 if (st_now.st_dev != server_socket->st_socket.st_dev)
119 return 1;
120
121 if (!S_ISSOCK(st_now.st_mode))
122 return 1;
123
124 return 0;
125}