diff options
Diffstat (limited to 'client.c')
-rw-r--r-- | client.c | 62 |
1 files changed, 41 insertions, 21 deletions
@@ -1,4 +1,4 @@ -/* $Id$ */ +/* $OpenBSD$ */ /* * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net> @@ -26,7 +26,7 @@ #include <errno.h> #include <event.h> #include <fcntl.h> -#include <pwd.h> +#include <signal.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -78,13 +78,18 @@ client_get_lock(char *lockfile) 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 @@ client_connect(char *path, int start_server) { 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 @@ client_connect(char *path, int start_server) 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 +258,7 @@ client_main(int argc, char **argv, int flags) return (1); } - /* Initialise the client socket and start the server. */ + /* 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", @@ -292,7 +316,7 @@ client_main(int argc, char **argv, int flags) /* Prepare command for server. */ data->argc = argc; - if (cmd_pack_argv(argc, argv, (char*)(data + 1), size) != 0) { + if (cmd_pack_argv(argc, argv, (char *)(data + 1), size) != 0) { fprintf(stderr, "command too long\n"); free(data); return (1); @@ -374,7 +398,7 @@ client_write_one(enum msgtype type, int fd, const void *buf, size_t len) int retval; retval = imsg_compose(&client_ibuf, type, PROTOCOL_VERSION, -1, fd, - (void*)buf, len); + (void *)buf, len); if (retval != 1) return (-1); return (0); @@ -414,15 +438,11 @@ client_signal(int sig, unused short events, unused void *data) struct sigaction sigact; int status; - if (!client_attached) { - switch (sig) { - case SIGCHLD: - waitpid(WAIT_ANY, &status, WNOHANG); - break; - case SIGTERM: + if (sig == SIGCHLD) + waitpid(WAIT_ANY, &status, WNOHANG); + else if (!client_attached) { + if (sig == SIGTERM) event_loopexit(NULL); - break; - } } else { switch (sig) { case SIGHUP: @@ -474,7 +494,7 @@ client_callback(unused int fd, short events, void *data) } if (events & EV_WRITE) { - if (msgbuf_write(&client_ibuf.w) < 0 && errno != EAGAIN) + if (msgbuf_write(&client_ibuf.w) <= 0 && errno != EAGAIN) goto lost_server; } |