abduco

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

commit 277f4d154df9632e215c1ae57080a6dd492fd5d6
parent 91feaaa9f9b3b1183543dba547d7643bf2526cbc
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Thu, 30 Jul 2015 11:14:35 +0200

Improve detection and handling of stale sessions

With this it should be possible to create sessions for which a
dead left over socket still exists. Also the session list as
printed by abduco without any arguments will delete those stale
sockets.

Diffstat:
abduco.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
server.c | 8++++----
2 files changed, 59 insertions(+), 30 deletions(-)

diff --git a/abduco.c b/abduco.c @@ -236,6 +236,34 @@ static bool xsnprintf(char *buf, size_t size, const char *fmt, ...) { return true; } +static int session_connect(const char *name) { + int fd; + if (!set_socket_name(&sockaddr, name) || (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + return -1; + socklen_t socklen = offsetof(struct sockaddr_un, sun_path) + strlen(sockaddr.sun_path) + 1; + if (connect(fd, (struct sockaddr*)&sockaddr, socklen) == -1) { + if (errno == ECONNREFUSED) + unlink(sockaddr.sun_path); + close(fd); + return -1; + } + return fd; +} + +static bool session_exists(const char *name) { + int fd = session_connect(name); + if (fd != -1) + close(fd); + return fd != -1; +} + +static bool session_alive(const char *name) { + struct stat sb; + return session_exists(name) && + stat(sockaddr.sun_path, &sb) == 0 && + S_ISSOCK(sb.st_mode) && (sb.st_mode & S_IXGRP) == 0; +} + static bool create_socket_dir(struct sockaddr_un *sockaddr) { sockaddr->sun_path[0] = '\0'; uid_t uid = getuid(); @@ -348,6 +376,11 @@ static bool create_session(const char *name, char * const argv[]) { char errormsg[255]; struct sigaction sa; + if (session_exists(name)) { + errno = EADDRINUSE; + return false; + } + if (pipe(client_pipe) == -1) return false; if ((server.socket = server_create_socket(name)) == -1) @@ -454,10 +487,7 @@ static bool create_session(const char *name, char * const argv[]) { static bool attach_session(const char *name, const bool terminate) { if (server.socket > 0) close(server.socket); - if (!set_socket_name(&sockaddr, name) || (server.socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - return false; - socklen_t socklen = offsetof(struct sockaddr_un, sun_path) + strlen(sockaddr.sun_path) + 1; - if (connect(server.socket, (struct sockaddr*)&sockaddr, socklen) == -1) + if ((server.socket = session_connect(name)) == -1) return false; if (server_set_socket_non_blocking(server.socket) == -1) return false; @@ -486,21 +516,6 @@ static bool attach_session(const char *name, const bool terminate) { return terminate; } -static bool session_exists(const char *name) { - struct stat sb; - if (!set_socket_name(&sockaddr, name)) - return false; - return stat(sockaddr.sun_path, &sb) == 0 && S_ISSOCK(sb.st_mode); -} - -static bool session_alive(const char *name) { - struct stat sb; - if (!set_socket_name(&sockaddr, name)) - return false; - return stat(sockaddr.sun_path, &sb) == 0 && S_ISSOCK(sb.st_mode) && - (sb.st_mode & S_IXGRP) == 0; -} - static int session_filter(const struct dirent *d) { return strstr(d->d_name, server.host) != NULL; } @@ -528,13 +543,27 @@ static int list_session(void) { if (stat(namelist[n]->d_name, &sb) == 0 && S_ISSOCK(sb.st_mode)) { strftime(buf, sizeof(buf), "%a%t %F %T", localtime(&sb.st_atime)); char status = ' '; - if (sb.st_mode & S_IXUSR) - status = '*'; - else if (sb.st_mode & S_IXGRP) - status = '+'; - char *name = strstr(namelist[n]->d_name, server.host); - if (name) - *name = '\0'; + char *local = strstr(namelist[n]->d_name, server.host); + if (local) { + char *name = strdup(namelist[n]->d_name); + *local = '\0'; /* truncate hostname if we are local */ + if (session_alive(namelist[n]->d_name)) + status = '*'; + else if (session_exists(namelist[n]->d_name)) + status = '+'; + /* check if the socket is still valid, session_{alive,exists} + * might have deleted it */ + if (name && stat(name, &sb) == -1) { + free(name); + continue; + } + free(name); + } else { + if (sb.st_mode & S_IXUSR) + status = '*'; + else if (sb.st_mode & S_IXGRP) + status = '+'; + } printf("%c %s\t%s\n", status, buf, namelist[n]->d_name); } free(namelist[n]); diff --git a/server.c b/server.c @@ -212,8 +212,10 @@ static void server_mainloop(void) { } kill(-server.pid, SIGWINCH); break; - case MSG_DETACH: case MSG_EXIT: + exit_packet_delivered = true; + /* fall through */ + case MSG_DETACH: c->state = STATE_DISCONNECTED; break; default: /* ignore package */ @@ -249,9 +251,7 @@ static void server_mainloop(void) { .u.i = server.exit_status, .len = sizeof(pkt.u.i), }; - if (server_send_packet(c, &pkt)) - exit_packet_delivered = true; - else + if (!server_send_packet(c, &pkt)) FD_SET_MAX(c->socket, &new_writefds, new_fdmax); } else { FD_SET_MAX(c->socket, &new_writefds, new_fdmax);