Refactor main() - slock - simple X display locker utility
 (HTM) git clone git://git.suckless.org/slock
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 3bb868e40873c568acdec74f7783c77f063aa396
 (DIR) parent a7afade1701a809f6a33b53525d59dd29b38d381
 (HTM) Author: FRIGN <dev@frign.de>
       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(-)
       ---
 (DIR) 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
 (DIR) 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);