t7501: add tests for --amend --signoff
[alt-git.git] / unix-stream-server.c
blob22ac2373e0788d9a0c7f377b86a756e5ef4ee518
1 #include "git-compat-util.h"
2 #include "lockfile.h"
3 #include "unix-socket.h"
4 #include "unix-stream-server.h"
6 #define DEFAULT_LOCK_TIMEOUT (100)
8 /*
9 * Try to connect to a unix domain socket at `path` (if it exists) and
10 * see if there is a server listening.
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.
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.
21 static int is_another_server_alive(const char *path,
22 const struct unix_stream_listen_opts *opts)
24 int fd = unix_stream_connect(path, opts->disallow_chdir);
25 if (fd >= 0) {
26 close(fd);
27 return 1;
30 return 0;
33 int 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)
38 struct lock_file lock = LOCK_INIT;
39 int fd_socket;
40 struct unix_ss_socket *server_socket;
42 *new_server_socket = NULL;
44 if (timeout_ms < 0)
45 timeout_ms = DEFAULT_LOCK_TIMEOUT;
48 * Create a lock at "<path>.lock" if we can.
50 if (hold_lock_file_for_update_timeout(&lock, path, 0, timeout_ms) < 0)
51 return -1;
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.
57 if (is_another_server_alive(path, opts)) {
58 rollback_lock_file(&lock);
59 errno = EADDRINUSE;
60 return -2;
64 * Create and bind to a Unix domain socket at "<path>".
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;
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);
79 *new_server_socket = server_socket;
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.
86 rollback_lock_file(&lock);
88 return 0;
91 void unix_ss_free(struct unix_ss_socket *server_socket)
93 if (!server_socket)
94 return;
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);
102 free(server_socket->path_socket);
103 free(server_socket);
106 int unix_ss_was_stolen(struct unix_ss_socket *server_socket)
108 struct stat st_now;
110 if (!server_socket)
111 return 0;
113 if (lstat(server_socket->path_socket, &st_now) == -1)
114 return 1;
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;
121 if (!S_ISSOCK(st_now.st_mode))
122 return 1;
124 return 0;