/*-
 * Copyright (c) 2003 Networks Associates Technology, Inc.
 * All rights reserved.
 *
 * This software was developed for the FreeBSD Project by and Network
 * Associates Laboratories, the Security Research Division of Network
 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
 * as part of the DARPA CHATS research program.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD$
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/file.h>

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

static void
usage(void)
{

	fprintf(stderr, "locktest "
	    "[create|nocreate] "
	    "[openexlock|openshlock|noopenlock] "
	    "[block|nonblock] "
	    "[exflock|shflock|noflock] "
	    "filename "
	    "sleeplen\n");
	exit(-1);
}

int
main(int argc, char *argv[])
{
	int error, fd, flags;
	time_t t;
	pid_t pid;

	pid = getpid();

	if (argc != 7)
		usage();

	if (strcmp(argv[1], "create") != 0 &&
	    strcmp(argv[1], "nocreate") != 0)
		usage();

	if (strcmp(argv[2], "openexlock") != 0 &&
	    strcmp(argv[2], "openshlock") != 0 &&
	    strcmp(argv[2], "noopenlock") != 0)
		usage();

	if (strcmp(argv[3], "block") != 0 &&
	    strcmp(argv[3], "nonblock") != 0)
		usage();

	if (strcmp(argv[4], "exflock") != 0 &&
	    strcmp(argv[4], "shflock") != 0 &&
	    strcmp(argv[4], "noflock") != 0)
		usage();

	flags = 0;
	if (strcmp(argv[1], "create") == 0) {
		/* printf("O_CREAT\n"); */
		flags |= O_CREAT;
	}
	if (strcmp(argv[2], "openexlock") == 0) {
		/* printf("O_EXLOCK\n"); */
		flags |= O_EXLOCK;
	} else if (strcmp(argv[2], "openshlock") == 0) {
		/* printf("O_SHLOCK\n"); */
		flags |= O_SHLOCK;
	}
	if (strcmp(argv[3], "nonblock") == 0) {
		/* printf("O_NONBLOCK\n"); */
		flags |= O_NONBLOCK;
	}

	t = time(NULL);
	printf("%d  open(%s, %d, 0666)\t\t%s", pid, argv[5], flags, ctime(&t));
	fd = open(argv[5], flags, 0666);
	if (fd == -1) {
		t = time(NULL);
		printf("%d  open() returns %s (%d)\t\t%s", pid,
		    strerror(errno), errno, ctime(&t));
		exit(-1);
	}
	t = time(NULL);
	printf("%d  open() returns\t\t%s", pid, ctime(&t));

	if (strcmp(argv[4], "exflock") == 0) {
		t = time(NULL);
		printf("%d  flock(%d, LOCK_EX)\t\t%s", pid, fd, ctime(&t));
		error = flock(fd, LOCK_EX);
		if (error) {
			t = time(NULL);
			printf("%d  flock() returns %s (%d)\t\t%s", pid,
			    strerror(errno), errno, ctime(&t));
			exit(-1);
		}
	} else if (strcmp(argv[4], "shflock") == 0) {
		t = time(NULL);
		printf("%d  flock(%d, LOCK_SH)\t\t%s", pid, fd, ctime(&t));
		error = flock(fd, LOCK_SH);
		if (error) {
			t = time(NULL);
			printf("%d  flock() returns %s (%d)\t\t%s", pid,
			    strerror(errno), errno, ctime(&t));
			exit(-1);
		}
	}

	if (atoi(argv[6]) != 0) {
		t = time(NULL);
		printf("%d  sleep(%d)\t\t%s", pid, atoi(argv[6]), ctime(&t));
		sleep(atoi(argv[6]));
		t = time(NULL);
		printf("%d  sleep() returns\t\t%s", pid, ctime(&t));
	}

	return (0);
}
