=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/client.c,v retrieving revision 1.81 retrieving revision 1.82 diff -u -r1.81 -r1.82 --- src/usr.bin/tmux/client.c 2014/07/13 20:51:08 1.81 +++ src/usr.bin/tmux/client.c 2014/07/21 10:52:48 1.82 @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.81 2014/07/13 20:51:08 krw Exp $ */ +/* $OpenBSD: client.c,v 1.82 2014/07/21 10:52:48 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -77,13 +77,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); } @@ -94,8 +99,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; @@ -104,29 +109,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); } @@ -233,17 +257,17 @@ return (1); } - /* Initialise the client socket and start the server. */ + /* Set process title, log and signals now this is the client. */ + setproctitle("client (%s)", socket_path); + 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", strerror(errno)); return (1); } - - /* Set process title, log and signals now this is the client. */ - setproctitle("client (%s)", socket_path); - logfile("client"); /* Create imsg. */ imsg_init(&client_ibuf, fd);