/***********************************************************
 * mmap-demo                                               *
 * a demonstration for using the mmap call                 *
 * Verteilte Systeme II Kapitel 9                          *
 ***********************************************************
 * 1998 by Frank Kargl (frank.kargl@informatik.uni-ulm.de) *
 ***********************************************************
 * Usage: mmap-demo                                        *
 ***********************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>

/* enumeration for status of memory map */
enum status_t {NONE, READ, WRITE};

int fd;				/* filedescriptor for /dev/zero */
enum status_t status;		/* status of memory page */
void* page;			/* pointer to memory page */
long pagesize;			/* size of memory page */

/***********************************************************
 *                                                         *
 * Function:                                               *
 * void usage(char* name)                                  *
 * print usage message                                     *
 * Parameters:                                             * 
 *  name - name of executable                              *
 * Return:                                                 *
 *  -                                                      *
 *                                                         *
 ***********************************************************/

void usage(char* name) {
    printf("%s - a demo how to use the mmap syscall\n", name);
    printf("Usage: %s\n", name);
    exit(1);
}

/***********************************************************
 *                                                         *
 * Function:                                               *
 * void segv(int sig)                                      *
 * segmentation violation signal handler                   *
 * Parameters:                                             * 
 *  sig - signal caught                                    *
 * Return:                                                 *
 *  -                                                      *
 *                                                         *
 ***********************************************************/

void segv(int sig) {

    void* ptr;
    int mode;
    
    printf("SIGSEGV signal\n");

    /* change protection of page */
    switch(status) {
	case NONE :	mode = PROT_READ; status=READ;
			break;
	case READ :	mode = PROT_READ|PROT_WRITE; status=WRITE;
			break;
    }

    ptr = mmap((void *)page, pagesize, mode, MAP_SHARED|MAP_FIXED, fd, 0);
    
    /* reinstall signal handler */
    signal(SIGSEGV,segv);

}

int main(int argc, char** argv) {
    
    char c;
    char* p;

    /* get this system's pagesize */
    pagesize = sysconf(_SC_PAGESIZE);
    printf("System pagesize (bytes) %lu\n",pagesize);

    /* create emtpy memory page */
    fd = open("/dev/zero", O_RDWR);
    if (fd == -1) {
	perror("can't open /dev/zero\n");
	exit(1);
    }
    page = mmap((void *)0, pagesize, PROT_NONE, MAP_SHARED, fd, 0);
    if (page == MAP_FAILED) {
	perror("can't map memory page\n");
    }
    status = NONE;
    printf("address = %08X\n",page);

    /* install signal handler */
    signal(SIGSEGV,segv);

    p=(char *)page;
    
    /* read from page */
    c=*p;
    printf("read %d\n",c);
    
    /* write to page */
    *p=1;
    printf("write %d\n",*p);

}
