- added instructions how to update the online documentation
[bochs-mirror.git] / misc / bxcommit.c
blob9f998d98b94e33cdf7bedbdee0c972cfbb896d59
1 /*
2 * misc/bximage.c
3 * $Id: bxcommit.c,v 1.13 2008/02/05 22:57:42 sshwarts Exp $
5 * Commits a redolog file in a flat file for bochs images.
7 */
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #ifndef _MSC_VER
13 #include <unistd.h>
14 #else
15 #include <io.h>
16 #endif
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <assert.h>
22 #ifdef WIN32
23 # include <conio.h>
24 #endif
25 #include "config.h"
27 #include <string.h>
29 #if !BX_HAVE_SNPRINTF
30 #include <stdarg.h>
31 /* XXX use real snprintf */
32 /* if they don't have snprintf, just use sprintf */
33 int snprintf (char *s, size_t maxlen, const char *format, ...)
35 va_list arg;
36 int done;
38 va_start (arg, format);
39 done = vsprintf (s, format, arg);
40 va_end (arg);
42 return done;
44 #endif /* !BX_HAVE_SNPRINTF */
46 #include "../osdep.h"
48 #define HDIMAGE_HEADERS_ONLY 1
49 #include "../iodev/hdimage.h"
51 char *EOF_ERR = "ERROR: End of input";
52 char *rcsid = "$Id: bxcommit.c,v 1.13 2008/02/05 22:57:42 sshwarts Exp $";
53 char *divider = "========================================================================";
55 void myexit (int code)
57 #ifdef WIN32
58 printf ("\nPress any key to continue\n");
59 getch();
60 #endif
61 exit(code);
64 /* stolen from main.cc */
65 void bx_center_print (FILE *file, char *line, int maxwidth)
67 int imax;
68 int i;
69 imax = (maxwidth - strlen(line)) >> 1;
70 for (i=0; i<imax; i++) fputc (' ', file);
71 fputs (line, file);
74 void
75 print_banner ()
77 printf ("%s\n", divider);
78 bx_center_print (stdout, "bxcommit\n", 72);
79 bx_center_print (stdout, "Undoable Disk Image Commit Tool for Bochs\n", 72);
80 bx_center_print (stdout, rcsid, 72);
81 printf ("\n%s\n", divider);
84 /* this is how we crash */
85 void fatal (char *c)
87 printf ("%s\n", c);
88 myexit (1);
91 /* remove leading spaces, newline junk at end. returns pointer to
92 cleaned string, which is between s0 and the null */
93 char *
94 clean_string (char *s0)
96 char *s = s0;
97 char *ptr;
98 /* find first nonblank */
99 while (isspace (*s))
100 s++;
101 /* truncate string at first non-alphanumeric */
102 ptr = s;
103 while (isprint (*ptr))
104 ptr++;
105 *ptr = 0;
106 return s;
109 /* returns 0 on success, -1 on failure. The value goes into out. */
111 ask_int (char *prompt, int min, int max, int the_default, int *out)
113 int n = max + 1;
114 char buffer[1024];
115 char *clean;
116 int illegal;
117 while (1) {
118 printf ("%s", prompt);
119 printf ("[%d] ", the_default);
120 if (!fgets (buffer, sizeof(buffer), stdin))
121 return -1;
122 clean = clean_string (buffer);
123 if (strlen(clean) < 1) {
124 // empty line, use the default
125 *out = the_default;
126 return 0;
128 illegal = (1 != sscanf (buffer, "%d", &n));
129 if (illegal || n<min || n>max) {
130 printf ("Your choice (%s) was not an integer between %d and %d.\n\n",
131 clean, min, max);
132 } else {
133 // choice is okay
134 *out = n;
135 return 0;
141 ask_menu (char *prompt, int n_choices, char *choice[], int the_default, int *out)
143 char buffer[1024];
144 char *clean;
145 int i;
146 *out = -1;
147 while (1) {
148 printf ("%s", prompt);
149 printf ("[%s] ", choice[the_default]);
150 if (!fgets (buffer, sizeof(buffer), stdin))
151 return -1;
152 clean = clean_string (buffer);
153 if (strlen(clean) < 1) {
154 // empty line, use the default
155 *out = the_default;
156 return 0;
158 for (i=0; i<n_choices; i++) {
159 if (!strcmp (choice[i], clean)) {
160 // matched, return the choice number
161 *out = i;
162 return 0;
165 printf ("Your choice (%s) did not match any of the choices:\n", clean);
166 for (i=0; i<n_choices; i++) {
167 if (i>0) printf (", ");
168 printf ("%s", choice[i]);
170 printf ("\n");
175 ask_yn (char *prompt, int the_default, int *out)
177 char buffer[16];
178 char *clean;
179 *out = -1;
180 while (1) {
181 printf ("%s", prompt);
182 printf ("[%s] ", the_default?"yes":"no");
183 if (!fgets (buffer, sizeof(buffer), stdin))
184 return -1;
185 clean = clean_string (buffer);
186 if (strlen(clean) < 1) {
187 // empty line, use the default
188 *out = the_default;
189 return 0;
191 switch (tolower(clean[0])) {
192 case 'y': *out=1; return 0;
193 case 'n': *out=0; return 0;
195 printf ("Please type either yes or no.\n");
200 ask_string (char *prompt, char *the_default, char *out)
202 char buffer[1024];
203 char *clean;
204 out[0] = 0;
205 printf ("%s", prompt);
206 printf ("[%s] ", the_default);
207 if (!fgets (buffer, sizeof(buffer), stdin))
208 return -1;
209 clean = clean_string (buffer);
210 if (strlen(clean) < 1) {
211 // empty line, use the default
212 strcpy (out, the_default);
213 return 0;
215 strcpy (out, clean);
216 return 0;
219 /* produce the image file */
220 int commit_redolog (char *flatname, char *redologname )
222 int flatfd, redologfd;
223 redolog_header_t header;
224 Bit32u *catalog, catalog_size;
225 Bit8u *bitmap;
226 Bit32u i, bitmap_blocs, extent_blocs;
227 Bit8u buffer[512];
229 // check if flat file exists
230 flatfd = open (flatname, O_WRONLY
231 #ifdef O_BINARY
232 | O_BINARY
233 #endif
235 if (flatfd<0) {
236 fatal ("ERROR: flat file not found or not writable");
239 // Check if redolog exists
240 printf("%s\n",redologname);
241 redologfd = open (redologname, O_RDONLY
242 #ifdef O_BINARY
243 | O_BINARY
244 #endif
246 if (redologfd<0) {
247 fatal ("ERROR: redolog file not found");
250 printf ("\nReading redolog header: [");
252 if (read(redologfd, &header, STANDARD_HEADER_SIZE) != STANDARD_HEADER_SIZE)
253 fatal ("\nERROR: while reading redolog header!");
255 // Print infos on redlog
256 printf("Type='%s', Subtype='%s', Version=%d.%d] Done.",
257 header.standard.type, header.standard.subtype,
258 dtoh32(header.standard.version)/0x10000,
259 dtoh32(header.standard.version)%0x10000);
261 printf ("\nChecking redolog header: [");
263 if (strcmp((char *)header.standard.magic, STANDARD_HEADER_MAGIC) != 0)
264 fatal ("\nERROR: bad magic in redolog header!");
266 if (strcmp((char *)header.standard.type, REDOLOG_TYPE) != 0)
267 fatal ("\nERROR: bad type in redolog header!");
269 if (strcmp((char *)header.standard.subtype, REDOLOG_SUBTYPE_UNDOABLE) != 0)
270 fatal ("\nERROR: bad subtype in redolog header!");
272 if (header.standard.version != htod32(STANDARD_HEADER_VERSION))
273 fatal ("\nERROR: bad version in redolog header!");
275 printf("#entries=%d, bitmap size=%d, exent size = %d] Done.",
276 dtoh32(header.specific.catalog),
277 dtoh32(header.specific.bitmap),
278 dtoh32(header.specific.extent));
280 catalog = (Bit32u*)malloc(dtoh32(header.specific.catalog) * sizeof(Bit32u));
281 bitmap = (Bit8u*)malloc(dtoh32(header.specific.bitmap));
282 printf ("\nReading Catalog: [");
284 lseek(redologfd, dtoh32(header.standard.header), SEEK_SET);
286 catalog_size = dtoh32(header.specific.catalog) * sizeof(Bit32u);
287 if ((Bit32u) read(redologfd, catalog, catalog_size) != catalog_size)
288 fatal ("\nERROR: while reading redolog catalog!");
290 printf ("] Done.");
292 printf ("\nCommitting changes to flat file: [ 0%%]");
294 bitmap_blocs = 1 + (dtoh32(header.specific.bitmap) - 1) / 512;
295 extent_blocs = 1 + (dtoh32(header.specific.extent) - 1) / 512;
297 for(i=0; i<dtoh32(header.specific.catalog); i++)
299 printf("\x8\x8\x8\x8\x8%3d%%]", (i+1)*100/dtoh32(header.specific.catalog));
300 fflush(stdout);
302 if (dtoh32(catalog[i]) != REDOLOG_PAGE_NOT_ALLOCATED)
304 Bit64s bitmap_offset;
305 Bit32u bitmap_size, j;
307 bitmap_offset = (Bit64s)STANDARD_HEADER_SIZE + (dtoh32(header.specific.catalog) * sizeof(Bit32u));
308 bitmap_offset += (Bit64s)512 * dtoh32(catalog[i]) * (extent_blocs + bitmap_blocs);
310 // Read bitmap
311 lseek(redologfd, bitmap_offset, SEEK_SET);
313 bitmap_size = dtoh32(header.specific.bitmap);
314 if ((Bit32u) read(redologfd, bitmap, bitmap_size) != bitmap_size)
315 fatal ("\nERROR: while reading bitmap from redolog !");
317 for(j=0; j<dtoh32(header.specific.bitmap); j++)
319 Bit32u bit;
321 for(bit=0; bit<8; bit++)
323 if ( (bitmap[j] & (1<<bit)) != 0)
325 Bit64s flat_offset, bloc_offset;
327 bloc_offset = bitmap_offset + ((Bit64s)512 * (bitmap_blocs + ((j*8)+bit)));
329 lseek(redologfd, (off_t)bloc_offset, SEEK_SET);
331 if (read(redologfd, buffer, 512) != 512)
332 fatal ("\nERROR: while reading bloc from redolog !");
334 flat_offset = (Bit64s)i * (dtoh32(header.specific.extent));
335 flat_offset += (Bit64s)512 * ((j * 8) + bit);
337 lseek(flatfd, (off_t)flat_offset, SEEK_SET);
339 if (write(flatfd, buffer, 512) != 512)
340 fatal ("\nERROR: while writing bloc in flatfile !");
347 printf (" Done.");
348 printf ("\n");
350 close (flatfd);
351 close (redologfd);
352 return 0;
355 int main()
357 char filename[256];
358 char tmplogname[256];
359 char redologname[256];
360 int remove;
362 print_banner();
363 filename[0] = 0;
364 redologname[0] = 0;
366 if (ask_string("\nWhat is the flat image name?\n", "c.img", filename) < 0)
367 fatal (EOF_ERR);
369 snprintf(tmplogname,256,"%s%s", filename, UNDOABLE_REDOLOG_EXTENSION);
371 if (ask_string("\nWhat is the redolog name?\n", tmplogname, redologname) < 0)
372 fatal (EOF_ERR);
374 if (ask_yn("\nShall I remove the redolog afterwards?\n", 1, &remove) < 0)
375 fatal (EOF_ERR);
377 commit_redolog(filename, redologname);
379 if (remove) {
380 if (unlink(redologname) != 0)
381 fatal ("ERROR: while removing the redolog !\n");
384 // make picky compilers (c++, gcc) happy,
385 // even though we leave via 'myexit' just above
386 return 0;