Refactor main() - slock - simple X display locker utility | |
git clone git://git.suckless.org/slock | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 3bb868e40873c568acdec74f7783c77f063aa396 | |
parent a7afade1701a809f6a33b53525d59dd29b38d381 | |
Author: FRIGN <[email protected]> | |
Date: Mon, 22 Aug 2016 00:25:21 +0200 | |
Refactor main() | |
- Add arg.h and fix usage | |
Given slock is suid we don't want to have half-measures in place to | |
parse the arguments in case the code is changed in the future with | |
somebody not paying enough attention. | |
Also, fix the usage string output to be more consistent across the | |
suckless toolbase and make it reflect the manpage entry. | |
- Comments | |
Use proper block comments and add/change them where necessary | |
to help in studying the code. | |
- Error messages | |
Consistently prepend them with "slock:" and fix wording and | |
do a proper cleanup before quitting (XCloseDisplay and free | |
the locks), making the die() semantics consistent with st's. | |
- getpwuid() error reporting | |
Properly present an error message if getpwuid() fails. | |
- fork() error reporting | |
Properly present an error message if fork() fails. If we cannot | |
close the connection within the fork context we abort the | |
operation and report an error. | |
- execvp() error handling | |
If execvp fails, we cannot call die() afterwards as this implies | |
calling exit(). We must use _exit() to prevent the libc from | |
doing now "illegal" cleanup-work. | |
Diffstat: | |
A arg.h | 65 +++++++++++++++++++++++++++++… | |
M slock.c | 85 ++++++++++++++++++++---------… | |
2 files changed, 119 insertions(+), 31 deletions(-) | |
--- | |
diff --git a/arg.h b/arg.h | |
@@ -0,0 +1,65 @@ | |
+/* | |
+ * Copy me if you can. | |
+ * by 20h | |
+ */ | |
+ | |
+#ifndef ARG_H__ | |
+#define ARG_H__ | |
+ | |
+extern char *argv0; | |
+ | |
+/* use main(int argc, char *argv[]) */ | |
+#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ | |
+ argv[0] && argv[0][0] == '-'\ | |
+ && argv[0][1];\ | |
+ argc--, argv++) {\ | |
+ char argc_;\ | |
+ char **argv_;\ | |
+ int brk_;\ | |
+ if (argv[0][1] == '-' && argv[0][2] == '\0') {\ | |
+ argv++;\ | |
+ argc--;\ | |
+ break;\ | |
+ }\ | |
+ for (brk_ = 0, argv[0]++, argv_ = argv;\ | |
+ argv[0][0] && !brk_;\ | |
+ argv[0]++) {\ | |
+ if (argv_ != argv)\ | |
+ break;\ | |
+ argc_ = argv[0][0];\ | |
+ switch (argc_) | |
+ | |
+/* Handles obsolete -NUM syntax */ | |
+#define ARGNUM case '0':\ | |
+ case '1':\ | |
+ case '2':\ | |
+ case '3':\ | |
+ case '4':\ | |
+ case '5':\ | |
+ case '6':\ | |
+ case '7':\ | |
+ case '8':\ | |
+ case '9' | |
+ | |
+#define ARGEND }\ | |
+ } | |
+ | |
+#define ARGC() argc_ | |
+ | |
+#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) | |
+ | |
+#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ | |
+ ((x), abort(), (char *)0) :\ | |
+ (brk_ = 1, (argv[0][1] != '\0')?\ | |
+ (&argv[0][1]) :\ | |
+ (argc--, argv++, argv[0]))) | |
+ | |
+#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ | |
+ (char *)0 :\ | |
+ (brk_ = 1, (argv[0][1] != '\0')?\ | |
+ (&argv[0][1]) :\ | |
+ (argc--, argv++, argv[0]))) | |
+ | |
+#define LNGARG() &argv[0][0] | |
+ | |
+#endif | |
diff --git a/slock.c b/slock.c | |
@@ -23,8 +23,11 @@ | |
#include <bsd_auth.h> | |
#endif | |
+#include "arg.h" | |
#include "util.h" | |
+char *argv0; | |
+ | |
enum { | |
INIT, | |
INPUT, | |
@@ -54,7 +57,6 @@ die(const char *errstr, ...) | |
{ | |
va_list ap; | |
- fputs("slock: ", stderr); | |
va_start(ap, errstr); | |
vfprintf(stderr, errstr, ap); | |
va_end(ap); | |
@@ -280,8 +282,7 @@ lockscreen(Display *dpy, int screen) | |
static void | |
usage(void) | |
{ | |
- fprintf(stderr, "usage: slock [-v|POST_LOCK_CMD]\n"); | |
- exit(1); | |
+ die("usage: slock [-v | cmd [arg ...]]\n"); | |
} | |
int | |
@@ -290,64 +291,86 @@ main(int argc, char **argv) { | |
const char *pws; | |
#endif | |
Display *dpy; | |
- int screen; | |
+ int s, nlocks; | |
- if ((argc >= 2) && !strcmp("-v", argv[1])) | |
- die("version %s, © 2006-2016 slock engineers\n", VERSION); | |
- | |
- /* treat first argument starting with a '-' as option */ | |
- if ((argc >= 2) && argv[1][0] == '-') | |
+ ARGBEGIN { | |
+ case 'v': | |
+ fprintf(stderr, "slock-"VERSION"\n"); | |
+ return 0; | |
+ default: | |
usage(); | |
+ } ARGEND | |
#ifdef __linux__ | |
dontkillme(); | |
#endif | |
- if (!getpwuid(getuid())) | |
- die("no passwd entry for you\n"); | |
+ /* Check if the current user has a password entry */ | |
+ errno = 0; | |
+ if (!getpwuid(getuid())) { | |
+ if (errno == 0) | |
+ die("slock: no password entry for current user\n"); | |
+ else | |
+ die("slock: getpwuid: %s\n", strerror(errno)); | |
+ } | |
#ifndef HAVE_BSD_AUTH | |
pws = getpw(); | |
#endif | |
- if (!(dpy = XOpenDisplay(0))) | |
- die("cannot open display\n"); | |
+ if (!(dpy = XOpenDisplay(NULL))) | |
+ die("slock: cannot open display\n"); | |
+ | |
+ /* check for Xrandr support */ | |
rr = XRRQueryExtension(dpy, &rrevbase, &rrerrbase); | |
- /* Get the number of screens in display "dpy" and blank them all. */ | |
+ | |
+ /* get number of screens in display "dpy" and blank them */ | |
nscreens = ScreenCount(dpy); | |
- if (!(locks = malloc(sizeof(Lock*) * nscreens))) | |
- die("Out of memory.\n"); | |
- int nlocks = 0; | |
- for (screen = 0; screen < nscreens; screen++) { | |
- if ((locks[screen] = lockscreen(dpy, screen)) != NULL) | |
+ if (!(locks = malloc(sizeof(Lock *) * nscreens))) { | |
+ XCloseDisplay(dpy); | |
+ die("slock: out of memory\n"); | |
+ } | |
+ for (nlocks = 0, s = 0; s < nscreens; s++) { | |
+ if ((locks[s] = lockscreen(dpy, s)) != NULL) | |
nlocks++; | |
} | |
- XSync(dpy, False); | |
+ XSync(dpy, 0); | |
- /* Did we actually manage to lock something? */ | |
- if (nlocks == 0) { /* nothing to protect */ | |
+ /* did we actually manage to lock anything? */ | |
+ if (nlocks == 0) { | |
+ /* nothing to protect */ | |
free(locks); | |
XCloseDisplay(dpy); | |
return 1; | |
} | |
- if (argc >= 2 && fork() == 0) { | |
- if (dpy) | |
- close(ConnectionNumber(dpy)); | |
- execvp(argv[1], argv+1); | |
- die("execvp %s failed: %s\n", argv[1], strerror(errno)); | |
+ /* run post-lock command */ | |
+ if (argc > 0) { | |
+ switch (fork()) { | |
+ case -1: | |
+ free(locks); | |
+ XCloseDisplay(dpy); | |
+ die("slock: fork failed: %s\n", strerror(errno)); | |
+ case 0: | |
+ if (close(ConnectionNumber(dpy)) < 0) | |
+ die("slock: close: %s\n", strerror(errno)); | |
+ execvp(argv[0], argv); | |
+ fprintf(stderr, "slock: execvp %s: %s\n", argv[0], | |
+ strerror(errno)); | |
+ _exit(1); | |
+ } | |
} | |
- /* Everything is now blank. Now wait for the correct password. */ | |
+ /* everything is now blank. Wait for the correct password */ | |
#ifdef HAVE_BSD_AUTH | |
readpw(dpy); | |
#else | |
readpw(dpy, pws); | |
#endif | |
- /* Password ok, unlock everything and quit. */ | |
- for (screen = 0; screen < nscreens; screen++) | |
- unlockscreen(dpy, locks[screen]); | |
+ /* password ok, unlock everything and quit */ | |
+ for (s = 0; s < nscreens; s++) | |
+ unlockscreen(dpy, locks[s]); | |
free(locks); | |
XCloseDisplay(dpy); |