All of lore.kernel.org
 help / color / mirror / Atom feed
* grub-fstest: debug tool for filesystem driver
@ 2008-01-02 17:11 Bean
  2008-01-04 11:53 ` Robert Millan
  0 siblings, 1 reply; 16+ messages in thread
From: Bean @ 2008-01-02 17:11 UTC (permalink / raw)
  To: The development of GRUB 2

[-- Attachment #1: Type: text/plain, Size: 1415 bytes --]

Hi,

I've written a new tool grub-fstest which can be useful in debuging
filesystem drivers. To build grub-fstest, you must use option
--enable-grub-fstest:

./configure --enable-grub-fstest

Usage:

fstest [OPTIONS] IMAGE_PATH COMMANDS

IMAGE_PATH is the absolute path to an image file, COMMANDS is one of
the following commands:

ls PATH
list files in PATH

cp SRC DEST
copy file SRC in the image file to DEST in the local system.

cmp SRC DEST
compare file SRC in the image file with DEST in the local system.

dump FILE
hexdump FILE in the image file

blst FILE
display the blocklist of FILE in the image file

Options:
-s, --skip=N
set the number of bytes to skip in command cp, cmp and dump.

-n, --length=N
set the number of bytes to process in command cp, cmp and dump.

-r, --raw
disable auto decompression

-p, --part=N
if IMAGE_FILE contain partition map, use the option to select partition.

Examples:

./grub-fstest /path/aa.iso ls /
List files in aa.iso

./grub-fstest -p 1 /path/aa.dsk cp /bb cc
Copy file /bb in the first partition of aa.dsk to cc in the current directory

./grub-fstest -p 1 /path/aa.dsk cmp /bb cc
Compare file /bb in the first partition of aa.dsk with cc in the
current directory

./grub-fstest -s 10 -n 20 /path/aa.tar dump /bb
Hexdump file /bb in aa.tar, skip 10 bytes, print 20 bytes.

./grub-fstest /path/aa.iso blst /bb
display the blocklist of file /bb in aa.iso

-- 
Bean

[-- Attachment #2: grub2-fstest.diff --]
[-- Type: application/octet-stream, Size: 15939 bytes --]

diff --git a/Makefile.in b/Makefile.in
index c6a04c9..c4b8835 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -79,6 +79,7 @@ UNIFONT_HEX = @UNIFONT_HEX@
 
 # Options.
 enable_grub_emu = @enable_grub_emu@
+enable_grub_fstest = @enable_grub_fstest@
 
 ### General variables.
 
diff --git a/conf/common.rmk b/conf/common.rmk
index 4773f7d..45dfeef 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -44,6 +44,19 @@ grub_setup_init.c: grub_setup_init.lst $(filter-out grub_setup_init.c,$(grub_set
 	rm -f $@; sh $(srcdir)/geninit.sh $< $(filter %.c,$^) > $@
 DISTCLEANFILES += grub_setup_init.c
 
+# For grub-fstest.
+grub_fstest_init.lst: geninit.sh $(filter-out grub_fstest_init.c,$(grub_fstest_SOURCES))
+	rm -f $@; grep GRUB_MOD_INIT $(filter %.c,$^) /dev/null > $@
+DISTCLEANFILES += grub_fstest_init.lst
+
+grub_fstest_init.h: grub_fstest_init.lst $(filter-out grub_fstest_init.c,$(grub_fstest_SOURCES)) geninitheader.sh
+	rm -f $@; sh $(srcdir)/geninitheader.sh $< > $@
+DISTCLEANFILES += grub_fstest_init.h
+
+grub_fstest_init.c: grub_fstest_init.lst $(filter-out grub_fstest_init.c,$(grub_fstest_SOURCES)) geninit.sh grub_fstest_init.h
+	rm -f $@; sh $(srcdir)/geninit.sh $< $(filter %.c,$^) > $@
+DISTCLEANFILES += grub_fstest_init.c
+
 # For update-grub
 update-grub: util/update-grub.in config.status
 	./config.status --file=$@:$<
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index 2638ee5..a25dd76 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -59,6 +59,9 @@ sbin_UTILITIES = grub-setup grub-mkdevicemap grub-probe
 ifeq ($(enable_grub_emu), yes)
 sbin_UTILITIES += grub-emu
 endif
+ifeq ($(enable_grub_fstest), yes)
+bin_UTILITIES += grub-fstest
+endif
 
 # For grub-mkimage.
 grub_mkimage_SOURCES = util/i386/pc/grub-mkimage.c util/misc.c \
@@ -121,6 +124,18 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c	\
 
 grub_emu_LDFLAGS = $(LIBCURSES)
 
+# For grub-fstest.
+util/grub-fstest.c_DEPENDENCIES = grub_fstest_init.h
+grub_fstest_SOURCES = util/grub-fstest.c util/hostfs.c util/misc.c 	\
+	kern/file.c kern/device.c kern/disk.c kern/err.c kern/misc.c	\
+	disk/host.c disk/loopback.c commands/hexdump.c io/gzio.c	\
+	commands/blocklist.c fs/fat.c fs/ext2.c kern/parser.c		\
+	kern/partition.c partmap/pc.c partmap/apple.c partmap/gpt.c 	\
+	fs/ufs.c fs/minix.c fs/hfs.c fs/jfs.c fs/ntfs.c kern/fs.c	\
+	kern/env.c fs/fshelp.c fs/xfs.c fs/affs.c fs/sfs.c fs/hfsplus.c	\
+	fs/ntfscomp.c fs/iso9660.c fs/cpio.c disk/lvm.c disk/raid.c	\
+	grub_fstest_init.c
+
 # Scripts.
 sbin_SCRIPTS = grub-install
 bin_SCRIPTS = grub-mkrescue
diff --git a/configure b/configure
index bd2d745..8ca04d5 100755
--- a/configure
+++ b/configure
@@ -695,6 +695,7 @@ TARGET_CPPFLAGS
 TARGET_LDFLAGS
 LIBCURSES
 enable_grub_emu
+enable_grub_fstest
 LIBOBJS
 LTLIBOBJS'
 ac_subst_files=''
@@ -1290,6 +1291,8 @@ Optional Features:
   --disable-largefile     omit support for large files
   --enable-mm-debug       include memory manager debugging
   --enable-grub-emu       build and install the `grub-emu' debugging utility
+  --enable-grub-fstest    build and install the `grub-fstest' debugging
+                          utility
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -8141,6 +8144,13 @@ done
 fi
 
 
+# Check whether --enable-grub-fstest was given.
+if test "${enable_grub_fstest+set}" = set; then
+  enableval=$enable_grub_fstest;
+fi
+
+
+
 # Output files.
 ac_config_links="$ac_config_links include/grub/cpu:include/grub/$target_cpu include/grub/machine:include/grub/$target_cpu/$platform"
 
@@ -8854,11 +8864,12 @@ TARGET_CPPFLAGS!$TARGET_CPPFLAGS$ac_delim
 TARGET_LDFLAGS!$TARGET_LDFLAGS$ac_delim
 LIBCURSES!$LIBCURSES$ac_delim
 enable_grub_emu!$enable_grub_emu$ac_delim
+enable_grub_fstest!$enable_grub_fstest$ac_delim
 LIBOBJS!$LIBOBJS$ac_delim
 LTLIBOBJS!$LTLIBOBJS$ac_delim
 _ACEOF
 
-  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 82; then
+  if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 83; then
     break
   elif $ac_last_try; then
     { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5
diff --git a/configure.ac b/configure.ac
index fb6e026..451230f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -319,6 +319,11 @@ AC_ARG_ENABLE([grub-emu],
 [fi]
 AC_SUBST([enable_grub_emu])
 
+AC_ARG_ENABLE([grub-fstest],
+	      [AS_HELP_STRING([--enable-grub-fstest],
+                             [build and install the `grub-fstest' debugging utility])])
+AC_SUBST([enable_grub_fstest])
+
 # Output files.
 AC_CONFIG_LINKS([include/grub/cpu:include/grub/$target_cpu
 	include/grub/machine:include/grub/$target_cpu/$platform])
diff --git a/util/grub-fstest.c b/util/grub-fstest.c
new file mode 100755
index 0000000..7621af6
--- /dev/null
+++ b/util/grub-fstest.c
@@ -0,0 +1,540 @@
+/* grub-fstest.c - debug tool for filesystem driver */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2008 Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/util/misc.h>
+#include <grub/misc.h>
+#include <grub/device.h>
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/term.h>
+#include <grub/normal.h>
+#include <grub/hexdump.h>
+
+#include <grub_fstest_init.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define _GNU_SOURCE	1
+#include <getopt.h>
+
+void
+grub_putchar (int c)
+{
+  putchar (c);
+}
+
+int
+grub_getkey (void)
+{
+  return -1;
+}
+
+grub_term_t
+grub_term_get_current (void)
+{
+  return 0;
+}
+
+void
+grub_refresh (void)
+{
+}
+
+static grub_err_t (*loopfunc) (struct grub_arg_list * state, int argc,
+			       char **args);
+static grub_err_t (*blstfunc) (struct grub_arg_list * state, int argc,
+			       char **args);
+
+grub_command_t
+grub_register_command (const char *name,
+		       grub_err_t (*func) (struct grub_arg_list * state,
+					   int argc, char **args),
+		       unsigned flags,
+		       const char *summary,
+		       const char *description,
+		       const struct grub_arg_option *options)
+{
+  (void) flags;
+  (void) summary;
+  (void) description;
+  (void) options;
+
+  if (!grub_strcmp (name, "loopback"))
+    loopfunc = func;
+  else if (!grub_strcmp (name, "blocklist"))
+    blstfunc = func;
+
+  return NULL;
+}
+
+void
+grub_unregister_command (const char *name)
+{
+  (void) name;
+}
+
+#define CMD_LIST  1
+#define CMD_COPY  2
+#define CMD_COMP  3
+#define CMD_DUMP  4
+#define CMD_BLST  5
+
+#define BUF_SIZE  32256
+
+static grub_off_t skip, leng;
+static int part;
+
+static void
+cmd_list (grub_fs_t fs, grub_device_t dev, char *dirname)
+{
+  auto int print_files_long (const char *filename, int dir);
+  int print_files_long (const char *filename, int dir)
+  {
+    char pathname[grub_strlen (dirname) + grub_strlen (filename) + 1];
+
+    if (!dir)
+      {
+	grub_file_t file;
+
+	if (dirname[grub_strlen (dirname) - 1] == '/')
+	  grub_sprintf (pathname, "%s%s", dirname, filename);
+	else
+	  grub_sprintf (pathname, "%s/%s", dirname, filename);
+
+	file = grub_file_open (pathname);
+	if (!file)
+	  {
+	    grub_errno = 0;
+	    return 0;
+	  }
+
+	grub_printf ("%-12llu", file->size);
+	grub_file_close (file);
+      }
+    else
+      grub_printf ("%-12s", "DIR");
+
+    grub_printf ("%s%s\n", filename, dir ? "/" : "");
+
+    return 0;
+  }
+
+  fs->dir (dev, dirname, print_files_long);
+}
+
+static void
+read_file (char *pathname, int (*hook) (grub_off_t ofs, char *buf, int len))
+{
+  static char buf[BUF_SIZE];
+  grub_file_t file;
+  grub_off_t ofs, len;
+
+  file = grub_file_open (pathname);
+  if (!file)
+    {
+      grub_util_error ("cannot open file %s.\n", pathname);
+      return;
+    }
+
+  if (skip > file->size)
+    {
+      grub_util_error ("invalid skip value %d.\n");
+      return;
+    }
+
+  ofs = skip;
+  len = file->size - skip;
+  if ((leng) && (leng < len))
+    len = leng;
+
+  file->offset = skip;
+
+  while (len)
+    {
+      grub_ssize_t sz;
+
+      sz = grub_file_read (file, buf, (len > BUF_SIZE) ? BUF_SIZE : len);
+      if (sz < 0)
+	{
+	  grub_util_error ("read error at offset %llu.\n", ofs);
+	  break;
+	}
+
+      if ((sz == 0) || (hook (ofs, buf, sz)))
+	break;
+
+      ofs += sz;
+      len -= sz;
+    }
+
+  grub_file_close (file);
+}
+
+static void
+cmd_copy (char *src, char *dest)
+{
+  FILE *ff;
+
+  auto int copy_hook (grub_off_t ofs, char *buf, int len);
+  int copy_hook (grub_off_t ofs, char *buf, int len)
+  {
+    (void) ofs;
+
+    if ((int) fwrite (buf, 1, len, ff) != len)
+      {
+	grub_util_error ("write error.\n");
+	return 1;
+      }
+
+    return 0;
+  }
+
+  ff = fopen (dest, "w");
+  if (ff == NULL)
+    {
+      grub_util_error ("open error.\n");
+      return;
+    }
+  read_file (src, copy_hook);
+  fclose (ff);
+}
+
+static void
+cmd_comp (char *src, char *dest)
+{
+  FILE *ff;
+  static char buf_1[BUF_SIZE];
+
+  auto int comp_hook (grub_off_t ofs, char *buf, int len);
+  int comp_hook (grub_off_t ofs, char *buf, int len)
+  {
+    if ((int) fread (buf_1, 1, len, ff) != len)
+      {
+	grub_util_error ("read error at offset %llu.\n", ofs);
+	return 1;
+      }
+
+    if (grub_memcmp (buf, buf_1, len))
+      {
+	int i;
+
+	for (i = 0; i < len; i++, ofs++)
+	  if (buf_1[i] != buf[i])
+	    {
+	      grub_util_error ("compare fail at offset %llu.\n", ofs);
+	      return 1;
+	    }
+      }
+    return 0;
+  }
+
+  ff = fopen (dest, "r");
+  if (ff == NULL)
+    {
+      grub_util_error ("open error.\n");
+      return;
+    }
+
+  if ((skip) && (fseek (ff, skip, SEEK_SET)))
+    grub_util_error ("fseek error.\n");
+
+  read_file (src, comp_hook);
+  fclose (ff);
+}
+
+static void
+cmd_dump (char *pathname)
+{
+  auto int dump_hook (grub_off_t ofs, char *buf, int len);
+  int dump_hook (grub_off_t ofs, char *buf, int len)
+  {
+    hexdump (ofs, buf, len);
+    return 0;
+  }
+
+  read_file (pathname, dump_hook);
+}
+
+static void
+cmd_blst (char *pathname)
+{
+  char *argv[1];
+
+  argv[0] = pathname;
+  if (blstfunc (NULL, 1, argv))
+    grub_util_error ("blocklist command fails.\n");
+  else
+    grub_printf ("\n");
+}
+
+static void
+fstest (char *image_path, int cmd, char **parm)
+{
+  grub_device_t dev = 0;
+  grub_fs_t fs;
+  char host_file[7 + grub_strlen (image_path) + 1];
+  struct grub_arg_list state[2];
+  char *argv[2];
+  char device_name[10];
+
+  grub_memset (&state, 0, sizeof (state));
+  state[1].set = (part != 0);
+
+  argv[0] = "loop";
+  grub_sprintf (host_file, "(host)/%s", image_path);
+  argv[1] = host_file;
+
+  if (loopfunc (state, 2, argv))
+    {
+      grub_util_error ("loopback command fails.\n");
+      goto fail;
+    }
+
+  if (part)
+    grub_sprintf (device_name, "loop,%d", part);
+  else
+    grub_strcpy (device_name, "loop");
+
+  dev = grub_device_open (device_name);
+  if (!dev)
+    {
+      grub_util_error ("cannot open device (%s).\n", device_name);
+      goto fail;
+    }
+
+  grub_env_set ("root", device_name);
+
+  fs = grub_fs_probe (dev);
+  if (!fs)
+    {
+      grub_util_error ("Unknown fs.\n");
+      goto fail;
+    }
+
+  grub_util_info ("filesystem %s.", fs->name);
+
+  switch (cmd)
+    {
+    case CMD_LIST:
+      cmd_list (fs, dev, parm[0]);
+      break;
+    case CMD_COPY:
+      cmd_copy (parm[0], parm[1]);
+      break;
+    case CMD_COMP:
+      cmd_comp (parm[0], parm[1]);
+      break;
+    case CMD_DUMP:
+      cmd_dump (parm[0]);
+      break;
+    case CMD_BLST:
+      cmd_blst (parm[0]);
+    }
+
+fail:
+  state[0].set = 1;
+  loopfunc (state, 1, argv);
+
+  if (dev)
+    grub_device_close (dev);
+}
+
+static struct option options[] = {
+  {"part", required_argument, 0, 'p'},
+  {"skip", required_argument, 0, 's'},
+  {"length", required_argument, 0, 'n'},
+  {"raw", required_argument, 0, 'r'},
+  {"help", no_argument, 0, 'h'},
+  {"version", no_argument, 0, 'V'},
+  {"verbose", no_argument, 0, 'v'},
+  {0, 0, 0, 0}
+};
+
+static void
+usage (int status)
+{
+  if (status)
+    fprintf (stderr, "Try ``grub-fstest --help'' for more information.\n");
+  else
+    printf ("\
+Usage: grub-fstest [OPTION]... IMAGE_PATH COMMANDS\n\
+\n\
+Debug tool for filesystem driver.\n\
+\nCommands:\n\
+  ls PATH                   list files in PATH\n\
+  cp SRC DEST               copy file to local system\n\
+  cmp SRC DEST              compare files\n\
+  dump FILE                 hexdump FILE\n\
+  blst FILE                 display blocklist of FILE\n\
+\nOptions:\n\
+  -p, --part=NUM            select partition NUM\n\
+  -s, --skip=N              skip N bytes from output file\n\
+  -n, --length=N            handle N bytes in output file\n\
+  -r, --raw                 disable auto decompression\n\
+  -h, --help                display this message and exit\n\
+  -V, --version             print version information and exit\n\
+  -v, --verbose             print verbose messages\n\
+\n\
+Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
+
+  exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+  char *image_path;
+  int cmd, raw = 0;
+
+  progname = "grub-fstest";
+
+  /* Check for options.  */
+  while (1)
+    {
+      int c = getopt_long (argc, argv, "p:s:n:rhVv", options, 0);
+
+      if (c == -1)
+	break;
+      else
+	switch (c)
+	  {
+	  case 'p':
+	    part = grub_strtoul (optarg, NULL, 0);
+	    break;
+
+	  case 's':
+	    skip = grub_strtoul (optarg, NULL, 0);
+	    break;
+
+	  case 'n':
+	    leng = grub_strtoul (optarg, NULL, 0);
+	    break;
+
+	  case 'r':
+	    raw = 1;
+	    break;
+
+	  case 'h':
+	    usage (0);
+	    break;
+
+	  case 'V':
+	    printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION);
+	    return 0;
+
+	  case 'v':
+	    verbosity++;
+	    break;
+
+	  default:
+	    usage (1);
+	    break;
+	  }
+    }
+
+  /* Obtain PATH.  */
+  if (optind >= argc)
+    {
+      fprintf (stderr, "No path is specified.\n");
+      usage (1);
+    }
+
+  image_path = argv[optind];
+
+  if (*image_path != '/')
+    {
+      fprintf (stderr, "Must use absolute path.\n");
+      usage (1);
+    }
+
+  optind++;
+
+  cmd = 0;
+  if (optind < argc)
+    {
+      int nparm = 1;
+
+      if (!grub_strcmp (argv[optind], "ls"))
+	{
+	  cmd = CMD_LIST;
+	}
+      else if (!grub_strcmp (argv[optind], "cp"))
+	{
+	  cmd = CMD_COPY;
+	  nparm = 2;
+	}
+      else if (!grub_strcmp (argv[optind], "cmp"))
+	{
+	  cmd = CMD_COMP;
+	  nparm = 2;
+	}
+      else if (!grub_strcmp (argv[optind], "dump"))
+	{
+	  cmd = CMD_DUMP;
+	}
+      else if (!grub_strcmp (argv[optind], "blst"))
+	{
+	  cmd = CMD_BLST;
+	}
+      else
+	{
+	  fprintf (stderr, "Invalid command %s.\n", argv[optind]);
+	  usage (1);
+	}
+
+      if (optind + 1 + nparm != argc)
+	{
+	  fprintf (stderr, "Invalid parameter for command %s.\n",
+		   argv[optind]);
+	  usage (1);
+	}
+
+      optind++;
+    }
+  else
+    {
+      fprintf (stderr, "No command is specified.\n");
+      usage (1);
+    }
+
+  grub_hostfs_init ();
+
+  /* Initialize all modules. */
+  grub_init_all ();
+
+  if (raw)
+    grub_env_set ("nofshook", "1");
+
+  /* Do it.  */
+  fstest (image_path + 1, cmd, argv + optind);
+
+  /* Free resources.  */
+  grub_fini_all ();
+
+  grub_hostfs_fini ();
+
+  return 0;
+}

^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2008-02-04  8:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-02 17:11 grub-fstest: debug tool for filesystem driver Bean
2008-01-04 11:53 ` Robert Millan
2008-01-04 12:08   ` Bean
2008-01-05  7:37     ` Bean
2008-01-05 11:52       ` Robert Millan
2008-01-05 12:11         ` Bean
2008-01-28 10:45           ` Robert Millan
2008-01-28 14:48             ` Bean
2008-01-28 17:27               ` Robert Millan
2008-01-28 17:35                 ` Bean
2008-01-28 18:13                   ` Robert Millan
2008-01-29 10:18                     ` Bean
2008-01-29 13:45                       ` Robert Millan
2008-01-29 13:51                         ` Bean
2008-02-03 17:56                           ` Bean
2008-02-04  8:46                             ` Bean

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.