Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Avoid strict-aliasing related issues when compiling with optimization
[palacios.git] / linux_usr / v3_create.c
index 3605702..4a0b9ff 100644 (file)
@@ -3,7 +3,6 @@
  * (c) Jack lange, 2010
  */
 
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h> 
 #include <sys/types.h> 
 #include <unistd.h> 
 #include <string.h>
+#include <getopt.h> 
+
+
 #include "v3_ctrl.h"
+#include "ezxml.h"
 
-int read_file(int fd, int size, unsigned char * buf);
 
-int main(int argc, char* argv[]) {
-    char * filename = argv[1];
-    char * name = argv[2];
-    int guest_fd = 0;
-    int v3_fd = 0;
+#define MAX_FILES 256
+unsigned long long num_files = 0;
+struct file_info files[MAX_FILES];
+
+
+int create_vm(char * vm_name, void * img_data, unsigned int img_size) {
     struct v3_guest_img guest_img;
-    struct stat guest_stats;
+    int v3_fd = 0;
     int dev_idx = 0;
 
     memset(&guest_img, 0, sizeof(struct v3_guest_img));
 
-    if (argc <= 2) {
-       printf("usage: v3_create <guest_img> <vm name>\n");
+    guest_img.size = img_size;
+    guest_img.guest_data = img_data;
+    strncpy(guest_img.name, vm_name, 127);
+
+    dev_idx = v3_dev_ioctl(V3_CREATE_GUEST, &guest_img); 
+
+    if (dev_idx < 0) {
+       printf("Error (%d) creating VM\n", dev_idx);
        return -1;
     }
 
-    printf("Creating guest: %s\n", filename);
+    printf("VM (%s) created at /dev/v3-vm%d\n", vm_name, dev_idx);
+    return 0;
+}
+
+
+int load_image(char * vm_name, char * filename) {
+    int guest_fd = 0;
+    struct stat guest_stats;
+    int img_size = 0;
+    void * img_data = NULL;
 
     guest_fd = open(filename, O_RDONLY); 
 
@@ -46,72 +63,356 @@ int main(int argc, char* argv[]) {
        printf("ERROR: Could not stat guest image file -- %s\n", filename);
        return -1;
     }
-
-    
-    guest_img.size = guest_stats.st_size;
     
+    img_size = guest_stats.st_size;
+
     // load guest image into user memory
-    guest_img.guest_data = malloc(guest_img.size);
-    if (!guest_img.guest_data) {
-            printf("ERROR: could not allocate memory for guest image\n");
-            return -1;
-    }
+    img_data = malloc(img_size);
 
-    read_file(guest_fd, guest_img.size, guest_img.guest_data);
+    v3_read_file(guest_fd, img_size, img_data);
     
     close(guest_fd);
 
-    printf("Loaded guest image. Creation begins.\n");
+    printf("Guest image Loaded (size=%u)\n", img_size);
+    return create_vm(vm_name, img_data, img_size);
+
+}
+
+
+ezxml_t open_xml_file(char * filename) {
+
+    ezxml_t xml_input = ezxml_parse_file(filename);
     
-    strncpy(guest_img.name, name, 127);
+    if (xml_input == NULL) {
+       printf("Error: Could not open XML input file (%s)\n", filename);
+       return NULL;
+    } else if (strcmp("", ezxml_error(xml_input)) != 0) {
+       printf("%s\n", ezxml_error(xml_input));
+       return NULL;
+    }
+
+    return xml_input;
+}
 
 
-    v3_fd = open(v3_dev, O_RDONLY);
+int find_xml_options(ezxml_t xml,  struct xml_option ** opts) {
+    int num_opts = 0;
+    ezxml_t child = xml->child;
+    struct xml_option * next_opt = NULL;
 
-    if (v3_fd == -1) {
-       printf("Error opening V3Vee control device\n");
-       return -1;
+    char * opt = (char *)ezxml_attr(xml, "opt_tag");
+
+    if (opt) {
+       next_opt = malloc(sizeof(struct xml_option));
+
+       memset(next_opt, 0, sizeof(struct xml_option));
+
+       next_opt->tag = opt;
+       next_opt->location = xml;
+       next_opt->next = NULL;
+
+//     printf("Option found: %s\n", opt);
+
+       *opts = next_opt;
+       num_opts++;
     }
 
-    dev_idx = ioctl(v3_fd, V3_CREATE_GUEST, &guest_img); 
 
+    while (child) {
 
-    if (dev_idx < 0) {
-       printf("Error (%d) creating VM\n", dev_idx);
-       return -1;
+       fflush(stdout);
+
+       if (next_opt != 0x0) {
+           num_opts += find_xml_options(child, &(next_opt->next));
+       } else {
+           num_opts += find_xml_options(child, opts);
+
+           if (*opts) {
+               next_opt = *opts;
+           }
+       }
+
+       if (next_opt) {
+           while (next_opt->next) {
+               next_opt = next_opt->next;
+           }
+       }
+
+       child = child->ordered;
     }
+    
+    return num_opts;
 
-    printf("VM (%s) created at /dev/v3-vm%d\n", name, dev_idx);
+}
 
-    /* Close the file descriptor.  */ 
-    close(v3_fd); 
 
+char * get_val(ezxml_t cfg, char * tag) {
+    char * attrib = (char *)ezxml_attr(cfg, tag);
+    ezxml_t txt = ezxml_child(cfg, tag);
 
-    return 0; 
-} 
+    if ((txt != NULL) && (attrib != NULL)) {
+       printf("Invalid Cfg file: Duplicate value for %s (attr=%s, txt=%s)\n", 
+              tag, attrib, ezxml_txt(txt));
+       exit(-1);
+    }
 
+    return (attrib == NULL) ? ezxml_txt(txt) : attrib;
+}
 
 
-int read_file(int fd, int size, unsigned char * buf) {
-    int left_to_read = size;
-    int have_read = 0;
+int parse_aux_files(ezxml_t cfg_input) {
+    ezxml_t file_tags = NULL;
+    ezxml_t tmp_file_tag = NULL;
 
-    while (left_to_read != 0) {
-       int bytes_read = read(fd, buf + have_read, left_to_read);
+    // files are transformed into blobs that are slapped to the end of the file
+        
+    file_tags = ezxml_child(cfg_input, "files");
 
-       if (bytes_read <= 0) {
-           break;
+    tmp_file_tag = ezxml_child(file_tags, "file");
+
+    while (tmp_file_tag) {
+       char * filename = get_val(tmp_file_tag, "filename");
+       struct stat file_stats;
+       char * id = get_val(tmp_file_tag, "id");
+       char index_buf[256];
+
+
+       if (stat(filename, &file_stats) != 0) {
+           perror(filename);
+           exit(-1);
        }
 
-       have_read += bytes_read;
-       left_to_read -= bytes_read;
+       files[num_files].size = (unsigned int)file_stats.st_size;
+       strncpy(files[num_files].id, id, 256);
+       strncpy(files[num_files].filename, filename, 2048);
+
+       snprintf(index_buf, 256, "%llu", num_files);
+       ezxml_set_attr_d(tmp_file_tag, "index", index_buf);
+
+       num_files++;
+       tmp_file_tag = ezxml_next(tmp_file_tag);
     }
 
-    if (left_to_read != 0) {
-       printf("Error could not finish reading file\n");
-       return -1;
+
+    return 0;
+}
+
+int build_image(char * vm_name, char * filename, struct cfg_value * cfg_vals, int num_options) {
+    int i = 0;
+    ezxml_t xml = NULL;
+    struct xml_option * xml_opts = NULL;
+    int num_xml_opts = 0;
+    void * guest_img_data = NULL;
+    int guest_img_size = 0;
+
+
+    xml = open_xml_file(filename);
+    
+    // parse options
+    num_xml_opts = find_xml_options(xml, &xml_opts);
+    
+    //  printf("%d options\n", num_xml_opts);
+
+    // apply options
+    for (i = 0; i < num_options; i++) {
+       struct cfg_value * cfg_val = &cfg_vals[i];
+       struct xml_option * xml_opt = xml_opts;
+
+       while (xml_opt) {
+           if (strcasecmp(cfg_val->tag, xml_opt->tag) == 0) {
+               break;
+           }
+           
+           xml_opt = xml_opt->next;
+       }
+
+
+       if (!xml_opt) {
+           printf("Could not find Config option (%s) in XML file\n", cfg_val->tag);
+           return -1;
+       }
+
+       ezxml_set_txt(xml_opt->location, cfg_val->value);
     }
     
-    return 0;
+
+
+    // parse files
+    parse_aux_files(xml);
+    
+    // create image data blob
+    {
+       char * new_xml_str = ezxml_toxml(xml);
+       int file_data_size = 0;
+       int i = 0;
+       int offset = 0;
+       unsigned long long file_offset = 0;
+        struct mem_file_hdr * hdrs = NULL;
+
+       /* Image size is: 
+          8 byte header + 
+          4 byte xml length + 
+          xml strlen + 
+          8 bytes of zeros + 
+          8 bytes (number of files) + 
+          num_files * (16+sizeof(unsigned long)) byte file header + 
+          8 bytes of zeroes + 
+          file data
+       */
+       for (i = 0; i < num_files; i++) {
+           file_data_size += files[i].size;
+       }
+
+       guest_img_size = 8 + 4 + strlen(new_xml_str) + 8 + 8 + 
+           (num_files * (16*sizeof(unsigned long))) + 8 + file_data_size;
+           
+
+       guest_img_data = malloc(guest_img_size);
+       memset(guest_img_data, 0, guest_img_size);
+
+       //
+       // Dynamically built guests are version 1 by default now
+       //
+       memcpy(guest_img_data, "v3vee\0\0\1", 8);
+       offset += 8;
+
+       *(unsigned int *)(guest_img_data + offset) = strlen(new_xml_str);
+       offset += 4;
+
+       memcpy(guest_img_data + offset, new_xml_str, strlen(new_xml_str));
+       offset += strlen(new_xml_str);
+
+       memset(guest_img_data + offset, 0, 8);
+       offset += 8;
+       
+       *(unsigned long long *)(guest_img_data + offset) = num_files;
+       offset += 8;
+
+        hdrs = guest_img_data + offset;
+       
+       // The file offset starts at the end of the file list
+       file_offset = offset + ((sizeof(unsigned long) + 16) * num_files) + 8;
+
+       for (i = 0; i < num_files; i++) {
+            /*
+           unsigned int *)(guest_img_data + offset) = i;
+           offset += 4;
+           *(unsigned int *)(guest_img_data + offset) = files[i].size;
+           offset += 4;
+           *(unsigned long long *)(guest_img_data + offset) = file_offset;
+           offset += 8;
+            *(unsigned long *)(guest_img_data + offset) = 0;
+            offset += sizeof(unsigned long);
+            */
+            hdrs[i].file_idx     = i;
+            hdrs[i].file_size    = files[i].size;
+            hdrs[i].file_offset  = file_offset;
+            hdrs[i].file_hash    = 0;
+
+            offset +=  16 + sizeof(unsigned long);
+           file_offset += files[i].size;
+       }
+
+       memset(guest_img_data + offset, 0, 8);
+       offset += 8;
+
+
+       for (i = 0; i < num_files; i++) {
+           int fd = open(files[i].filename, O_RDONLY);
+            unsigned char * faddr = (unsigned char *)(guest_img_data + offset);
+
+           if (fd == -1) {
+               printf("Error: Could not open aux file (%s)\n", files[i].filename);
+               return -1;
+           }
+
+           v3_read_file(fd, files[i].size, faddr);
+
+            /* store a hash of the file blob for integrity checking later */
+            hdrs[i].file_hash = v3_hash_buffer(faddr, files[i].size);
+            printf("File Hash: %llx\n", hdrs[i].file_hash);
+
+           close(fd);
+
+           offset += files[i].size;
+
+       }
+       
+       free(new_xml_str);
+
+    }
+
+    printf("Guest Image Created (size=%u)\n", guest_img_size);
+    return create_vm(vm_name, guest_img_data, guest_img_size);
 }
+
+
+
+
+int main(int argc, char** argv) {
+    char * filename = NULL;
+    char * name = NULL;
+    int build_flag  = 0;
+    int c = 0;
+
+    opterr = 0;
+
+    while (( c = getopt(argc, argv, "b")) != -1) {
+       switch (c) {
+       case 'b':
+           build_flag = 1;
+           break;
+       }
+    }
+
+    if (argc - optind + 1 < 3) 
+        v3_usage("[-b] <guest_img> <vm_name> [cfg options]\n");
+
+    filename = argv[optind];
+    name = argv[optind + 1];
+
+
+    if (build_flag == 1) {
+       int cfg_idx = optind + 2;
+       int i = 0;
+       struct cfg_value * cfg_vals = NULL;
+       
+       printf("Building VM Image (cfg=%s) (name=%s) (%d config options)\n", filename, name, argc - cfg_idx);
+
+       cfg_vals = malloc(sizeof(struct cfg_value) * argc - cfg_idx);
+       
+       
+
+       while (i < argc - cfg_idx) {
+           char * tag = NULL;
+           char * value = NULL;
+
+           value = argv[cfg_idx + i];
+
+           tag = strsep(&value, "=");
+           // parse
+
+           if (value == NULL) {
+               printf("Invalid Option format: %s\n", argv[cfg_idx + i]);
+               return -1;
+           }
+
+           cfg_vals[i].tag = tag;
+           cfg_vals[i].value = value;
+
+           printf("Config option: %s: %s\n", tag, value);
+
+
+           i++;
+       }
+
+       return build_image(name, filename, cfg_vals, argc - cfg_idx);
+
+
+    } else {
+       printf("Loading VM Image (img=%s) (name=%s)\n", filename, name);
+       return load_image(name, filename);
+    }
+
+    return 0; 
+}