#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <sys/types.h>
#include <pwd.h>
 
void printHelp() {
	printf("Insomnia 24/7 backup and restore utility.\n\n");
	printf("Options:\n");
	printf("\t-h or --help\t\t Print this help and exit.\n");
	printf("\t-b or --backup\t\t Backup files.\n");
	printf("\t-r or --restore\t\t Restore files.\n");
	printf("\n");
	printf("Usage:\n");
	printf("\tbackup -r /home/user/file_i_deleted.c\n");
	printf("\tbackup -b /home/user/file_i_want_to_backup.c\n");
	printf("\n");
}
 
int main(int argc, char *argv[]) {
	struct passwd *pwd;
 
        uid_t id = getuid();
 
        if ( (pwd = getpwuid (id) ) == NULL) {
                printf("Error: Could not determine username.\n");
                return 1;
        }
 
        char *username = calloc(strlen(pwd->pw_name), 1);
        if(username == NULL) {
                printf("Error: Could not allocate memory.\n");
                return 1;
        }
 
        strcpy(username, pwd->pw_name);
 
 
	char* home = calloc(strlen(username) + 6, 1);
	int user = getuid();
	char restore = '0';
 
	strcpy(home, "/home/");
	strcat(home,  username);
 
	/* Check if any commandline args are given. */
	if(argc < 2) {
		printf("Error: No arguements given!\nAborting.\n\n");
		printHelp();
		return 1;
	}
 
	/* parse commandline args */
	int i;
	for(i = 1; i < argc; i++) {
		if(argv[i][0] == '-') {
			switch(argv[i][1]) {
				case 'b':
					restore = '0';
					break;
 
				case 'r':
					restore = '1';
					break;
 
				case 'h':
					printHelp();
					return 0;
 
				case '-':
					if(strlen(argv[i]) > 2){
						switch(argv[i][2]) {
							case 'b':
								restore = '0';
								break;
 
							case 'r':
								restore = '1';
								break;
 
							case 'h':
								printHelp();
								return 0;
 
							default:
								printf("Error: Unknown argument given: %s\n\n", argv[i]);
								printHelp();
								return 0;
						}
					} else {
						printf("Error: Argument too short: %s\n\n", argv[i]);
						printHelp();
						return 0;
					}
 
					break;
 
				default:
					printf("Error: Unknown argument given: %s\n\n", argv[i]);
					printHelp();
					return 0;
			}
		}
 
		if(argc != 3) {
			printf("Error: Wrong number of arguments!\nAborting.\n");
			return 1;
		}
	}
 
	if(user != 0) {
		/* Check if the file is in the users home directory */
		printf("Verifying file ownership...\n");
		char* test = calloc(strlen(home), 1);
		strncpy(test, argv[2]+0,strlen(home));
		int diff = strcmp(test, home);
		free(test);
 
		if(diff != 0) {
			printf("Error: File not in user directory! Only root may do that.\nAborting.\n");
			return 1;
		}
 
		if(strlen(argv[2]) > 256) {
			printf("Error: File name is ridiculously long.\nAborting.\n");
			return 1;
		}
	}
 
	/* Check if filename contains ..'s */
	char *ptr1 = NULL;
	char *ptr2 = NULL;
	char *ptr3 = NULL;
	char *ptr4 = NULL;
	char *ptr5 = NULL;
	char *ptr6 = NULL;
	char *ptr7 = NULL;
	ptr1 = strstr(argv[2], "..");
	ptr2 = strstr(argv[2], "&");
	ptr3 = strstr(argv[2], ";");
	ptr4 = strstr(argv[2], "|");
	ptr5 = strstr(argv[2], "<");
	ptr6 = strstr(argv[2], ">");
	ptr7 = strstr(argv[2], "\\");
 
	if(ptr1 != NULL || ptr2 != NULL || ptr3 != NULL || ptr4 != NULL || ptr5 != NULL || ptr6 != NULL || ptr7 != NULL) {
		printf("Error: Filename contains invalid characters!\nUse double quotes (\") for special characters.\nAborting.\n");
		return 1;
	}
 
 
	/* Start building command */
	char *command = calloc(75 + (sizeof(argv[2]) * 2) - 5, 1);
	strcpy(command, "/usr/bin/rsync --bwlimit=5000 --no-motd -a ");
 
	/* Cut /home of the filename (since that's not on the backup server) */
	char* remotefile = calloc(strlen(argv[2]) + 29, 1);
	strcpy(remotefile, "root@10.0.1.105:/home/backup/files");
	strcat(remotefile, &argv[2][5]);
 
	int result;
 
	setuid(0);
 
	if(restore == '1') {
		printf("Attempting to restore %s...\n", argv[2]);
		strcat(command, remotefile);
		strcat(command, " ");
		strcat(command, argv[2]);
		result = system(command);
		//printf("%s\n", command);
 
	} else {
		printf("Attempting to backup %s...\n", argv[2]);
		strcat(command, argv[2]);
		strcat(command, " ");
		strcat(command, remotefile);
 
		result = system(command);
		//printf("%s\n", command);
	}
 
	if(result == 0) {
		printf("Done.\n");
		return 0;
	} else {
		printf("\n\nError: Operation could not be completed!\n");
		return 1;
	}
}