#include "util.h"
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/file.h>
#include <unistd.h>
static void acq_fcntl(int, int, int);
static void acq_flock(int fd, int mode);
static void acq_run(int, lock_style_t, boolean_t);
static void
acq_fcntl(int fd, int cmd, int mode)
{
struct flock fl;
int ret, i;
for (i = 0; i < 3; i++) {
flock_reinit(&fl, mode);
flock_log("Acquiring lock (fcntl)...\n");
ret = fcntl(fd, cmd, &fl);
if (ret == -1) {
err(EXIT_FAILURE, "fcntl failed");
}
}
flock_log("Waiting (fcntl)...\n");
flock_alert(1);
flock_block(0);
flock_reinit(&fl, F_UNLCK);
flock_log("Releasing lock (fcntl)...\n");
ret = fcntl(fd, cmd, &fl);
if (ret == -1) {
err(EXIT_FAILURE, "fcntl failed");
}
}
static void
acq_flock(int fd, int mode)
{
int ret, i;
for (i = 0; i < 3; i++) {
flock_log("Acquiring lock (flock)...\n");
ret = flock(fd, mode);
if (ret == -1) {
err(EXIT_FAILURE, "flock failed");
}
}
flock_log("Waiting (flock)...\n");
flock_alert(1);
flock_block(0);
flock_log("Releasing lock (flock)...\n");
ret = flock(fd, LOCK_UN);
if (ret == -1) {
err(EXIT_FAILURE, "flock failed");
}
}
static void
acq_run(int fd, lock_style_t style, boolean_t is_exclusive)
{
switch (style) {
case LSTYLE_POSIX:
acq_fcntl(fd, F_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK);
break;
case LSTYLE_OFD:
acq_fcntl(fd, F_OFD_SETLKW, is_exclusive ? F_WRLCK : F_RDLCK);
break;
case LSTYLE_FLOCK:
acq_flock(fd, is_exclusive ? LOCK_EX : LOCK_SH);
break;
default:
abort();
}
}
int
main(int argc, char *argv[])
{
char *modestr, *path;
lock_style_t style;
boolean_t is_exclusive;
int fd;
if (argc < 4) {
errx(EXIT_FAILURE, BAD_ARGS_MESSAGE, argc - 1);
}
modestr = argv[2];
path = argv[3];
style = flock_styleenum(argv[1]);
if (strcmp(modestr, "shared") == 0) {
is_exclusive = B_FALSE;
} else if (strcmp(modestr, "exclusive") == 0) {
is_exclusive = B_TRUE;
} else {
errx(EXIT_FAILURE, BAD_MODE_MESSAGE);
}
boolean_t rdonly = style == LSTYLE_FLOCK || !is_exclusive;
fd = open(path, rdonly ? O_RDONLY : O_WRONLY);
if (fd == -1) {
err(EXIT_FAILURE, "Failed to open %s", path);
}
acq_run(fd, style, is_exclusive);
return (0);
}