* (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);
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);
+ 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;
+}