/* 
 * Copyright (c) 2010, digital <digital [at] theknotter [dot] net>
 * All rights reserved.
 *
 * 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 REGENTS 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 REGENTS 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.
 */

#define _GNU_SOURCE 1

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/mman.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define MEM_FILE "/dev/mem"
#define IOM_FILE "/proc/iomem"

int main(/*int argc, char *argv[]*/)
{
	FILE *map_file;
	int mem_fd, sock;
	long unsigned int r0, r1;
	long unsigned int count;
	long unsigned int chunk;
	char *ptr, *mem;
	size_t n;
	int rohan;
//	struct sockaddr_in addr;

/*	if (argc != 3) {
		printf("USAGE: %s <ip> <port>\n", argv[0]);
		return -1;		
	}
*/
	if (!(map_file = fopen(IOM_FILE, "r"))) {
		perror("fopen");
		return -1;
	}

	if ((mem_fd = open(MEM_FILE, O_RDONLY)) < 0) {
		perror("fopen");
		return -1;
	}
	if ((rohan = open("./rohan.txt", O_WRONLY | O_CREAT)) < 0) {
                perror("fopen");
                return -1;
        }


/*	if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		perror("socket");
		return -1;
	}

	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(argv[1]);
	addr.sin_port = htons(atoi(argv[2]));

	if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
		perror("connect");
		return -1;
	}
*/
	for (ptr = NULL; getline(&ptr, &n, map_file) > 0;) {
		if (ptr[0] == ' ' || !strstr(ptr, "System RAM"))
			continue;

		if (sscanf(ptr, "%lx-%lx", &r0, &r1) != 2) {

			return -1;
		}

		if (r1 % 4096)
			r1 = (r1 - (r1 % 4096)) + 4096;

		count = r1 - r0;

		for (chunk = count / 4096; chunk > 0; chunk--) {
			mem = mmap(NULL, 4096, PROT_READ, MAP_PRIVATE,
				   mem_fd, r0 + (count - (chunk * 4096)));
			if (mem == (void*) -1) {
				char zeroed[4096] = { 0 };

				if (write(rohan , zeroed, 4096) != 4096) {
					perror("write");
					return -1;
				}

				continue;
			}

			if (write(rohan , mem, 4096) != 4096) {
				perror("write");
				return -1;
			}

			munmap(mem, 4096);
		}
	}

	free(ptr);
	close(mem_fd);
	fclose(map_file);
	close(sock);

	return 0;
}
