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.


Support for new Palacios image file format (Version 1)
[palacios.git] / utils / guest_creator / main.c
1 #include "ezxml.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <getopt.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include <sys/stat.h>
9 #include <sys/types.h>
10 #include <sys/ioctl.h>
11 #include <sys/mman.h>
12 #include <unistd.h>
13 #include <errno.h>
14
15 #include <v3_ctrl.h>
16
17 #define MAX_FILES 256
18
19 /*
20 struct file_info {
21     int size;
22     char filename[2048];
23     char id[256];
24 };
25 */
26
27 /*
28
29    The Palacios cookie encodes "v3vee" followed by a 
30    3 byte version code.   There are currently two versions:
31
32     \0\0\0 => original (no checksum)
33     \0\0\1 => checksum
34 */
35
36 #define COOKIE "v3vee\0\0\0"
37 #define COOKIE_LEN            8
38 #define COOKIE_VERSION_OFFSET 5
39 #define COOKIE_VERSION_LEN    3
40
41 int version = 1; // default version is now 1
42
43
44 int num_files = 0;
45 struct file_info files[MAX_FILES];
46
47 #define STDIO_FD 1
48
49
50 int parse_config_input(ezxml_t cfg_input);
51 int write_output(char * filename, ezxml_t cfg_output);
52 int copy_file(int file_index, FILE * data_file);
53
54 void usage() {
55     printf("Usage: build_vm <infile> [-v version] [-o outfile]\n");
56 }
57
58 int main(int argc, char ** argv) {
59     int c;
60     char * outfile = NULL;
61     char * infile = NULL;
62
63     memset((char *)files, 0, sizeof(files));
64
65     opterr = 0;
66
67     while ((c = getopt(argc, argv, "ho:v:")) != -1) {
68         switch (c) {
69             case 'o':
70                 outfile = optarg;
71                 break;
72             case 'v':
73                 version = atoi(optarg);
74                 break;
75             case 'h':
76                 usage();
77                 return 1;
78             default:
79                 abort();
80         }
81     }
82
83     if (optind >= argc) {
84         usage();
85         return 1;
86     }
87
88     if (version != 0 && version != 1) { 
89         printf("Only versions 0 and 1 are supported\n");
90         return 1;
91     }
92
93     infile = argv[optind];
94
95
96     if (outfile == NULL) {
97         char * endptr = rindex(infile, '.');
98
99         outfile = malloc(strlen(infile) + strlen(".dat") + 1);
100
101         strncpy(outfile, infile, endptr - infile);
102
103         sprintf(outfile, "%s.dat", outfile);
104     }
105
106
107
108     printf("Input: [%s] ==>>  Output: [%s]\n", infile, outfile);
109
110     ezxml_t cfg_input = ezxml_parse_file(infile);
111     if (strcmp("", ezxml_error(cfg_input)) != 0) {
112         printf("%s\n", ezxml_error(cfg_input));
113         return -1;
114     }
115
116     if (cfg_input == NULL) {
117         printf("Could not open configuration input file: %s\n", infile);
118         return 1;
119     }
120
121
122
123
124     // parse input
125     if (parse_config_input(cfg_input) == -1) {
126         printf("Error parsing configuration input\n");
127         return 1;
128     }
129
130     //  printf("xml : %s\n", ezxml_toxml(cfg_input));
131
132
133
134     // write output
135
136
137
138     write_output(outfile, cfg_input);
139
140
141     return 0;
142 }
143
144 char * get_val(ezxml_t cfg, char * tag) {
145     char * attrib = (char *)ezxml_attr(cfg, tag);
146     ezxml_t txt = ezxml_child(cfg, tag);
147
148     if ((txt != NULL) && (attrib != NULL)) {
149         printf("Invalid Cfg file: Duplicate value for %s (attr=%s, txt=%s)\n", 
150                tag, attrib, ezxml_txt(txt));
151         exit(-1);
152     }
153
154     return (attrib == NULL) ? ezxml_txt(txt) : attrib;
155 }
156
157
158
159 int parse_config_input(ezxml_t cfg_input) {
160     ezxml_t file_tags = NULL;
161     ezxml_t tmp_file_tag = NULL;
162
163     // files are transformed into blobs that are slapped to the end of the file
164         
165     file_tags = ezxml_child(cfg_input, "files");
166
167     tmp_file_tag = ezxml_child(file_tags, "file");
168
169     while (tmp_file_tag) {
170         char * filename = get_val(tmp_file_tag, "filename");
171         struct stat file_stats;
172         char * id = get_val(tmp_file_tag, "id");
173         char index_buf[256];
174
175
176         if (stat(filename, &file_stats) != 0) {
177             perror(filename);
178             exit(-1);
179         }
180
181         files[num_files].size = (unsigned int)file_stats.st_size;
182         strncpy(files[num_files].id, id, 256);
183         strncpy(files[num_files].filename, filename, 2048);
184
185         snprintf(index_buf, 256, "%d", num_files);
186         ezxml_set_attr_d(tmp_file_tag, "index", index_buf);
187
188         num_files++;
189         tmp_file_tag = ezxml_next(tmp_file_tag);
190     }
191
192
193     return 0;
194 }
195
196
197 static int generate_file_hashes (char * filename,
198                                  unsigned long long hdr_offset,
199                                  int num_files) {
200     unsigned char * file_data;
201     unsigned char * out_data;
202     struct mem_file_hdr * hdrs = NULL;
203     int i, fd, out_fd;
204     struct stat st;
205
206     out_fd = open(filename, O_RDWR);
207     if (!out_fd) {
208         fprintf(stderr, "Couldn't open output file %s\n", filename);
209         return -1;
210     }
211     fstat(out_fd, &st);
212
213     /* mmap the out file, easy access to file headers */
214     if ((out_data = mmap(0,
215                          st.st_size,
216                          PROT_READ|PROT_WRITE,
217                          MAP_SHARED,
218                          out_fd,
219                          0)) == MAP_FAILED) {
220         fprintf(stderr, "Error mapping output file (%d)\n", errno);
221         return -1;
222     }
223
224     hdrs = (struct mem_file_hdr *)(out_data + hdr_offset);
225
226     /* mmap each file, then update it's hash */
227     for (i = 0; i < num_files; i++) {
228
229         fd = open(files[i].filename, O_RDONLY);
230         if (!fd) {
231             fprintf(stderr, "Error opening file %s\n",
232                     files[i].filename);
233             return -1;
234         }
235
236         if ((file_data = mmap(0, 
237                               hdrs[i].file_size, 
238                               PROT_READ,
239                               MAP_PRIVATE,
240                               fd,
241                               0)) == MAP_FAILED) {
242             fprintf(stderr, "Could not mmap file for hashing\n");
243             return -1;
244          }
245
246          /* generate the hash and save it */
247         hdrs[i].file_hash = v3_hash_buffer(file_data, hdrs[i].file_size);
248         printf("Generating hash for file %s (hash=0x%lx)\n", 
249                 files[i].filename, hdrs[i].file_hash);
250
251         munmap(file_data, hdrs[i].file_size);
252         close(fd);
253     }
254
255     munmap(out_data, st.st_size);
256     return 0;
257 }
258
259 void gen_cookie(char *dest)
260 {
261     memcpy(dest,COOKIE,COOKIE_LEN);
262     dest[COOKIE_VERSION_OFFSET]   = (((unsigned)version) >> 16) & 0xff;
263     dest[COOKIE_VERSION_OFFSET+1] = (((unsigned)version) >>  8) & 0xff;
264     dest[COOKIE_VERSION_OFFSET+2] = (((unsigned)version) >>  0) & 0xff;
265 }
266
267
268 int write_output(char * filename, ezxml_t cfg_output) {
269     FILE * data_file = fopen(filename, "w+");
270     char * new_cfg_str = ezxml_toxml(cfg_output);
271     unsigned int cfg_len = strlen(new_cfg_str);
272     unsigned long long zero = 0;
273     int i = 0;
274     unsigned long long offset = 0;
275     unsigned long long file_cnt = num_files;
276     unsigned long long hdr_offset = 0;
277     char cookie[COOKIE_LEN];
278
279     gen_cookie(cookie);
280
281     fwrite(cookie, COOKIE_LEN, 1, data_file);
282     offset += COOKIE_LEN;
283
284     //  printf("New config: \n%s\n", new_cfg_str);
285     
286     fwrite(&cfg_len, sizeof(unsigned int), 1, data_file);
287     offset += sizeof(unsigned int);
288
289     fwrite(new_cfg_str, cfg_len, 1, data_file);
290     offset += cfg_len;
291
292     fwrite(&zero, 1, 8, data_file);
293     offset += 8;
294
295     printf("Total number of files: %llu\n", file_cnt);
296
297     fwrite(&file_cnt, 8, 1, data_file);
298     offset += 8;
299
300
301     if (version==0) { 
302         // for version 0, we simply have the file num, offset, size list
303         // each index entry is 16 bytes long plus end padding
304         offset += (16 * num_files) + 8;
305     } else if (version==1) { 
306         // For a version 1, we have the file num, offset, size, and hash list
307         // We need to remember where this begins in the file, though...
308         hdr_offset = offset;
309
310         // each index entry is (16+sizeof(unsigned long)) bytes long plus end padding
311         offset += ((16 + sizeof(unsigned long)) * num_files) + 8;
312     }
313     
314     for (i = 0; i < num_files; i++) {
315         fwrite(&i, 4, 1, data_file);
316         fwrite(&(files[i].size), 4, 1, data_file);
317         fwrite(&offset, 8, 1, data_file);
318
319         if (version==1) { 
320             /* we can't generate the hash yet, zero for now */
321             fwrite(&zero, sizeof(unsigned long), 1, data_file);
322         }
323
324         offset += files[i].size;
325     }
326
327     fwrite(&zero, 1, 8, data_file);
328
329     for (i = 0; i < num_files; i++) {
330
331         copy_file(i, data_file);
332         
333     }
334     
335     fclose(data_file);
336
337     if (version==1) { 
338         // We now will go back and place the hashes
339         if (generate_file_hashes(filename,
340                                  hdr_offset,
341                                  num_files) < 0) {
342             fprintf(stderr, "Error generating file hashes\n");
343             return -1;
344         }
345     }
346
347
348     return 0;
349 }
350
351
352 #define XFER_BLK_SIZE 4096
353
354 int copy_file(int file_index, FILE * data_file) {
355     char xfer_buf[XFER_BLK_SIZE];
356     int bytes_to_read = files[file_index].size;
357     int bytes_read = 0;
358     int xfer_len = XFER_BLK_SIZE;
359     FILE * in_file = NULL;
360     char * filename = files[file_index].filename;
361     struct winsize wsz;
362     char cons_line[256];
363     int prog_len = 0;
364     double ratio = 100;
365     int num_dots = 256;
366
367     printf("Copying [%d] -- %s \n",
368            file_index,     
369            filename);
370
371
372     if (ioctl(STDIO_FD, TIOCGWINSZ, &wsz) == -1) {
373         printf("ioctl error on STDIO\n");
374         return -1;
375     }
376
377
378     memset(cons_line, 0, 256);
379     snprintf(cons_line, 256, "\r(%s) [", files[file_index].id);
380     prog_len = wsz.ws_col - (strlen(cons_line) + 11);
381
382
383
384     in_file = fopen(filename, "r");
385
386     while (bytes_to_read > 0) {
387         struct winsize tmp_wsz;
388         int tmp_dots = 0;
389
390         if (ioctl(STDIO_FD, TIOCGWINSZ, &tmp_wsz) == -1) {
391             printf("ioctl error on STDIO\n");
392             return -1;
393         }
394
395         ratio = (double)bytes_read / (double)(files[file_index].size); 
396         tmp_dots = (int)(ratio * (double)prog_len);
397
398         if ((tmp_dots != num_dots) || (tmp_wsz.ws_col != wsz.ws_col)) {
399             int i = 0;
400             int num_blanks = 0;
401             
402             wsz = tmp_wsz;
403             num_dots = tmp_dots;
404             
405             num_blanks = prog_len - num_dots;
406
407             memset(cons_line, 0, 256);
408             snprintf(cons_line, 256, "\r(%s) [", files[file_index].id);
409             
410             for (i = 0; i <= num_dots; i++) {
411                 strcat(cons_line, "=");
412             }
413             
414             for (i = 0; i < num_blanks - 1; i++) {
415                 strcat(cons_line, " ");
416             }
417             
418             strcat(cons_line, "] ");
419
420             //  printf("console width = %d\n", wsz.ws_col);
421             write(STDIO_FD, cons_line, wsz.ws_col);
422         }
423         
424         
425         
426         if (xfer_len > bytes_to_read) {
427             xfer_len = bytes_to_read;
428         }
429         
430         if (fread(xfer_buf, xfer_len, 1, in_file) == 0) {
431             printf("Error reading data file %s\n", filename);
432             exit(-1);
433         }       
434         
435         if (fwrite(xfer_buf, xfer_len, 1, data_file) == 0) {
436             printf("Error writing data file contents");
437             exit(-1);
438         }
439
440
441         bytes_read += xfer_len;
442         bytes_to_read -= xfer_len;
443     }
444
445     strcat(cons_line, "Done\n");
446     write(STDIO_FD, cons_line, wsz.ws_col);
447
448
449     fclose(in_file);
450
451     return 0;
452 }