1 /* grub-fstest.c - debug tool for filesystem driver */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009,2010 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/>.
21 #include <grub/types.h>
22 #include <grub/emu/misc.h>
23 #include <grub/util/misc.h>
24 #include <grub/misc.h>
25 #include <grub/device.h>
26 #include <grub/disk.h>
27 #include <grub/file.h>
30 #include <grub/term.h>
32 #include <grub/lib/hexdump.h>
33 #include <grub/crypto.h>
34 #include <grub/command.h>
35 #include <grub/i18n.h>
36 #include <grub/zfs/zfs.h>
37 #include <grub/emu/hostfile.h>
44 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
45 #pragma GCC diagnostic ignored "-Wmissing-declarations"
47 #pragma GCC diagnostic error "-Wmissing-prototypes"
48 #pragma GCC diagnostic error "-Wmissing-declarations"
51 execute_command (const char *name
, int n
, char **args
)
55 cmd
= grub_command_find (name
);
57 grub_util_error (_("can't find command `%s'"), name
);
59 return (cmd
->func
) (cmd
, n
, args
);
74 #define BUF_SIZE 32256
76 static grub_disk_addr_t skip
, leng
;
77 static int uncompress
= 0;
80 read_file (char *pathname
, int (*hook
) (grub_off_t ofs
, char *buf
, int len
, void *hook_arg
), void *hook_arg
)
82 static char buf
[BUF_SIZE
];
85 if ((pathname
[0] == '-') && (pathname
[1] == 0))
89 dev
= grub_device_open (0);
90 if ((! dev
) || (! dev
->disk
))
91 grub_util_error ("%s", grub_errmsg
);
93 grub_util_info ("total sectors : %" GRUB_HOST_PRIuLONG_LONG
,
94 (unsigned long long) dev
->disk
->total_sectors
);
97 leng
= (dev
->disk
->total_sectors
<< GRUB_DISK_SECTOR_BITS
) - skip
;
103 len
= (leng
> BUF_SIZE
) ? BUF_SIZE
: leng
;
105 if (grub_disk_read (dev
->disk
, 0, skip
, len
, buf
))
107 char *msg
= grub_xasprintf (_("disk read fails at offset %lld, length %lld"),
108 (long long) skip
, (long long) len
);
109 grub_util_error ("%s", msg
);
112 if (hook (skip
, buf
, len
, hook_arg
))
119 grub_device_close (dev
);
124 grub_file_filter_disable_compression ();
125 file
= grub_file_open (pathname
);
128 grub_util_error (_("cannot open `%s': %s"), pathname
,
133 grub_util_info ("file size : %" GRUB_HOST_PRIuLONG_LONG
,
134 (unsigned long long) file
->size
);
136 if (skip
> file
->size
)
138 char *msg
= grub_xasprintf (_("invalid skip value %lld"),
139 (unsigned long long) skip
);
140 grub_util_error ("%s", msg
);
147 len
= file
->size
- skip
;
148 if ((leng
) && (leng
< len
))
157 sz
= grub_file_read (file
, buf
, (len
> BUF_SIZE
) ? BUF_SIZE
: len
);
160 char *msg
= grub_xasprintf (_("read error at offset %llu: %s"),
161 (unsigned long long) ofs
, grub_errmsg
);
162 grub_util_error ("%s", msg
);
166 if ((sz
== 0) || (hook (ofs
, buf
, sz
, hook_arg
)))
174 grub_file_close (file
);
184 cp_hook (grub_off_t ofs
, char *buf
, int len
, void *_ctx
)
186 struct cp_hook_ctx
*ctx
= _ctx
;
189 if ((int) fwrite (buf
, 1, len
, ctx
->ff
) != len
)
191 grub_util_error (_("cannot write to `%s': %s"),
192 ctx
->dest
, strerror (errno
));
200 cmd_cp (char *src
, const char *dest
)
202 struct cp_hook_ctx ctx
=
207 ctx
.ff
= grub_util_fopen (dest
, "wb");
210 grub_util_error (_("cannot open OS file `%s': %s"), dest
,
214 read_file (src
, cp_hook
, &ctx
);
219 cat_hook (grub_off_t ofs
, char *buf
, int len
, void *_arg
__attribute__ ((unused
)))
223 if ((int) fwrite (buf
, 1, len
, stdout
) != len
)
225 grub_util_error (_("cannot write to the stdout: %s"),
236 read_file (src
, cat_hook
, 0);
240 cmp_hook (grub_off_t ofs
, char *buf
, int len
, void *ff_in
)
243 static char buf_1
[BUF_SIZE
];
244 if ((int) fread (buf_1
, 1, len
, ff
) != len
)
246 char *msg
= grub_xasprintf (_("read error at offset %llu: %s"),
247 (unsigned long long) ofs
, grub_errmsg
);
248 grub_util_error ("%s", msg
);
252 if (grub_memcmp (buf
, buf_1
, len
) != 0)
256 for (i
= 0; i
< len
; i
++, ofs
++)
257 if (buf_1
[i
] != buf
[i
])
259 char *msg
= grub_xasprintf (_("compare fail at offset %llu"),
260 (unsigned long long) ofs
);
261 grub_util_error ("%s", msg
);
270 cmd_cmp (char *src
, char *dest
)
274 if (grub_util_is_directory (dest
))
276 grub_util_fd_dir_t dir
= grub_util_fd_opendir (dest
);
277 grub_util_fd_dirent_t entry
;
280 grub_util_error (_("OS file %s open error: %s"), dest
,
281 grub_util_fd_strerror ());
284 while ((entry
= grub_util_fd_readdir (dir
)))
286 char *srcnew
, *destnew
;
288 if (strcmp (entry
->d_name
, ".") == 0
289 || strcmp (entry
->d_name
, "..") == 0)
291 srcnew
= xmalloc (strlen (src
) + sizeof ("/")
292 + strlen (entry
->d_name
));
293 destnew
= xmalloc (strlen (dest
) + sizeof ("/")
294 + strlen (entry
->d_name
));
295 ptr
= grub_stpcpy (srcnew
, src
);
297 strcpy (ptr
, entry
->d_name
);
298 ptr
= grub_stpcpy (destnew
, dest
);
300 strcpy (ptr
, entry
->d_name
);
302 if (grub_util_is_special_file (destnew
))
305 cmd_cmp (srcnew
, destnew
);
307 grub_util_fd_closedir (dir
);
311 ff
= grub_util_fopen (dest
, "rb");
314 grub_util_error (_("OS file %s open error: %s"), dest
,
319 if ((skip
) && (fseeko (ff
, skip
, SEEK_SET
)))
320 grub_util_error (_("cannot seek `%s': %s"), dest
,
323 read_file (src
, cmp_hook
, ff
);
328 fseek (ff
, 0, SEEK_END
);
329 if (pre
!= ftell (ff
))
330 grub_util_error ("%s", _("unexpected end of file"));
336 hex_hook (grub_off_t ofs
, char *buf
, int len
, void *arg
__attribute__ ((unused
)))
338 hexdump (ofs
, buf
, len
);
343 cmd_hex (char *pathname
)
345 read_file (pathname
, hex_hook
, 0);
349 crc_hook (grub_off_t ofs
, char *buf
, int len
, void *crc_ctx
)
353 GRUB_MD_CRC32
->write(crc_ctx
, buf
, len
);
358 cmd_crc (char *pathname
)
360 grub_uint8_t
*crc32_context
= xmalloc (GRUB_MD_CRC32
->contextsize
);
361 GRUB_MD_CRC32
->init(crc32_context
);
363 read_file (pathname
, crc_hook
, crc32_context
);
364 GRUB_MD_CRC32
->final(crc32_context
);
366 grub_be_to_cpu32 (grub_get_unaligned32 (GRUB_MD_CRC32
->read (crc32_context
))));
367 free (crc32_context
);
370 static const char *root
= NULL
;
371 static int args_count
= 0;
372 static int nparm
= 0;
373 static int num_disks
= 1;
374 static char **images
= NULL
;
376 static char *debug_str
= NULL
;
377 static char **args
= NULL
;
378 static int mount_crypt
= 0;
387 for (i
= 0; i
< num_disks
; i
++)
390 loop_name
= grub_xasprintf ("loop%d", i
);
392 grub_util_error ("%s", grub_errmsg
);
394 host_file
= grub_xasprintf ("(host)%s", images
[i
]);
396 grub_util_error ("%s", grub_errmsg
);
401 if (execute_command ("loopback", 2, argv
))
402 grub_util_error (_("`loopback' command fails: %s"), grub_errmsg
);
404 grub_free (loop_name
);
405 grub_free (host_file
);
411 char *argv
[2] = { xstrdup ("-a"), NULL
};
412 if (execute_command ("cryptomount", 1, argv
))
413 grub_util_error (_("`cryptomount' command fails: %s"),
421 grub_mdraid09_fini ();
422 grub_mdraid1x_fini ();
423 grub_diskfilter_fini ();
424 grub_diskfilter_init ();
425 grub_mdraid09_init ();
426 grub_mdraid1x_init ();
433 execute_command ("ls", n
, args
);
436 execute_command ("zfsinfo", n
, args
);
439 cmd_cp (args
[0], args
[1]);
445 cmd_cmp (args
[0], args
[1]);
454 execute_command ("blocklist", n
, args
);
458 execute_command ("testload", n
, args
);
466 char *argv
[3] = { xstrdup ("-l"), NULL
, NULL
};
467 dev
= grub_device_open (n
? args
[0] : 0);
469 grub_util_error ("%s", grub_errmsg
);
470 fs
= grub_fs_probe (dev
);
472 grub_util_error ("%s", grub_errmsg
);
474 grub_util_error ("%s", _("couldn't retrieve UUID"));
475 if (fs
->uuid (dev
, &uuid
))
476 grub_util_error ("%s", grub_errmsg
);
478 grub_util_error ("%s", _("couldn't retrieve UUID"));
480 execute_command ("xnu_uuid", 2, argv
);
483 grub_device_close (dev
);
487 for (i
= 0; i
< num_disks
; i
++)
491 loop_name
= grub_xasprintf ("loop%d", i
);
493 grub_util_error ("%s", grub_errmsg
);
495 argv
[0] = xstrdup ("-d");
498 execute_command ("loopback", 2, argv
);
500 grub_free (loop_name
);
505 static struct argp_option options
[] = {
506 {0, 0, 0 , OPTION_DOC
, N_("Commands:"), 1},
507 {N_("ls PATH"), 0, 0 , OPTION_DOC
, N_("List files in PATH."), 1},
508 {N_("cp FILE LOCAL"), 0, 0, OPTION_DOC
, N_("Copy FILE to local file LOCAL."), 1},
509 {N_("cat FILE"), 0, 0 , OPTION_DOC
, N_("Copy FILE to standard output."), 1},
510 {N_("cmp FILE LOCAL"), 0, 0, OPTION_DOC
, N_("Compare FILE with local file LOCAL."), 1},
511 {N_("hex FILE"), 0, 0 , OPTION_DOC
, N_("Show contents of FILE in hex."), 1},
512 {N_("crc FILE"), 0, 0 , OPTION_DOC
, N_("Get crc32 checksum of FILE."), 1},
513 {N_("blocklist FILE"), 0, 0, OPTION_DOC
, N_("Display blocklist of FILE."), 1},
514 {N_("xnu_uuid DEVICE"), 0, 0, OPTION_DOC
, N_("Compute XNU UUID of the device."), 1},
516 {"root", 'r', N_("DEVICE_NAME"), 0, N_("Set root device."), 2},
517 {"skip", 's', N_("NUM"), 0, N_("Skip N bytes from output file."), 2},
518 {"length", 'n', N_("NUM"), 0, N_("Handle N bytes in output file."), 2},
519 {"diskcount", 'c', N_("NUM"), 0, N_("Specify the number of input files."), 2},
520 {"debug", 'd', N_("STRING"), 0, N_("Set debug environment variable."), 2},
521 {"crypto", 'C', NULL
, 0, N_("Mount crypto devices."), 2},
523 /* TRANSLATORS: "prompt" is a keyword. */
524 N_("FILE|prompt"), 0, N_("Load zfs crypto key."), 2},
525 {"verbose", 'v', NULL
, 0, N_("print verbose messages."), 2},
526 {"uncompress", 'u', NULL
, 0, N_("Uncompress data."), 2},
530 /* Print the version information. */
532 print_version (FILE *stream
, struct argp_state
*state
)
534 fprintf (stream
, "%s (%s) %s\n", program_name
, PACKAGE_NAME
, PACKAGE_VERSION
);
536 void (*argp_program_version_hook
) (FILE *, struct argp_state
*) = print_version
;
539 argp_parser (int key
, char *arg
, struct argp_state
*state
)
550 if (strcmp (arg
, "prompt") == 0)
553 grub_puts_ (N_("Enter ZFS password: "));
554 if (grub_password_get (buf
, 1023))
556 grub_zfs_add_key ((grub_uint8_t
*) buf
, grub_strlen (buf
), 1);
563 grub_uint8_t buf
[1024];
564 f
= grub_util_fopen (arg
, "rb");
567 printf (_("%s: error:"), program_name
);
568 printf (_("cannot open `%s': %s"), arg
, strerror (errno
));
572 real_size
= fread (buf
, 1, 1024, f
);
576 printf (_("%s: error:"), program_name
);
577 printf (_("cannot read `%s': %s"), arg
, strerror (errno
));
581 grub_zfs_add_key (buf
, real_size
, 0);
590 skip
= grub_strtoul (arg
, &p
, 0);
592 skip
<<= GRUB_DISK_SECTOR_BITS
;
596 leng
= grub_strtoul (arg
, &p
, 0);
598 leng
<<= GRUB_DISK_SECTOR_BITS
;
602 num_disks
= grub_strtoul (arg
, NULL
, 0);
605 fprintf (stderr
, "%s", _("Invalid disk count.\n"));
610 /* TRANSLATORS: disk count is optional but if it's there it must
611 be before disk list. So please don't imply disk count as mandatory.
613 fprintf (stderr
, "%s", _("Disk count must precede disks list.\n"));
631 if (args_count
< num_disks
)
633 fprintf (stderr
, "%s", _("No command is specified.\n"));
636 if (args_count
- 1 - num_disks
< nparm
)
638 fprintf (stderr
, "%s", _("Not enough parameters to command.\n"));
647 return ARGP_ERR_UNKNOWN
;
650 if (args_count
< num_disks
)
653 images
= xmalloc (num_disks
* sizeof (images
[0]));
654 images
[args_count
] = canonicalize_file_name (arg
);
659 if (args_count
== num_disks
)
661 if (!grub_strcmp (arg
, "ls"))
665 else if (!grub_strcmp (arg
, "zfsinfo"))
669 else if (!grub_strcmp (arg
, "cp"))
674 else if (!grub_strcmp (arg
, "cat"))
679 else if (!grub_strcmp (arg
, "cmp"))
684 else if (!grub_strcmp (arg
, "hex"))
689 else if (!grub_strcmp (arg
, "crc"))
694 else if (!grub_strcmp (arg
, "blocklist"))
699 else if (!grub_strcmp (arg
, "testload"))
704 else if (grub_strcmp (arg
, "xnu_uuid") == 0)
711 fprintf (stderr
, _("Invalid command %s.\n"), arg
);
718 args
[args_count
- 1 - num_disks
] = xstrdup (arg
);
724 options
, argp_parser
, N_("IMAGE_PATH COMMANDS"),
725 N_("Debug tool for filesystem driver."),
730 main (int argc
, char *argv
[])
732 const char *default_root
;
735 grub_util_host_init (&argc
, &argv
);
737 args
= xmalloc (argc
* sizeof (args
[0]));
739 argp_parse (&argp
, argc
, argv
, 0, 0, 0);
741 /* Initialize all modules. */
743 grub_gcry_init_all ();
746 grub_env_set ("debug", debug_str
);
748 default_root
= (num_disks
== 1) ? "loop0" : "md0";
752 if ((*root
>= '0') && (*root
<= '9'))
754 alloc_root
= xmalloc (strlen (default_root
) + strlen (root
) + 2);
756 sprintf (alloc_root
, "%s,%s", default_root
, root
);
763 grub_env_set ("root", root
);
769 fstest (args_count
- 1 - num_disks
);
771 /* Free resources. */
772 grub_gcry_fini_all ();