Merge branch 'mainline' into zfs
[grub2/phcoder.git] / util / grub-fstest.c
blob47222699f4dc1e3489f98962696a0e67fde415f8
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/raid.h>
32 #include <grub/lib/hexdump.h>
33 #include <grub/lib/crc.h>
34 #include <grub/command.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 struct grub_handler_class grub_term_input_class;
57 struct grub_handler_class grub_term_output_class;
59 void
60 grub_refresh (void)
62 fflush (stdout);
65 static grub_err_t
66 execute_command (char *name, int n, char **args)
68 grub_command_t cmd;
70 cmd = grub_command_find (name);
71 if (! cmd)
72 grub_util_error ("Can\'t find command %s", name);
74 return (cmd->func) (cmd, n, args);
77 #define CMD_LS 1
78 #define CMD_CP 2
79 #define CMD_CMP 3
80 #define CMD_HEX 4
81 #define CMD_CRC 6
82 #define CMD_BLOCKLIST 7
84 #define BUF_SIZE 32256
86 static grub_off_t skip, leng;
88 static void
89 read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len))
91 static char buf[BUF_SIZE];
92 grub_file_t file;
93 grub_off_t ofs, len;
95 if ((pathname[0] == '-') && (pathname[1] == 0))
97 grub_device_t dev;
99 dev = grub_device_open (0);
100 if ((! dev) || (! dev->disk))
101 grub_util_error ("Can\'t open device.");
103 grub_util_info ("total sectors : %lld.",
104 (unsigned long long) dev->disk->total_sectors);
106 if (! leng)
107 leng = (dev->disk->total_sectors << GRUB_DISK_SECTOR_BITS) - skip;
109 while (leng)
111 grub_size_t len;
113 len = (leng > BUF_SIZE) ? BUF_SIZE : leng;
115 if (grub_disk_read (dev->disk, 0, skip, len, buf))
116 grub_util_error ("Disk read fails at offset %lld, length %d.",
117 skip, len);
119 if (hook (skip, buf, len))
120 break;
122 skip += len;
123 leng -= len;
126 grub_device_close (dev);
127 return;
130 file = grub_file_open (pathname);
131 if (!file)
133 grub_util_error ("cannot open file %s.", pathname);
134 return;
137 grub_util_info ("file size : %lld.", (unsigned long long) file->size);
139 if (skip > file->size)
141 grub_util_error ("invalid skip value %d.");
142 return;
145 ofs = skip;
146 len = file->size - skip;
147 if ((leng) && (leng < len))
148 len = leng;
150 file->offset = skip;
152 while (len)
154 grub_ssize_t sz;
156 sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len);
157 if (sz < 0)
159 grub_util_error ("read error at offset %llu.", ofs);
160 break;
163 if ((sz == 0) || (hook (ofs, buf, sz)))
164 break;
166 ofs += sz;
167 len -= sz;
170 grub_file_close (file);
173 static void
174 cmd_cp (char *src, char *dest)
176 FILE *ff;
178 auto int cp_hook (grub_off_t ofs, char *buf, int len);
179 int cp_hook (grub_off_t ofs, char *buf, int len)
181 (void) ofs;
183 if ((int) fwrite (buf, 1, len, ff) != len)
185 grub_util_error ("write error.");
186 return 1;
189 return 0;
192 ff = fopen (dest, "wb");
193 if (ff == NULL)
195 grub_util_error ("open error.");
196 return;
198 read_file (src, cp_hook);
199 fclose (ff);
202 static void
203 cmd_cmp (char *src, char *dest)
205 FILE *ff;
206 static char buf_1[BUF_SIZE];
208 auto int cmp_hook (grub_off_t ofs, char *buf, int len);
209 int cmp_hook (grub_off_t ofs, char *buf, int len)
211 if ((int) fread (buf_1, 1, len, ff) != len)
213 grub_util_error ("read error at offset %llu.", ofs);
214 return 1;
217 if (grub_memcmp (buf, buf_1, len))
219 int i;
221 for (i = 0; i < len; i++, ofs++)
222 if (buf_1[i] != buf[i])
224 grub_util_error ("compare fail at offset %llu.", ofs);
225 return 1;
228 return 0;
231 ff = fopen (dest, "rb");
232 if (ff == NULL)
234 grub_util_error ("open error.");
235 return;
238 if ((skip) && (fseeko (ff, skip, SEEK_SET)))
239 grub_util_error ("seek error.");
241 read_file (src, cmp_hook);
242 fclose (ff);
245 static void
246 cmd_hex (char *pathname)
248 auto int hex_hook (grub_off_t ofs, char *buf, int len);
249 int hex_hook (grub_off_t ofs, char *buf, int len)
251 hexdump (ofs, buf, len);
252 return 0;
255 read_file (pathname, hex_hook);
258 static void
259 cmd_crc (char *pathname)
261 grub_uint32_t crc = 0;
263 auto int crc_hook (grub_off_t ofs, char *buf, int len);
264 int crc_hook (grub_off_t ofs, char *buf, int len)
266 (void) ofs;
268 crc = grub_getcrc32 (crc, buf, len);
269 return 0;
272 read_file (pathname, crc_hook);
273 printf ("%08x\n", crc);
276 static void
277 fstest (char **images, int num_disks, int cmd, int n, char **args)
279 char host_file[128];
280 char loop_name[8];
281 char *argv[3] = { "-p", loop_name, host_file};
282 int i;
284 for (i = 0; i < num_disks; i++)
286 if (grub_strlen (images[i]) + 7 > sizeof (host_file))
287 grub_util_error ("Pathname %s too long.", images[i]);
289 grub_sprintf (loop_name, "loop%d", i);
290 grub_sprintf (host_file, "(host)%s", images[i]);
292 if (execute_command ("loopback", 3, argv))
293 grub_util_error ("loopback command fails.");
296 grub_raid_rescan ();
297 switch (cmd)
299 case CMD_LS:
300 execute_command ("ls", n, args);
301 break;
302 case CMD_CP:
303 cmd_cp (args[0], args[1]);
304 break;
305 case CMD_CMP:
306 cmd_cmp (args[0], args[1]);
307 break;
308 case CMD_HEX:
309 cmd_hex (args[0]);
310 break;
311 case CMD_CRC:
312 cmd_crc (args[0]);
313 break;
314 case CMD_BLOCKLIST:
315 execute_command ("blocklist", n, args);
316 grub_printf ("\n");
319 argv[0] = "-d";
321 for (i = 0; i < num_disks; i++)
323 grub_sprintf (loop_name, "loop%d", i);
324 execute_command ("loopback", 2, argv);
328 static struct option options[] = {
329 {"root", required_argument, 0, 'r'},
330 {"skip", required_argument, 0, 's'},
331 {"length", required_argument, 0, 'n'},
332 {"diskcount", required_argument, 0, 'c'},
333 {"debug", required_argument, 0, 'd'},
334 {"help", no_argument, 0, 'h'},
335 {"version", no_argument, 0, 'V'},
336 {"verbose", no_argument, 0, 'v'},
337 {0, 0, 0, 0}
340 static void
341 usage (int status)
343 if (status)
344 fprintf (stderr, "Try ``grub-fstest --help'' for more information.\n");
345 else
346 printf ("\
347 Usage: grub-fstest [OPTION]... IMAGE_PATH COMMANDS\n\
349 Debug tool for filesystem driver.\n\
350 \nCommands:\n\
351 ls PATH list files in PATH\n\
352 cp FILE LOCAL copy FILE to local file LOCAL\n\
353 cmp FILE LOCAL compare FILE with local file LOCAL\n\
354 hex FILE Hex dump FILE\n\
355 crc FILE Get crc32 checksum of FILE\n\
356 blocklist FILE display blocklist of FILE\n\
357 \nOptions:\n\
358 -r, --root=DEVICE_NAME set root device\n\
359 -s, --skip=N skip N bytes from output file\n\
360 -n, --length=N handle N bytes in output file\n\
361 -c, --diskcount=N N input files\n\
362 -d, --debug=S Set debug environment variable\n\
363 -h, --help display this message and exit\n\
364 -V, --version print version information and exit\n\
365 -v, --verbose print verbose messages\n\
367 Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
369 exit (status);
373 main (int argc, char *argv[])
375 char *debug_str = 0, *root = 0, *default_root, *alloc_root;
376 int i, cmd, num_opts, image_index, num_disks = 1;
378 progname = "grub-fstest";
380 /* Find the first non option entry. */
381 for (num_opts = 1; num_opts < argc; num_opts++)
382 if (argv[num_opts][0] == '-')
384 if ((argv[num_opts][2] == 0) && (num_opts < argc - 1) &&
385 ((argv[num_opts][1] == 'r') ||
386 (argv[num_opts][1] == 's') ||
387 (argv[num_opts][1] == 'n') ||
388 (argv[num_opts][1] == 'c') ||
389 (argv[num_opts][1] == 'd')))
390 num_opts++;
392 else
393 break;
395 /* Check for options. */
396 while (1)
398 int c = getopt_long (num_opts, argv, "r:s:n:c:d:hVv", options, 0);
399 char *p;
401 if (c == -1)
402 break;
403 else
404 switch (c)
406 case 'r':
407 root = optarg;
408 break;
410 case 's':
411 skip = grub_strtoul (optarg, &p, 0);
412 if (*p == 's')
413 skip <<= GRUB_DISK_SECTOR_BITS;
414 break;
416 case 'n':
417 leng = grub_strtoul (optarg, &p, 0);
418 if (*p == 's')
419 leng <<= GRUB_DISK_SECTOR_BITS;
420 break;
422 case 'c':
423 num_disks = grub_strtoul (optarg, NULL, 0);
424 if (num_disks < 1)
426 fprintf (stderr, "Invalid disk count.\n");
427 usage (1);
429 break;
431 case 'd':
432 debug_str = optarg;
433 break;
435 case 'h':
436 usage (0);
437 break;
439 case 'V':
440 printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
441 return 0;
443 case 'v':
444 verbosity++;
445 break;
447 default:
448 usage (1);
449 break;
453 /* Obtain PATH. */
454 if (optind + num_disks - 1 >= argc)
456 fprintf (stderr, "Not enough pathname.\n");
457 usage (1);
460 image_index = optind;
461 for (i = 0; i < num_disks; i++, optind++)
462 if (argv[optind][0] != '/')
464 fprintf (stderr, "Must use absolute path.\n");
465 usage (1);
468 cmd = 0;
469 if (optind < argc)
471 int nparm = 0;
473 if (!grub_strcmp (argv[optind], "ls"))
475 cmd = CMD_LS;
477 else if (!grub_strcmp (argv[optind], "cp"))
479 cmd = CMD_CP;
480 nparm = 2;
482 else if (!grub_strcmp (argv[optind], "cmp"))
484 cmd = CMD_CMP;
485 nparm = 2;
487 else if (!grub_strcmp (argv[optind], "hex"))
489 cmd = CMD_HEX;
490 nparm = 1;
492 else if (!grub_strcmp (argv[optind], "crc"))
494 cmd = CMD_CRC;
495 nparm = 1;
497 else if (!grub_strcmp (argv[optind], "blocklist"))
499 cmd = CMD_BLOCKLIST;
500 nparm = 1;
502 else
504 fprintf (stderr, "Invalid command %s.\n", argv[optind]);
505 usage (1);
508 if (optind + 1 + nparm > argc)
510 fprintf (stderr, "Invalid parameter for command %s.\n",
511 argv[optind]);
512 usage (1);
515 optind++;
517 else
519 fprintf (stderr, "No command is specified.\n");
520 usage (1);
523 /* Initialize all modules. */
524 grub_init_all ();
526 if (debug_str)
527 grub_env_set ("debug", debug_str);
529 default_root = (num_disks == 1) ? "loop0" : "md0";
530 alloc_root = 0;
531 if (root)
533 if ((*root >= '0') && (*root <= '9'))
535 alloc_root = xmalloc (strlen (default_root) + strlen (root) + 2);
537 sprintf (alloc_root, "%s,%s", default_root, root);
538 root = alloc_root;
541 else
542 root = default_root;
544 grub_env_set ("root", root);
546 if (alloc_root)
547 free (alloc_root);
549 /* Do it. */
550 fstest (argv + image_index, num_disks, cmd, argc - optind, argv + optind);
552 /* Free resources. */
553 grub_fini_all ();
555 return 0;