diff --git a/src/libeis-socket.c b/src/libeis-socket.c index b57cb9b..8b6e3bc 100644 --- a/src/libeis-socket.c +++ b/src/libeis-socket.c @@ -24,8 +24,11 @@ #include "config.h" #include +#include #include +#include #include +#include #include "util-io.h" #include "util-object.h" @@ -41,6 +44,8 @@ struct eis_socket { struct object object; struct source *listener; char *socketpath; + char *lockpath; + int lockfd; }; static inline struct eis_socket * @@ -54,6 +59,10 @@ eis_socket_destroy(struct eis_socket *socket) { source_remove(socket->listener); socket->listener = source_unref(socket->listener); + if (socket->lockpath) { + unlink(socket->lockpath); + xclose(socket->lockfd); + } if (socket->socketpath) { unlink(socket->socketpath); free(socket->socketpath); @@ -115,6 +124,32 @@ eis_setup_backend_socket(struct eis *eis, const char *socketpath) path = xaprintf("%s/%s", xdg, socketpath); } + /* Create a lockfile first, if that succeeds but the real socket path exists + * it's a leftover from an unclean shutdown and we can remove the old + * socket file. */ + _cleanup_free_ char *lockfile = xaprintf("%s.lock", path); + _cleanup_close_ int lockfd = open(lockfile, O_CREAT|O_CLOEXEC|O_RDWR, + (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)); + int rc = flock(lockfd, LOCK_EX | LOCK_NB); + if (rc < 0) { + log_error(eis, "Failed to create lockfile %s, is another EIS running?", lockfile); + return -errno; + } + + struct stat st; + rc = lstat(path, &st); + if (rc < 0) { + if (errno != ENOENT) { + log_error(eis, "Failed to stat socket path %s (%s)", + path, strerror(errno)); + return -errno; + } + } else if (st.st_mode & (S_IWUSR|S_IWGRP)) { + unlink(path); + } + + /* Lockfile succeeded and path is unlinked (if it existed), let's set + * up the socket */ struct sockaddr_un addr = { .sun_family = AF_UNIX, .sun_path = {0}, @@ -133,16 +168,19 @@ eis_setup_backend_socket(struct eis *eis, const char *socketpath) return -errno; struct source *s = source_new(sockfd, listener_dispatch, eis_socket); - int rc = sink_add_source(eis->sink, s); + rc = sink_add_source(eis->sink, s); if (rc == 0) { eis_socket->listener = source_ref(s); eis_socket->socketpath = steal(&path); + eis_socket->lockpath = steal(&lockfile); + eis_socket->lockfd = lockfd; eis->backend = steal(&eis_socket); eis->backend_interface = interface; } source_unref(s); sockfd = -1; + lockfd = -1; return rc; } diff --git a/tools/eis-demo-server.c b/tools/eis-demo-server.c index 63a4975..6e26ce5 100644 --- a/tools/eis-demo-server.c +++ b/tools/eis-demo-server.c @@ -288,14 +288,13 @@ static void usage(FILE *fp, const char *argv0) { fprintf(fp, - "Usage: %s [--verbose] [--uinput] [--socketpath=/path/to/socket] [--force]\n" + "Usage: %s [--verbose] [--uinput] [--socketpath=/path/to/socket]\n" "\n" "Start an EIS demo server. The server accepts all client connections\n" "and devices and prints any events from the client to stdout.\n" "\n" "Options:\n" " --socketpath Use the given socket path. Default: $XDG_RUNTIME/eis-0\n" - " --force Remove the socket if it already exists\n" " --layout Use the given XKB layout (requires libxkbcommon). Default: none\n" " --uinput Set up each device as uinput device (this requires root)\n" " --verbose Enable debugging output\n" @@ -307,7 +306,6 @@ int main(int argc, char **argv) { bool verbose = false; bool uinput = false; - bool force = false; const char *layout = NULL; _cleanup_unlink_free_ char *socketpath = NULL; @@ -320,14 +318,12 @@ int main(int argc, char **argv) OPT_VERBOSE, OPT_LAYOUT, OPT_SOCKETPATH, - OPT_FORCE, OPT_UINPUT, }; static struct option long_opts[] = { {"socketpath", required_argument, 0, OPT_SOCKETPATH}, {"layout", required_argument, 0, OPT_LAYOUT}, {"uinput", no_argument, 0, OPT_UINPUT}, - {"force", no_argument, 0, OPT_FORCE}, {"verbose", no_argument,0, OPT_VERBOSE}, {"help", no_argument,0, 'h'}, {NULL}, @@ -352,9 +348,6 @@ int main(int argc, char **argv) case OPT_UINPUT: uinput = true; break; - case OPT_FORCE: - force = true; - break; case OPT_VERBOSE: verbose = true; break; @@ -394,9 +387,6 @@ int main(int argc, char **argv) signal(SIGINT, sighandler); - if (force) - unlink(socketpath); - int rc = eis_setup_backend_socket(eis, socketpath); if (rc != 0) { fprintf(stderr, "init failed: %s\n", strerror(errno));