fork
Configure Feed
Select the types of activity you want to include in your feed.
Git fork
fork
Configure Feed
Select the types of activity you want to include in your feed.
1#include "git-compat-util.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}