2008-11-14 Robert Millan <rmh@aybabtu.com>
[grub2/phcoder.git] / util / grub-fstest.c
blobb622f849149b841ce028828035b6c19257989712
1 /* grub-fstest.c - debug tool for filesystem driver */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <config.h>
21 #include <grub/types.h>
22 #include <grub/util/misc.h>
23 #include <grub/misc.h>
24 #include <grub/device.h>
25 #include <grub/disk.h>
26 #include <grub/file.h>
27 #include <grub/fs.h>
28 #include <grub/env.h>
29 #include <grub/term.h>
30 #include <grub/mm.h>
31 #include <grub/normal.h>
32 #include <grub/raid.h>
33 #include <grub/lib/hexdump.h>
34 #include <grub/lib/crc.h>
36 #include <grub_fstest_init.h>
38 #include <stdio.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include <getopt.h>
44 void
45 grub_putchar (int c)
47 putchar (c);
50 int
51 grub_getkey (void)
53 return -1;
56 grub_term_t
57 grub_term_get_current_input (void)
59 return 0;
62 grub_term_t
63 grub_term_get_current_output (void)
65 return 0;
68 void
69 grub_refresh (void)
71 fflush (stdout);
74 static struct grub_command cmd_loopback;
75 static struct grub_command cmd_blocklist;
76 static struct grub_command cmd_ls;
78 grub_command_t
79 grub_register_command (const char *name,
80 grub_err_t (*func) (struct grub_arg_list * state,
81 int argc, char **args),
82 unsigned flags,
83 const char *summary __attribute__ ((unused)),
84 const char *description __attribute__ ((unused)),
85 const struct grub_arg_option *options)
87 grub_command_t cmd = 0;
89 if (!grub_strcmp (name, "loopback"))
90 cmd = &cmd_loopback;
91 else if (!grub_strcmp (name, "blocklist"))
92 cmd = &cmd_blocklist;
93 else if (!grub_strcmp (name, "ls"))
94 cmd = &cmd_ls;
96 if (cmd)
98 cmd->func = func;
99 cmd->flags = flags;
100 cmd->options = options;
102 return NULL;
105 static grub_err_t
106 execute_command (grub_command_t cmd, int n, char **args)
108 int maxargs = 0;
109 grub_err_t ret = 0;
110 struct grub_arg_list *state;
111 struct grub_arg_option *parser;
112 char **parsed_arglist;
113 int numargs;
115 /* Count the amount of options the command has. */
116 parser = (struct grub_arg_option *) cmd->options;
117 while (parser && (parser++)->doc)
118 maxargs++;
120 /* Set up the option state. */
121 state = grub_malloc (sizeof (struct grub_arg_list) * maxargs);
122 grub_memset (state, 0, sizeof (struct grub_arg_list) * maxargs);
124 /* Start the command. */
125 if (!(cmd->flags & GRUB_COMMAND_FLAG_NO_ARG_PARSE))
127 if (grub_arg_parse (cmd, n, args, state, &parsed_arglist, &numargs))
128 ret = (cmd->func) (state, numargs, parsed_arglist);
130 else
131 ret = (cmd->func) (state, n, args);
133 grub_free (state);
135 return ret;
138 void
139 grub_unregister_command (const char *name __attribute__ ((unused)))
143 #define CMD_LS 1
144 #define CMD_CP 2
145 #define CMD_CMP 3
146 #define CMD_HEX 4
147 #define CMD_CRC 6
148 #define CMD_BLOCKLIST 7
150 #define BUF_SIZE 32256
152 static grub_off_t skip, leng;
154 static void
155 read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len))
157 static char buf[BUF_SIZE];
158 grub_file_t file;
159 grub_off_t ofs, len;
161 if ((pathname[0] == '-') && (pathname[1] == 0))
163 grub_device_t dev;
165 dev = grub_device_open (0);
166 if ((! dev) || (! dev->disk))
167 grub_util_error ("Can\'t open device.");
169 grub_util_info ("total sectors : %lld.",
170 (unsigned long long) dev->disk->total_sectors);
172 if (! leng)
173 leng = (dev->disk->total_sectors << GRUB_DISK_SECTOR_BITS) - skip;
175 while (leng)
177 grub_size_t len;
179 len = (leng > BUF_SIZE) ? BUF_SIZE : leng;
181 if (grub_disk_read (dev->disk, 0, skip, len, buf))
182 grub_util_error ("Disk read fails at offset %lld, length %d.",
183 skip, len);
185 if (hook (skip, buf, len))
186 break;
188 skip += len;
189 leng -= len;
192 grub_device_close (dev);
193 return;
196 file = grub_file_open (pathname);
197 if (!file)
199 grub_util_error ("cannot open file %s.", pathname);
200 return;
203 grub_util_info ("file size : %lld.", (unsigned long long) file->size);
205 if (skip > file->size)
207 grub_util_error ("invalid skip value %d.");
208 return;
211 ofs = skip;
212 len = file->size - skip;
213 if ((leng) && (leng < len))
214 len = leng;
216 file->offset = skip;
218 while (len)
220 grub_ssize_t sz;
222 sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len);
223 if (sz < 0)
225 grub_util_error ("read error at offset %llu.", ofs);
226 break;
229 if ((sz == 0) || (hook (ofs, buf, sz)))
230 break;
232 ofs += sz;
233 len -= sz;
236 grub_file_close (file);
239 static void
240 cmd_cp (char *src, char *dest)
242 FILE *ff;
244 auto int cp_hook (grub_off_t ofs, char *buf, int len);
245 int cp_hook (grub_off_t ofs, char *buf, int len)
247 (void) ofs;
249 if ((int) fwrite (buf, 1, len, ff) != len)
251 grub_util_error ("write error.");
252 return 1;
255 return 0;
258 ff = fopen (dest, "wb");
259 if (ff == NULL)
261 grub_util_error ("open error.");
262 return;
264 read_file (src, cp_hook);
265 fclose (ff);
268 static void
269 cmd_cmp (char *src, char *dest)
271 FILE *ff;
272 static char buf_1[BUF_SIZE];
274 auto int cmp_hook (grub_off_t ofs, char *buf, int len);
275 int cmp_hook (grub_off_t ofs, char *buf, int len)
277 if ((int) fread (buf_1, 1, len, ff) != len)
279 grub_util_error ("read error at offset %llu.", ofs);
280 return 1;
283 if (grub_memcmp (buf, buf_1, len))
285 int i;
287 for (i = 0; i < len; i++, ofs++)
288 if (buf_1[i] != buf[i])
290 grub_util_error ("compare fail at offset %llu.", ofs);
291 return 1;
294 return 0;
297 ff = fopen (dest, "rb");
298 if (ff == NULL)
300 grub_util_error ("open error.");
301 return;
304 if ((skip) && (fseeko (ff, skip, SEEK_SET)))
305 grub_util_error ("seek error.");
307 read_file (src, cmp_hook);
308 fclose (ff);
311 static void
312 cmd_hex (char *pathname)
314 auto int hex_hook (grub_off_t ofs, char *buf, int len);
315 int hex_hook (grub_off_t ofs, char *buf, int len)
317 hexdump (ofs, buf, len);
318 return 0;
321 read_file (pathname, hex_hook);
324 static void
325 cmd_crc (char *pathname)
327 grub_uint32_t crc = 0;
329 auto int crc_hook (grub_off_t ofs, char *buf, int len);
330 int crc_hook (grub_off_t ofs, char *buf, int len)
332 (void) ofs;
334 crc = grub_getcrc32 (crc, buf, len);
335 return 0;
338 read_file (pathname, crc_hook);
339 printf ("%08x\n", crc);
342 static void
343 fstest (char **images, int num_disks, int cmd, int n, char **args)
345 char host_file[128];
346 char loop_name[8];
347 char *argv[3] = { "-p", loop_name, host_file};
348 int i;
350 for (i = 0; i < num_disks; i++)
352 if (grub_strlen (images[i]) + 7 > sizeof (host_file))
353 grub_util_error ("Pathname %s too long.", images[i]);
355 grub_sprintf (loop_name, "loop%d", i);
356 grub_sprintf (host_file, "(host)%s", images[i]);
358 if (execute_command (&cmd_loopback, 3, argv))
359 grub_util_error ("loopback command fails.");
362 grub_raid_rescan ();
363 switch (cmd)
365 case CMD_LS:
366 execute_command (&cmd_ls, n, args);
367 break;
368 case CMD_CP:
369 cmd_cp (args[0], args[1]);
370 break;
371 case CMD_CMP:
372 cmd_cmp (args[0], args[1]);
373 break;
374 case CMD_HEX:
375 cmd_hex (args[0]);
376 break;
377 case CMD_CRC:
378 cmd_crc (args[0]);
379 break;
380 case CMD_BLOCKLIST:
381 execute_command (&cmd_blocklist, n, args);
382 grub_printf ("\n");
385 argv[0] = "-d";
387 for (i = 0; i < num_disks; i++)
389 grub_sprintf (loop_name, "loop%d", i);
390 execute_command (&cmd_loopback, 2, argv);
394 static struct option options[] = {
395 {"root", required_argument, 0, 'r'},
396 {"skip", required_argument, 0, 's'},
397 {"length", required_argument, 0, 'n'},
398 {"diskcount", required_argument, 0, 'c'},
399 {"debug", required_argument, 0, 'd'},
400 {"help", no_argument, 0, 'h'},
401 {"version", no_argument, 0, 'V'},
402 {"verbose", no_argument, 0, 'v'},
403 {0, 0, 0, 0}
406 static void
407 usage (int status)
409 if (status)
410 fprintf (stderr, "Try ``grub-fstest --help'' for more information.\n");
411 else
412 printf ("\
413 Usage: grub-fstest [OPTION]... IMAGE_PATH COMMANDS\n\
415 Debug tool for filesystem driver.\n\
416 \nCommands:\n\
417 ls PATH list files in PATH\n\
418 cp FILE LOCAL copy FILE to local file LOCAL\n\
419 cmp FILE LOCAL compare FILE with local file LOCAL\n\
420 hex FILE Hex dump FILE\n\
421 crc FILE Get crc32 checksum of FILE\n\
422 blocklist FILE display blocklist of FILE\n\
423 \nOptions:\n\
424 -r, --root=DEVICE_NAME set root device\n\
425 -s, --skip=N skip N bytes from output file\n\
426 -n, --length=N handle N bytes in output file\n\
427 -c, --diskcount=N N input files\n\
428 -d, --debug=S Set debug environment variable\n\
429 -h, --help display this message and exit\n\
430 -V, --version print version information and exit\n\
431 -v, --verbose print verbose messages\n\
433 Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
435 exit (status);
439 main (int argc, char *argv[])
441 char *debug_str = 0, *root = 0, *default_root, *alloc_root;
442 int i, cmd, num_opts, image_index, num_disks = 1;
444 progname = "grub-fstest";
446 /* Find the first non option entry. */
447 for (num_opts = 1; num_opts < argc; num_opts++)
448 if (argv[num_opts][0] == '-')
450 if ((argv[num_opts][2] == 0) && (num_opts < argc - 1) &&
451 ((argv[num_opts][1] == 'r') ||
452 (argv[num_opts][1] == 's') ||
453 (argv[num_opts][1] == 'n') ||
454 (argv[num_opts][1] == 'c') ||
455 (argv[num_opts][1] == 'd')))
456 num_opts++;
458 else
459 break;
461 /* Check for options. */
462 while (1)
464 int c = getopt_long (num_opts, argv, "r:s:n:c:d:hVv", options, 0);
465 char *p;
467 if (c == -1)
468 break;
469 else
470 switch (c)
472 case 'r':
473 root = optarg;
474 break;
476 case 's':
477 skip = grub_strtoul (optarg, &p, 0);
478 if (*p == 's')
479 skip <<= GRUB_DISK_SECTOR_BITS;
480 break;
482 case 'n':
483 leng = grub_strtoul (optarg, &p, 0);
484 if (*p == 's')
485 leng <<= GRUB_DISK_SECTOR_BITS;
486 break;
488 case 'c':
489 num_disks = grub_strtoul (optarg, NULL, 0);
490 if (num_disks < 1)
492 fprintf (stderr, "Invalid disk count.\n");
493 usage (1);
495 break;
497 case 'd':
498 debug_str = optarg;
499 break;
501 case 'h':
502 usage (0);
503 break;
505 case 'V':
506 printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
507 return 0;
509 case 'v':
510 verbosity++;
511 break;
513 default:
514 usage (1);
515 break;
519 /* Obtain PATH. */
520 if (optind + num_disks - 1 >= argc)
522 fprintf (stderr, "Not enough pathname.\n");
523 usage (1);
526 image_index = optind;
527 for (i = 0; i < num_disks; i++, optind++)
528 if (argv[optind][0] != '/')
530 fprintf (stderr, "Must use absolute path.\n");
531 usage (1);
534 cmd = 0;
535 if (optind < argc)
537 int nparm = 0;
539 if (!grub_strcmp (argv[optind], "ls"))
541 cmd = CMD_LS;
543 else if (!grub_strcmp (argv[optind], "cp"))
545 cmd = CMD_CP;
546 nparm = 2;
548 else if (!grub_strcmp (argv[optind], "cmp"))
550 cmd = CMD_CMP;
551 nparm = 2;
553 else if (!grub_strcmp (argv[optind], "hex"))
555 cmd = CMD_HEX;
556 nparm = 1;
558 else if (!grub_strcmp (argv[optind], "crc"))
560 cmd = CMD_CRC;
561 nparm = 1;
563 else if (!grub_strcmp (argv[optind], "blocklist"))
565 cmd = CMD_BLOCKLIST;
566 nparm = 1;
568 else
570 fprintf (stderr, "Invalid command %s.\n", argv[optind]);
571 usage (1);
574 if (optind + 1 + nparm > argc)
576 fprintf (stderr, "Invalid parameter for command %s.\n",
577 argv[optind]);
578 usage (1);
581 optind++;
583 else
585 fprintf (stderr, "No command is specified.\n");
586 usage (1);
589 /* Initialize all modules. */
590 grub_init_all ();
592 if (debug_str)
593 grub_env_set ("debug", debug_str);
595 default_root = (num_disks == 1) ? "loop0" : "md0";
596 alloc_root = 0;
597 if (root)
599 if ((*root >= '0') && (*root <= '9'))
601 alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2);
603 sprintf (alloc_root, "%s,%s", default_root, root);
604 root = alloc_root;
607 else
608 root = default_root;
610 grub_env_set ("root", root);
612 if (alloc_root)
613 free (alloc_root);
615 /* Do it. */
616 fstest (argv + image_index, num_disks, cmd, argc - optind, argv + optind);
618 /* Free resources. */
619 grub_fini_all ();
621 return 0;