Hi there,

I've came across to the need of a flock(1) utility at work and I've
noticed we don't have any in OpenBSD, it's basically a flock(2)
wrapper that is usefull for running shell commands under a exclusive
and/or shared locks.

I've implemented one that the interface is 90% compatible with the one
found in linux-ng, although the implementation is quite
different. It's not final yet, I've tryed to follow style(9) and I'm
willing to make a port for it. So what do you guys think ? Can it be a
port ?

Any feedback is welcome, here is the code:
==flock.c==
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static int owait, oclose;
static const char *statusfile;

static int getlock(const char *, int, char *[]);
__dead void usage(void);

int
main(int argc, char *argv[])
{
        char **cmdargv, *lockfile;
        int ch, incmd, locktype, onblock;

        ch = incmd = locktype = onblock = owait = oclose = 0;
        cmdargv = NULL;
        if (argc < 2)
                usage();
        while (!incmd && (ch = getopt(argc, argv, "cehonr:suxw:?")) != -1) {
                switch (ch) {
                case 'c':
                        incmd = 1;
                        break;
                case 'e': /* FALLTROUGH */
                case 'x':
                        if (locktype & LOCK_UN || locktype & LOCK_SH)
                                usage();
                        locktype = LOCK_EX;
                        break;
                case 'n':
                        onblock = LOCK_NB;
                        break;
                case 'o':
                        oclose = 1;
                        break;
                case 's':
                        if (locktype & LOCK_UN || locktype & LOCK_EX)
                                usage();
                        locktype = LOCK_SH;
                        break;
                case 'u':
                        if (locktype & LOCK_SH || locktype & LOCK_EX)
                                usage();
                        locktype = LOCK_UN;
                        break;
                case 'w':
                        owait = strtol(optarg, NULL, 10);
                        break;
                case 'r':
                        statusfile = optarg;
                        break;
                case 'h': /* FALLTROUGH */
                default:
                        usage();
                        /* NOTREACHED */
                }
        }
        if ((argc - optind) < 3 || strcmp("-c", *(argv + optind + 1)) != 0)
                usage(); 
        lockfile = *(argv + optind);    
        argc -= optind + 2;
        argv += optind + 2;
        cmdargv = argv;
        if (!locktype)
                locktype = LOCK_EX;

        return getlock(lockfile, locktype | onblock, argv);
}

static int
getlock(const char *lockfile, int type, char *argv[])
{
        int mode, fd, fd_status, chstatus, chreturn;
        pid_t pid;

        mode = type & LOCK_EX ? O_WRONLY | O_CREAT : O_RDONLY | O_CREAT;
        if ((fd = open(lockfile, mode, 0644)) < 0)
                err(1, "Can't open %s", lockfile);
        if (owait)
                alarm(owait);
        if (flock(fd, type) < 0)
                return 1;
        /* We should have the lock by now */
        if ((pid = fork()) < 0)
                err(1, "fork error");
        else if(pid > 0) {/* parent */
                if (waitpid(pid, &chstatus, 0) < 0)
                        err(1, "waitpid error");
                if (statusfile && WIFEXITED(chstatus)) {
                        char buf[8];
                        
                        if ((fd_status = open(statusfile,
                                              O_CREAT | O_WRONLY,
                                              0644)) <  0) {
                                err(1, "Can't open %s", statusfile);
                        }
                        chreturn = WEXITSTATUS(chstatus);
                        snprintf(buf, sizeof(buf), "%d", chreturn);
                        if (write(fd_status, buf, strlen(buf)) < 0)
                                err(1, "write error");
                }
        }
        else  {/* child */
                if(oclose)
                        close(fd);
                return execvp(*argv, argv);
        }
        
        return 0;
}d

__dead void
usage(void)
{
        errx(1, "usage: flock [-sexu] [-no] [-r file] [-w seconds] -c command");
        /* NOTREACHED */
}
==end flock.c==

-- 
Christiano Farina HAESBAERT

Reply via email to