Package: tmux / 1.9-6

upstream-8e4ae12b4d.diff Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
commit 8e4ae12b4d0559a827f740f60b11f386f27f89dd
Author: nicm <nicm>
Date:   Mon Jul 21 10:52:48 2014 +0000

    lockf is entirely useless and it was a mistake to change to it, go back
    to using flock which actually works sensibly. Also always retry the lock
    to fix a potential race, and add some extra logging.

--- a/client.c
+++ b/client.c
@@ -78,13 +78,18 @@
 
 	if ((lockfd = open(lockfile, O_WRONLY|O_CREAT, 0600)) == -1)
 		fatal("open failed");
+	log_debug("lock file is %s", lockfile);
 
-	if (lockf(lockfd, F_TLOCK, 0) == -1 && errno == EAGAIN) {
-		while (lockf(lockfd, F_LOCK, 0) == -1 && errno == EINTR)
+	if (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
+		log_debug("flock failed: %s", strerror(errno));
+		if (errno != EAGAIN)
+			return (lockfd);
+		while (flock(lockfd, LOCK_EX) == -1 && errno == EINTR)
 			/* nothing */;
 		close(lockfd);
 		return (-1);
 	}
+	log_debug("flock succeeded");
 
 	return (lockfd);
 }
@@ -95,8 +100,8 @@
 {
 	struct sockaddr_un	sa;
 	size_t			size;
-	int			fd, lockfd;
-	char		       *lockfile;
+	int			fd, lockfd = -1, locked = 0;
+	char		       *lockfile = NULL;
 
 	memset(&sa, 0, sizeof sa);
 	sa.sun_family = AF_UNIX;
@@ -105,29 +110,48 @@
 		errno = ENAMETOOLONG;
 		return (-1);
 	}
+	log_debug("socket is %s", path);
 
 retry:
 	if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
 		fatal("socket failed");
 
+	log_debug("trying connect");
 	if (connect(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
+		log_debug("connect failed: %s", strerror(errno));
 		if (errno != ECONNREFUSED && errno != ENOENT)
 			goto failed;
 		if (!start_server)
 			goto failed;
 		close(fd);
 
-		xasprintf(&lockfile, "%s.lock", path);
-		if ((lockfd = client_get_lock(lockfile)) == -1) {
-			free(lockfile);
+		if (!locked) {
+			xasprintf(&lockfile, "%s.lock", path);
+			if ((lockfd = client_get_lock(lockfile)) == -1) {
+				log_debug("didn't get lock");
+				free(lockfile);
+				goto retry;
+			}
+			log_debug("got lock");
+
+			/*
+			 * Always retry at least once, even if we got the lock,
+			 * because another client could have taken the lock,
+			 * started the server and released the lock between our
+			 * connect() and flock().
+			 */
+			locked = 1;
 			goto retry;
 		}
+
 		if (unlink(path) != 0 && errno != ENOENT) {
 			free(lockfile);
 			close(lockfd);
 			return (-1);
 		}
 		fd = server_start(lockfd, lockfile);
+	}
+	if (locked) {
 		free(lockfile);
 		close(lockfd);
 	}
@@ -234,7 +234,13 @@
 		return (1);
 	}
 
-	/* Initialise the client socket and start the server. */
+	/* Set process title, log and signals now this is the client. */
+#ifdef HAVE_SETPROCTITLE
+	setproctitle("client (%s)", socket_path);
+#endif
+	logfile("client");
+
+	/* Initialize the client socket and start the server. */
 	fd = client_connect(socket_path, cmdflags & CMD_STARTSERVER);
 	if (fd == -1) {
 		fprintf(stderr, "failed to connect to server: %s\n",
@@ -242,12 +248,6 @@
 		return (1);
 	}
 
-	/* Set process title, log and signals now this is the client. */
-#ifdef HAVE_SETPROCTITLE
-	setproctitle("client (%s)", socket_path);
-#endif
-	logfile("client");
-
 	/* Create imsg. */
 	imsg_init(&client_ibuf, fd);
 	event_set(&client_event, fd, EV_READ, client_callback, shell_cmd);
--- a/server.c
+++ b/server.c
@@ -112,6 +112,7 @@
 	/* The first client is special and gets a socketpair; create it. */
 	if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0)
 		fatal("socketpair failed");
+	log_debug("starting server");
 
 	switch (fork()) {
 	case -1: