forked from swaywm/swaylock
-
Notifications
You must be signed in to change notification settings - Fork 47
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
167 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
swaylockd(1) | ||
|
||
# NAME | ||
|
||
swaylockd - launch swaylock(1) and re-launch if it dies | ||
|
||
|
||
# SYNOPSIS | ||
|
||
*swaylockd* [options...] | ||
|
||
All options are directly passed to *swaylock(1)*. | ||
|
||
|
||
# DESCRIPTION | ||
|
||
*swaylockd* is a dumb launcher to spawn *swaylock(1)* and ensure it's running no matter what - it immediately restarts *swaylock(1)* if terminated by a signal (e.g. the process crashed) and also blocks all signals (except `SIGKILL` and `SIGSTOP`). | ||
It also ensures that only one instance per user is running (using *flock(2)*). | ||
|
||
*IMPORTANT*: *swaylockd* is not compatible with *swaylock(1)* option *--daemonize*! | ||
|
||
|
||
# ENVIRONMENT | ||
|
||
*XDG_RUNTIME_DIR*: | ||
This variable must be set and contain the path to the existing directory where the lock file will be created. | ||
Refer to "XDG Base Directory Specification" for more information. | ||
|
||
|
||
# FILES | ||
|
||
*${XDG_RUNTIME_DIR}/swaylockd.lock* | ||
A lock file created when *swaylockd* is executed and removed right before it quits. | ||
|
||
|
||
# LOGGING | ||
|
||
Error messages generated by *swaylockd* are printed to STDERR and logged to syslog with ident string "swaylockd" and facility code 1 (user). | ||
|
||
|
||
# HISTORY | ||
|
||
*swaylockd* has been developed mainly as a workaround for the *swaylock(1)* stability issues (see e.g. https://github.com/swaywm/swaylock/issues/181). | ||
|
||
*swaylock* is a critical piece of security software - as a screen locker, any bug in the program that causes it to crash will cause the screen to unlock. | ||
As soon as *swaylock* is no longer running, the screen is no longer locked. | ||
Therefore, great care must be taken to ensure that it never crash. | ||
|
||
*swaylockd* started (and is still available) as a standalone project at https://github.com/jirutka/swaylockd. | ||
The code has been merged into sway-effects. | ||
|
||
|
||
# AUTHORS | ||
|
||
Jakub Jirutka | ||
|
||
|
||
# SEE ALSO | ||
|
||
*swaylock(1)* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// vim: set ts=4: | ||
// SPDX-FileCopyrightText: 2021 Jakub Jirutka <[email protected]> | ||
// SPDX-License-Identifier: MIT | ||
|
||
#define _POSIX_C_SOURCE 200809L | ||
|
||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <limits.h> | ||
#include <spawn.h> | ||
#include <stdbool.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <syslog.h> | ||
#include <unistd.h> | ||
#include <sys/file.h> | ||
#include <sys/wait.h> | ||
|
||
#define PROGNAME "swaylockd" | ||
|
||
#ifndef SWAYLOCK_PATH | ||
#define SWAYLOCK_PATH "/usr/bin/swaylock" | ||
#endif | ||
|
||
#define logerr(format, ...) \ | ||
do { \ | ||
fprintf(stderr, PROGNAME ": " format "\n", __VA_ARGS__); \ | ||
if (syslog_enabled) syslog(LOG_ERR, format, __VA_ARGS__); \ | ||
} while (0) | ||
|
||
|
||
extern char **environ; | ||
|
||
static bool syslog_enabled = true; | ||
|
||
int main (int argc, char **argv) { | ||
char lock_path[PATH_MAX] = "\0"; | ||
int lock_fd = -1; | ||
int rc = 1; | ||
|
||
// Open connection to syslog. | ||
openlog(PROGNAME, LOG_PID, LOG_USER); | ||
|
||
{ | ||
const char *xdg_rd = getenv("XDG_RUNTIME_DIR"); | ||
if (xdg_rd == NULL) { | ||
logerr("%s", "XDG_RUNTIME_DIR not set in the environment"); | ||
return 100; | ||
} | ||
(void) snprintf(lock_path, sizeof(lock_path), "%s/%s.lock", xdg_rd, PROGNAME); | ||
} | ||
|
||
// Obtain exclusive lock. | ||
if ((lock_fd = open(lock_path, O_CREAT | O_RDWR | O_CLOEXEC, 0600)) < 0) { | ||
logerr("failed to write %s: %s", lock_path, strerror(errno)); | ||
return 101; | ||
} | ||
if (flock(lock_fd, LOCK_EX | LOCK_NB) < 0) { | ||
logerr("another instance of %s is running", PROGNAME); | ||
return 102; | ||
} | ||
|
||
// Block (ignore) all signals we can (i.e. except SIGKILL and SIGSTOP). | ||
{ | ||
sigset_t mask; | ||
sigfillset(&mask); | ||
sigprocmask(SIG_SETMASK, &mask, NULL); | ||
} | ||
|
||
argv[0] = SWAYLOCK_PATH; | ||
|
||
for (int i = 1;; i++) { | ||
pid_t pid; | ||
if (posix_spawn(&pid, SWAYLOCK_PATH, NULL, 0, argv, environ) != 0) { | ||
logerr("failed to spawn %s: %s", SWAYLOCK_PATH, strerror(errno)); | ||
rc = 101; | ||
goto done; | ||
} | ||
|
||
int status = -1; | ||
(void) waitpid(pid, &status, 0); | ||
|
||
// Exit only if the child terminated normally, not via signal. | ||
if (WIFEXITED(status)) { | ||
rc = WEXITSTATUS(status); | ||
goto done; | ||
} | ||
logerr("%s terminated with signal %d, restarting (%d)", | ||
SWAYLOCK_PATH, WIFSIGNALED(status) ? WTERMSIG(status) : -1, i); | ||
|
||
// Just to make sure we don't flood syslog in case of some bug... | ||
if (i > 100) syslog_enabled = false; | ||
} | ||
|
||
done: | ||
if (unlink(lock_path) < 0) { | ||
logerr("failed to remove lock file %s: %s", lock_path, strerror(errno)); | ||
} | ||
return rc; | ||
} |