view ie-virsh.c @ 50:7a02dee972c4

easy fix randomUUID
author kono
date Tue, 30 Jan 2018 22:13:22 +0900
parents b8887c40f8b8
children e45676e6b6cd
line wrap: on
line source


#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <regex.h>
#include <pwd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>

/* Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License */

#define command "/usr/bin/virsh"
/* #define command "/usr/local/bin/virsh" */
#define list_command "/usr/bin/virsh list --all"
/* #define list_command "/usr/local/bin/virsh list --all" */
#define start_command "start"
#define stop_command "destroy"
#define define_command "define"
#define undefine_command "undefine"
#define dumpxml_command "dumpxml"
#define console_command "console"
#define debug_command "debug"
#define define_gdb_command "define-gdb"


const char *guests[] = {"145165B"};
const char *managers[] = {"atton"};
const char *students_identifier = "student";
const char *teachers_identifier = "teacher";
const char *students_sym        = "students";
const char *teachers_sym        = "teachers";
const char *managers_sym        = "managers";
const char *guests_sym          = "guests";
const char *delimiter           = "_";

static char bad_name[] = "Bad vmname. Try 01 or 02 ... 04\n";

const char newvm_command[] = "/usr/local/bin/newvm.py -c /etc/libvirt/qemu/ie-virsh-template.xml -n ";

enum {
    NAME_LENGTH = 50,
    VM_NAME_LENGTH = 50
};

enum {
    STUDENTS,
    GUESTS,
    MANAGERS,
    TEACHERS
};

#define VMNAME_MAX (512)

typedef struct vmlist {
    char name[VMNAME_MAX];
    struct vmlist *next;
} VMLIST, *VMLISTPTR;

#define NEW(type)  ((type*)malloc(sizeof(type)))

/* Define global variables */

VMLISTPTR
get_vmlist(char *list_pattern_str)
{
    regex_t *list_pattern = NEW(regex_t);
    if (regcomp(list_pattern, list_pattern_str, 0) != 0) {
        exit(0);
    }

    VMLISTPTR list = NEW(VMLIST);
    VMLISTPTR p = list ;
    p->name[0] = 0;
    p->next = 0;
    FILE *fp = popen(list_command,"r");
    while(fgets(p->name,VMNAME_MAX,fp)!=NULL) {
        if (regexec(list_pattern, p->name, (size_t) 0, NULL, 0)) continue;
        p->next = NEW(VMLIST);
        p = p->next;
    }
    p->name[0] = 0;
    pclose(fp);
    regfree(list_pattern);
    return list;
}

void
print_vmlist(VMLISTPTR list)
{
    for(;list && list->name[0]; list=list->next) {
        fprintf(stdout, "   %s\n",list->name);
    }
}

void
check_vmlist_name(VMLISTPTR list, char * name)
{
    for(;list && list->name[0]; list=list->next) {
        if (strstr(list->name, name)!=0) return;
    }

    fprintf(stderr, bad_name);
    print_vmlist(list);
    exit(1);
}

void
change_delimiter_to_slash(char *name)
{
    long size = sizeof(char) * VM_NAME_LENGTH;
    int i = 0;
    for (; i < size; i++) {
        if (name[i] == '_') {
            name[i] = '/';
        }
    }
}

int
check_name(const char *p)
{
    if (!p) return  1;
    for(;*p;p++) {
        char c = *p;
        if (c<=' ') return 1;
        if (('a'<=c && c<='z') ||
                ('0'<=c && c<='9') ||
                ('/'==c ) ||
                ('-'==c )) continue;
        return 1;
        printf("%c", c);
    }
    return 0;
}

void
usage()
{
    printf("Usage: COMMAND [define|define-gdb|list|start|destroy|dumpxml|vncdisplay|undefine|console] [vm-name]\n");
    printf("   vm-name should be 01 - 04\n");
}

int
check_user_name(const char *account_name)
{
    const char *home  = getpwuid(getuid())->pw_dir;

    if (strstr(home, students_identifier) != NULL) {
         return STUDENTS;
    } else if (strstr(home, teachers_identifier) != NULL) {
         return TEACHERS;
    }

    const int managers_num = sizeof(managers) / sizeof(managers[0]);
    int i = 0;
    for (; i < managers_num; i++) {
        if (strncmp(account_name, managers[i], NAME_LENGTH) == 0) {
            return MANAGERS;
        }
    }

    const int guests_num = sizeof(guests) / sizeof(guests[0]);
    int j = 0;
    for (; j < guests_num; j++) {
        if (strncmp(account_name, guests[j], NAME_LENGTH) == 0) { return GUESTS;
        }
    }

    return -1;
}

void
bind_name(char *name, const char *first,  const char *second)
{
    strncat(name, first, VM_NAME_LENGTH);
    strncat(name, delimiter, VM_NAME_LENGTH);
    strncat(name, second, VM_NAME_LENGTH);
    strncat(name, delimiter, VM_NAME_LENGTH);
    return;
}

void
make_vm_name(char *vm_name, const int account_type, const char *account_name, const char *vm_num)
{
    const char *regex    = "0[1-4]";
    regex_t *num_pattern = NEW(regex_t);

    if (regcomp(num_pattern, regex, REG_EXTENDED|REG_NEWLINE) != 0) {
        exit(0);
    }

    int ret = regexec(num_pattern, vm_num, (size_t) 0, NULL, 0);
    regfree(num_pattern);

    if (ret){
        fprintf(stderr, "This name is invalid number: %s\n", vm_num);
        exit(0);
    }

    switch(account_type) {
        case STUDENTS:
            strncat(vm_name, students_sym, VM_NAME_LENGTH);
            strncat(vm_name, delimiter, VM_NAME_LENGTH);
            strncat(vm_name, account_name, 3);
            strncat(vm_name, delimiter, VM_NAME_LENGTH);
            strncat(vm_name, account_name, VM_NAME_LENGTH);
            strncat(vm_name, delimiter, VM_NAME_LENGTH);
            break;
        case TEACHERS:
            strncat(vm_name, teachers_sym, VM_NAME_LENGTH);
            strncat(vm_name, delimiter, VM_NAME_LENGTH);
            strncat(vm_name, account_name, VM_NAME_LENGTH);
            strncat(vm_name, delimiter, VM_NAME_LENGTH);
            break;
        case GUESTS:
            bind_name(vm_name, guests_sym, account_name);
            break;
        case MANAGERS:
            bind_name(vm_name, managers_sym, account_name);
            break;
        default :
            fprintf(stderr, "Error: no registered type name.");
            return;
    }

    strncat(vm_name, vm_num, VM_NAME_LENGTH);
}

int
get_kernel_debug_port(void){
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    int i;
    srand(time(NULL));
    for (i = 0; i < 10; i++) {
        addr.sin_port = htons((rand() % 20000) + 10000);

        if ((bind(socket_fd, (struct sockaddr *)&addr, sizeof(struct sockaddr) ) == 0) && (listen(socket_fd, 1) == 0)) {
            printf("Port %d was allocated for your kernel debug.\n", ntohs(addr.sin_port));
            close(socket_fd);
            return ntohs(addr.sin_port);
        } else {
            printf("Port %d was used. Trying another port...\n", ntohs(addr.sin_port));
        }
    }
    printf("Cannot allocate debug port.\n");
    exit(EXIT_FAILURE);
}

void
create_new_vm(const char const *name, const char const *vm_name, char* xml_name, bool debug_kernel){
    if (check_name(name)) {
        fprintf(stderr, bad_name);
        exit(0);
    }
    char *vm_path = (char *)malloc(sizeof(char) * VM_NAME_LENGTH);
    strncpy(vm_path, vm_name, VM_NAME_LENGTH);
    change_delimiter_to_slash(vm_path);
    char exec[1024];
    if (debug_kernel) {
        snprintf(exec, 1024, "%s %s -d %d", newvm_command, vm_path, get_kernel_debug_port());
    } else {
        snprintf(exec, 1024, "%s %s", newvm_command, vm_path);
    }
    fprintf(stdout, "excuting %s\n",exec );
    system(exec);
    strncpy(xml_name, vm_path,900);
    strncat(xml_name,".xml",1000);
    free(vm_path);
}

/* main(int argc, char **argv) - main process loop */

int main(int argc, char **argv)
{
    /* Set euid and egid to actual user */
    int uid    = getuid();
    int gid    = getgid();
    char *name = getlogin();

    printf("uid %d gid %d name %s\n", uid,gid,name);
    setegid(getgid());
    seteuid(getuid());

    int account_type = check_user_name(name);
    if (account_type < 0) {
        fprintf(stderr, "Parmission denied. :%s\n", name);
        exit(1);
    }


    /* Confirm user is in GROUP(999) group */

    /*
       if ( gid != 999 ) {
       printf("User Not Authorized!  Exiting...\n");
       exit(1);
       }
     */

    if (argc<2) {
        usage();
        exit(0);
    }

    /* Set uid, gid, euid and egid to root */

    setegid(0);
    seteuid(0);
    setgid(0);
    setuid(0);

    char *vm_name = (char *)malloc(sizeof(char) * VM_NAME_LENGTH);
    vm_name[0] = '\0';
    if ((argc > 2) && (strncmp(argv[1], list_command, 4) != 0)) { make_vm_name(vm_name, account_type, name, argv[2]); }

    VMLISTPTR vmlist = get_vmlist(name);


    /* Check argv for proper arguments and run
     * the corresponding script, if invoked.
     */

    if (argv[1]==0 || strncmp(argv[1], "list", 4) == 0 ) {
        print_vmlist(vmlist);
    } else if (strncmp(argv[1], start_command, 5) == 0) {
        if (argc<3) {usage(); exit(1);}
        check_vmlist_name(vmlist, argv[2]);
        if (execl(command, command, start_command, vm_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if ( strncmp(argv[1], stop_command, 4) == 0 ) {
        if (argc<3) {usage(); exit(1);}
        check_vmlist_name(vmlist, argv[2]);
        if (execl(command, command, stop_command, vm_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if ( strncmp(argv[1], dumpxml_command, 7) == 0 ) {
        if (argc<3) {usage(); exit(1);}
        check_vmlist_name(vmlist, argv[2]);
        if (execl(command, command, dumpxml_command, vm_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if ( strncmp(argv[1], "vncdisplay", 10) == 0 ) {
        if (argc<3) {usage(); exit(1);}
        check_vmlist_name(vmlist, argv[2]);
        if (execl(command, command, "vncdisplay", vm_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if ( strncmp(argv[1], console_command, 8) == 0 ) {
        if (argc<3) {usage(); exit(1);}
        check_vmlist_name(vmlist, argv[2]);
        if (execl(command, command, console_command, vm_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if (strcmp(argv[1], define_command) == 0 ) {
        if (argc<3) {usage(); exit(1);}
        char xml_name[1024];
        xml_name[0] = 0;
        create_new_vm(argv[2], vm_name, xml_name, false);
        /* chdir("/usr/local/etc/libvirt/qemu"); */
        chdir("/etc/libvirt/qemu");
        if (execl(command, command, define_command, xml_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if (strcmp(argv[1], define_gdb_command) == 0 ) {
        if (argc<3) {usage(); exit(1);}
        char xml_name[1024];
        xml_name[0] = 0;
        create_new_vm(argv[2], vm_name, xml_name, true);
        /* chdir("/usr/local/etc/libvirt/qemu"); */
        chdir("/etc/libvirt/qemu");
        if (execl(command, command, define_command, xml_name, NULL) < 0) {
            perror("Execl:");
        }
    } else if ( strncmp(argv[1], undefine_command, 8) == 0 ) {
        /* chdir("/usr/local/etc/libvirt/qemu"); */
        chdir("/etc/libvirt/qemu");
        if (execl(command, command, undefine_command, vm_name, NULL) < 0) {
            perror("Execl:");
        }
    } else {
        printf("%s is invalid command.\n", argv[1]);
        usage();
        exit(1);
    }
    free(vm_name);
    exit(0);
}

/* end */