#include <sys/time.h>
#include <sys/stat.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <util.h>
#include "util.h"
int verbose = 0;
static void
ignore_alarm(int __unused sig)
{
}
static int
safe_kill(pid_t pid, int sig)
{
int save_errno;
int status;
save_errno = errno;
errno = 0;
status = kill(pid, sig);
errno = save_errno;
return (status);
}
static int
test1(int fd)
{
struct flock fl1, fl2;
memset(&fl1, 1, sizeof(fl1));
fl1.l_type = F_WRLCK;
fl1.l_whence = SEEK_SET;
fl2 = fl1;
if (fcntl(fd, F_GETLK, &fl1) < 0)
err(1, "F_GETLK");
if (verbose) printf("1 - F_GETLK on unlocked region: ");
FAIL(fl1.l_start != fl2.l_start);
FAIL(fl1.l_len != fl2.l_len);
FAIL(fl1.l_pid != fl2.l_pid);
FAIL(fl1.l_type != F_UNLCK);
FAIL(fl1.l_whence != fl2.l_whence);
SUCCEED;
}
static int
test2(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("2 - F_SETLK on locked region: ");
res = fcntl(fd, F_SETLK, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(res == 0);
FAIL(errno != EACCES && errno != EAGAIN);
SUCCEED;
}
static int
test3(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("3 - F_SETLKW on locked region: ");
alarm(1);
res = fcntl(fd, F_SETLKW, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(res == 0);
FAIL(errno != EINTR);
SUCCEED;
}
static int
test4(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 99;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (fcntl(fd, F_GETLK, &fl) < 0)
err(1, "F_GETLK");
if (verbose) printf("4 - F_GETLK on locked region: ");
FAIL(fl.l_start != 0);
FAIL(fl.l_len != 99);
FAIL(fl.l_type != F_WRLCK);
FAIL(fl.l_pid != pid);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
SUCCEED;
}
static int
test5(int fd)
{
int pid;
struct flock fl;
int res;
fl.l_start = 0;
fl.l_len = 1;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK 1 (parent)");
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
fl.l_start = 1;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
fl.l_start = 0;
if (fcntl(fd, F_SETLKW, &fl) < 0)
err(1, "F_SETLKW (child)");
exit(0);
}
sleep(1);
alarm(1);
if (verbose) printf("5 - F_SETLKW simple deadlock: ");
fl.l_start = 1;
res = fcntl(fd, F_SETLKW, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
FAIL(res == 0);
FAIL(errno != EDEADLK);
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_UNLCK");
alarm(0);
SUCCEED;
}
static int
test6(int fd)
{
int pid1, pid2;
struct flock fl;
int res;
fl.l_start = 0;
fl.l_len = 1;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK 1 (parent)");
pid1 = fork();
if (pid1 < 0)
err(1, "fork");
if (pid1 == 0) {
fl.l_start = 1;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child1)");
pause();
exit(0);
}
pid2 = fork();
if (pid2 < 0)
err(1, "fork");
if (pid2 == 0) {
fl.l_start = 2;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child2)");
fl.l_start = 0;
if (fcntl(fd, F_SETLKW, &fl) < 0)
err(1, "F_SETLKW (child2)");
exit(0);
}
sleep(1);
alarm(1);
if (verbose) printf("6 - F_SETLKW complex deadlock: ");
fl.l_start = 1;
fl.l_len = 2;
res = fcntl(fd, F_SETLKW, &fl);
safe_kill(pid1, SIGTERM);
safe_waitpid(pid1);
safe_kill(pid2, SIGTERM);
safe_waitpid(pid2);
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_UNLCK");
FAIL(res == 0);
FAIL(errno != EDEADLK);
alarm(0);
SUCCEED;
}
static int
test7(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("7 - F_SETLK shared lock on exclusive locked region: ");
fl.l_type = F_RDLCK;
res = fcntl(fd, F_SETLK, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(res == 0);
FAIL(errno != EACCES && errno != EAGAIN);
SUCCEED;
}
static int
test8(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("8 - F_SETLK shared lock on share locked region: ");
fl.l_type = F_RDLCK;
res = fcntl(fd, F_SETLK, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_UNLCK");
FAIL(res != 0);
SUCCEED;
}
static int
test9(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("9 - F_SETLK exclusive lock on share locked region: ");
fl.l_type = F_WRLCK;
res = fcntl(fd, F_SETLK, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(res == 0);
FAIL(errno != EACCES && errno != EAGAIN);
SUCCEED;
}
static int
test10(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_pid = 9999;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("10 - trying to set bogus pid or sysid values: ");
if (fcntl(fd, F_GETLK, &fl) < 0)
err(1, "F_GETLK");
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(fl.l_pid != pid);
SUCCEED;
}
static int
test11(int fd)
{
#ifdef F_SETLK_REMOTE
struct flock fl;
int res;
if (geteuid() != 0)
return 0;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_pid = 9999;
fl.l_sysid = 1001;
if (verbose) printf("11 - remote locks: ");
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res != 0);
fl.l_sysid = 1002;
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res == 0);
FAIL(errno != EACCES && errno != EAGAIN);
res = fcntl(fd, F_GETLK, &fl);
FAIL(res != 0);
FAIL(fl.l_pid != 9999);
FAIL(fl.l_sysid != 1001);
fl.l_type = F_UNLCK;
fl.l_sysid = 1001;
fl.l_start = 0;
fl.l_len = 0;
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res != 0);
fl.l_pid = 1234;
fl.l_sysid = 1001;
fl.l_start = 0;
fl.l_len = 1;
fl.l_whence = SEEK_SET;
fl.l_type = F_RDLCK;
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res != 0);
fl.l_sysid = 1002;
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res != 0);
fl.l_type = F_UNLCKSYS;
fl.l_sysid = 1001;
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res != 0);
fl.l_type = F_WRLCK;
res = fcntl(fd, F_GETLK, &fl);
FAIL(res != 0);
FAIL(fl.l_pid != 1234);
FAIL(fl.l_sysid != 1002);
fl.l_type = F_UNLCKSYS;
fl.l_sysid = 1002;
res = fcntl(fd, F_SETLK_REMOTE, &fl);
FAIL(res != 0);
SUCCEED;
#else
return 0;
#endif
}
static int
test12(int fd)
{
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
sleep(1);
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
if (verbose) printf("12 - F_SETLKW on locked region which is then unlocked: ");
res = fcntl(fd, F_SETLKW, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(res != 0);
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_UNLCK");
SUCCEED;
}
static int
test13(int fd)
{
int i;
int pid;
int pfd[2];
struct flock fl;
char ch;
int res;
struct itimerval itv;
if (verbose) printf("13 - F_SETLKW on locked region, race with owner: ");
fflush(stdout);
for (i = 0; i < 100; i++) {
if (pipe(pfd) < 0)
err(1, "pipe");
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_SETLK (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
sleep(1);
exit(0);
}
while (read(pfd[0], &ch, 1) != 1) {
if (errno == EINTR)
continue;
err(1, "reading from pipe (child)");
}
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 2;
setitimer(ITIMER_REAL, &itv, NULL);
res = fcntl(fd, F_SETLKW, &fl);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
close(pfd[0]);
close(pfd[1]);
FAIL(!(res == 0 || (res == -1 && errno == EINTR)));
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "F_UNLCK");
}
SUCCEED;
}
static int
test14(int fd)
{
#define CHILD_COUNT 20
int i, j, id;
int pids[CHILD_COUNT], pid;
char buf[128];
char tbuf[128];
int map[128];
char outbuf[512];
struct flock fl;
struct itimerval itv;
int status;
int id_base = 0;
if (verbose) printf("14 - soak test: ");
fflush(stdout);
for (i = 0; i < 128; i++)
map[i] = F_UNLCK;
for (i = 0; i < CHILD_COUNT; i++) {
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid) {
pids[i] = pid;
continue;
}
id = id_base + i;
for (j = 0; j < 50; j++) {
int start, end, len;
int set, wrlock;
do {
start = arc4random_uniform(128);
end = arc4random_uniform(128);
} while (end <= start);
set = arc4random_uniform(2);
wrlock = arc4random_uniform(2);
len = end - start;
fl.l_start = start;
fl.l_len = len;
fl.l_whence = SEEK_SET;
if (set)
fl.l_type = wrlock ? F_WRLCK : F_RDLCK;
else
fl.l_type = F_UNLCK;
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 3000;
setitimer(ITIMER_REAL, &itv, NULL);
if (fcntl(fd, F_SETLKW, &fl) < 0) {
if (errno == EDEADLK || errno == EINTR) {
if (verbose) {
snprintf(outbuf, sizeof(outbuf),
"%d[%d]: %s [%d .. %d] %s\n",
id, j,
set ? (wrlock ? "write lock"
: "read lock")
: "unlock", start, end,
errno == EDEADLK
? "deadlock"
: "interrupted");
write(1, outbuf,
strlen(outbuf));
}
continue;
} else {
perror("fcntl");
}
}
itv.it_interval.tv_sec = 0;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 0;
itv.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &itv, NULL);
if (verbose) {
snprintf(outbuf, sizeof(outbuf),
"%d[%d]: %s [%d .. %d] succeeded\n",
id, j,
set ? (wrlock ? "write lock" : "read lock")
: "unlock", start, end);
write(1, outbuf, strlen(outbuf));
}
if (set) {
if (wrlock) {
for (i = start; i < end; i++)
map[i] = F_WRLCK;
memset(&buf[start], id, len);
if (pwrite(fd, &buf[start], len,
start) != len) {
printf("%d: short write\n", id);
exit(1);
}
} else {
for (i = start; i < end; i++)
map[i] = F_RDLCK;
if (pread(fd, &buf[start], len,
start) != len) {
printf("%d: short read\n", id);
exit(1);
}
}
} else {
for (i = start; i < end; i++)
map[i] = F_UNLCK;
}
usleep(1000);
if (pread(fd, tbuf, sizeof(tbuf), 0) != sizeof(tbuf)) {
printf("%d: short read\n", id);
exit(1);
}
for (i = 0; i < 128; i++) {
if (map[i] != F_UNLCK && buf[i] != tbuf[i]) {
snprintf(outbuf, sizeof(outbuf),
"%d: byte %d expected %d, "
"got %d\n", id, i, buf[i], tbuf[i]);
write(1, outbuf, strlen(outbuf));
exit(1);
}
}
}
if (verbose)
printf("%d[%d]: done\n", id, j);
exit(0);
}
status = 0;
for (i = 0; i < CHILD_COUNT; i++) {
status += safe_waitpid(pids[i]);
}
if (status)
FAIL(status != 0);
SUCCEED;
}
static int
test15(int fd)
{
#ifdef LOCK_EX
int pid;
int pfd[2];
int fd2;
struct flock fl;
char ch;
int res;
if (pipe(pfd) < 0)
err(1, "pipe");
pid = fork();
if (pid < 0)
err(1, "fork");
if (pid == 0) {
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
if (fcntl(fd, F_SETLK, &fl) < 0)
err(1, "fcntl(F_SETLK) (child)");
if (write(pfd[1], "a", 1) < 0)
err(1, "writing to pipe (child)");
pause();
exit(0);
}
if (read(pfd[0], &ch, 1) != 1)
err(1, "reading from pipe (child)");
fd2 = dup(fd);
FAIL(fd2 == -1);
if (flock(fd, LOCK_SH) < 0)
err(1, "flock shared");
if (verbose) printf("15 - flock(2) semantics: ");
alarm(1);
flock(fd, LOCK_EX);
safe_kill(pid, SIGTERM);
safe_waitpid(pid);
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_GETLK, &fl);
close(pfd[0]);
close(pfd[1]);
FAIL(res != 0);
FAIL(fl.l_type != F_UNLCK);
SUCCEED;
#else
return 0;
#endif
}
static int
test16(int fd)
{
#if 0
struct flock fl;
int res;
fl.l_pid = 0;
fl.l_type = 1;
fl.l_whence = 0;
fl.l_start = 0;
fl.l_len = 0x8000000000000000;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 0x10000;
fl.l_len = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 0;
fl.l_len = 0x8000000000000000;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 0x10000;
fl.l_len = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
#endif
SUCCEED;
}
static int
test17(int fd)
{
struct flock fl;
int nfd, res;
{
nfd = dup(fd);
FAIL(nfd == -1);
fl.l_start = 0;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
close(nfd);
}
{
nfd = dup(fd);
FAIL(nfd == -1);
fl.l_start = 100;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 200;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
close(nfd);
}
{
nfd = dup(fd);
FAIL(nfd == -1);
fl.l_start = 300;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 500;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 400;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
close(nfd);
}
SUCCEED;
}
static int
test18(int fd)
{
struct flock fl;
int res;
fl.l_start = 0;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
SUCCEED;
}
static int
test19(int fd)
{
struct flock fl;
int nfd, res;
{
nfd = dup(fd);
FAIL(nfd == -1);
fl.l_start = 0;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 0;
fl.l_len = 50;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
close(nfd);
}
{
nfd = dup(fd);
FAIL(nfd == -1);
fl.l_start = 100;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 100;
fl.l_len = 50;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
close(nfd);
}
{
nfd = dup(fd);
FAIL(nfd == -1);
fl.l_start = 100;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 110;
fl.l_len = 50;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
close(nfd);
}
SUCCEED;
}
static int
test20(int fd)
{
struct flock fl;
int res;
fl.l_start = 0;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 0;
fl.l_len = 200;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
SUCCEED;
}
static int
test21(int fd)
{
struct flock fl;
int res;
fl.l_start = 0;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 50;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
SUCCEED;
}
static int
test22(int fd)
{
struct flock fl;
int res;
fl.l_start = 10;
fl.l_len = 100;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = 0;
fl.l_len = 50;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = 0;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
SUCCEED;
}
static int
test23(int fd)
{
struct flock fl;
int res;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 2;
fl.l_len = LLONG_MAX;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != -1);
FAIL(errno != EOVERFLOW);
SUCCEED;
}
static int
test24(int fd)
{
struct flock fl;
pid_t pid;
int res, status;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = LLONG_MIN;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != -1);
FAIL(errno != EINVAL);
fl.l_start = 4;
fl.l_len = -2;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
pid = fork();
if (pid == -1)
err(1, "fork");
if (pid == 0) {
fl.l_start = 2;
fl.l_len = 2;
res = fcntl(fd, F_GETLK, &fl);
FAIL(res != 0);
FAIL(fl.l_type == F_UNLCK);
_exit(0);
}
status = safe_waitpid(pid);
FAIL(status != 0);
SUCCEED;
}
static int
test25(int fd)
{
struct flock fl;
int master, res, slave;
res = openpty(&master, &slave, NULL, NULL, NULL);
FAIL(res == -1);
close(master);
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
res = fcntl(slave, F_SETLKW, &fl);
FAIL(res != 0);
fl.l_start = 3;
fl.l_len = 0x7ffffffffffffffd;
fl.l_pid = 0;
fl.l_type = F_UNLCK;
fl.l_whence = SEEK_END;
res = fcntl(slave, F_SETLKW, &fl);
FAIL(res != 0);
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
res = fcntl(slave, F_SETLKW, &fl);
FAIL(res != 0);
close(slave);
SUCCEED;
}
static int
test26(int fd)
{
struct flock fl;
pid_t pid;
int res, status;
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_RDLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
fl.l_start = LLONG_MAX;
fl.l_len = 1;
fl.l_pid = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
pid = fork();
if (pid == -1)
err(1, "fork");
if (pid == 0) {
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_GETLK, &fl);
FAIL(res != 0);
FAIL(fl.l_type != F_RDLCK);
FAIL(fl.l_start != 0);
FAIL(fl.l_len != LLONG_MAX);
fl.l_start = LLONG_MAX;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_GETLK, &fl);
FAIL(res != 0);
FAIL(fl.l_type != F_WRLCK);
FAIL(fl.l_start != LLONG_MAX);
FAIL(fl.l_len != 0);
_exit(0);
}
status = safe_waitpid(pid);
FAIL(status != 0);
fl.l_start = 0;
fl.l_len = 0;
fl.l_pid = 0;
fl.l_type = F_UNLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_SETLK, &fl);
FAIL(res != 0);
pid = fork();
if (pid == -1)
err(1, "fork");
if (pid == 0) {
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
res = fcntl(fd, F_GETLK, &fl);
FAIL(res != 0);
FAIL(fl.l_type != F_UNLCK);
FAIL(fl.l_start != 0);
FAIL(fl.l_len != 0);
_exit(0);
}
status = safe_waitpid(pid);
FAIL(status != 0);
SUCCEED;
}
static struct test tests[] = {
{ test1, 0 },
{ test2, 0 },
{ test3, 1 },
{ test4, 0 },
{ test5, 1 },
{ test6, 1 },
{ test7, 0 },
{ test8, 0 },
{ test9, 0 },
{ test10, 0 },
{ test11, 1 },
{ test12, 0 },
{ test13, 1 },
{ test14, 0 },
{ test15, 1 },
{ test16, 0 },
{ test17, 0 },
{ test18, 0 },
{ test19, 0 },
{ test20, 0 },
{ test21, 0 },
{ test22, 0 },
{ test23, 0 },
{ test24, 0 },
{ test25, 0 },
{ test26, 0 },
};
static int test_count = sizeof(tests) / sizeof(tests[0]);
int
main(int argc, char *argv[])
{
struct sigaction sa;
const char *errstr;
int c, fd, i;
int error = 0;
int testnum = 0;
while ((c = getopt(argc, argv, "v")) != -1)
switch (c) {
case 'v':
verbose = 1;
break;
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 1)
usage();
if (argc == 1) {
testnum = strtonum(argv[0], 1, test_count, &errstr);
if (testnum == 0)
errx(1, "test number %s", errstr);
}
fd = make_file(1024);
sa.sa_handler = ignore_alarm;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGALRM, &sa, 0);
for (i = 0; i < test_count; i++) {
if (testnum == 0 || testnum == i + 1)
error |= tests[i].testfn(fd);
}
return (error ? 1 : 0);
}