/*
 *   Copyright (c) International Business Machines  Corp., 2004
 *
 *   This program is free software;  you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
 *   the GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program;  if not, write to the Free Software
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/*
 * FILE NAME	: mmapfile.c
 *
 * PURPOSE	: This executable is invoked by the mmap test case to invoke
 * 		  mmap() from a process different than mmap.  If mmap() is
 * 		  invoked by the mmap process, a hang will generally occur
 * 		  because sys_mmap obtains write access to mmap_sem, and any
 * 		  page fault within the same process (while process is
 * 		  responding to read/write event generated by mmap() call)
 * 		  requires read access to the same mmap_sem.
 *
 * PARAMETERS	: argv[1] - name of file being memory mapped
 * 		  argv[2] - open flags:
 * 		  	0 - read-only
 * 		  	1 - write-only
 * 		  	2 - read-write
 * 		  argv[3] - offset within file of memory mapped region
 * 		  argv[4] - length of memory mapped region
 * 		  argv[5] - mmap() expected pass/fail status
 * 		  	0 - fail
 * 		  	1 - pass
 *
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
#include "dm_test.h"

char DummyFile[FILENAME_MAX];

int main(int argc, char **argv)
{
	int rc;
	int fd;
	int openflags;
	int offset;
	int length;
	int passflag;
	int flags;
	void *memmap;

	if (--argc != 5) {
		printf("usage: %s filename openflags offset length passflag\n",
		       argv[0]);
		exit(-1);
	}

	passflag = atoi(argv[5]);
	if ((passflag != 0) && (passflag != 1)) {
		printf("%s error: invalid passflag %s\n", argv[0], argv[5]);
		exit(-1);
	}

	length = atoi(argv[4]);
	if (length < 0) {
		printf("%s error: invalid length %s\n", argv[0], argv[4]);
		exit(-1);
	}

	offset = atoi(argv[3]);
	if (offset < 0) {
		printf("%s error: invalid offset %s\n", argv[0], argv[3]);
		exit(-1);
	}
	if (offset & (PAGE_SIZE - 1)) {
		printf("%s error: unaligned offset %d\n", argv[0], offset);
		exit(-1);
	}

	openflags = atoi(argv[2]);
	if (openflags == O_RDONLY) {
		flags = PROT_READ;
	} else if (openflags == O_WRONLY) {
		flags = PROT_WRITE;
	} else if (openflags == O_RDWR) {
		flags = PROT_READ | PROT_WRITE;
	} else {
		printf("%s error: invalid openflags %s\n", argv[0], argv[2]);
		exit(-1);
	}

	printf("invoking open(%s, %d)\n", argv[1], openflags);
	fd = open(argv[1], openflags);
	if (fd == -1) {
		printf("%s error: open failed with rc = %d (errno = %d)\n",
		       argv[0], rc, errno);
		exit(-1);
	}

	printf("invoking memmap(%d, %d, %s, %d)\n", length, flags, argv[1],
	       offset);
	memmap = mmap(NULL, length, flags, MAP_SHARED, fd, offset);
	if (memmap == MAP_FAILED) {
		printf("%s error: mmap failed with errno = %d\n", argv[0],
		       errno);
		if (passflag) {
			close(fd);
			exit(-1);
		}
	}

	EVENT_DELIVERY_DELAY;

	if (memmap != MAP_FAILED) {
		printf("invoking munmap(%p, %d)\n", memmap, length);
		munmap(memmap, length);
	}

	close(fd);

	_exit(0);
	tst_exit();
}
