mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2025-12-28 15:30:07 +01:00
eis: use a lockfile to determine whether we can remove the old socket
Same approach as libwayland-server Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
225e001c55
commit
014c0ce081
2 changed files with 40 additions and 12 deletions
|
|
@ -24,8 +24,11 @@
|
|||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue