grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: grub-fstest: debug tool for filesystem driver


From: Bean
Subject: Re: grub-fstest: debug tool for filesystem driver
Date: Sat, 5 Jan 2008 20:11:21 +0800

On Jan 5, 2008 7:52 PM, Robert Millan <address@hidden> wrote:
>
> Would be nice if you could include inline attachments without base64 encoding;
> that'd make it easier for context-reply.  At least in mutt.
>

ok, here is it.

2008-01-05  Bean <address@hidden>

        * Makefile.in (enable_grub_fstest): New variable.

        * conf/common.rmk (grub_fstest_init.lst): New rule.
        (grub_fstest_init.h): Likewise.
        (grub_fstest_init.c): Likewise.

        * i396-pc.rmk (util/grub-fstest.c_DEPENDENCIES): New variable.
        (grub_fstest_SOURCES): Likewise.

        * configure.ac (enable_grub_fstest): New test.

        * util/grub-fstest.c: New file.


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..c255dbb
--- /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_LS          1
+#define CMD_CP          2
+#define CMD_CMP         3
+#define CMD_HEX         4
+#define CMD_BLOCKLIST   5
+
+#define BUF_SIZE  32256
+
+static grub_off_t skip, leng;
+static int part;
+
+static void
+cmd_ls (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_ex (pathname, 1);
+       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_ex (pathname, 1);
+  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_cp (char *src, char *dest)
+{
+  FILE *ff;
+
+  auto int cp_hook (grub_off_t ofs, char *buf, int len);
+  int cp_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, cp_hook);
+  fclose (ff);
+}
+
+static void
+cmd_cmp (char *src, char *dest)
+{
+  FILE *ff;
+  static char buf_1[BUF_SIZE];
+
+  auto int cmp_hook (grub_off_t ofs, char *buf, int len);
+  int cmp_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, cmp_hook);
+  fclose (ff);
+}
+
+static void
+cmd_hex (char *pathname)
+{
+  auto int hex_hook (grub_off_t ofs, char *buf, int len);
+  int hex_hook (grub_off_t ofs, char *buf, int len)
+  {
+    hexdump (ofs, buf, len);
+    return 0;
+  }
+
+  read_file (pathname, hex_hook);
+}
+
+static void
+cmd_blocklist (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_LS:
+      cmd_ls (fs, dev, parm[0]);
+      break;
+    case CMD_CP:
+      cmd_cp (parm[0], parm[1]);
+      break;
+    case CMD_CMP:
+      cmd_cmp (parm[0], parm[1]);
+      break;
+    case CMD_HEX:
+      cmd_hex (parm[0]);
+      break;
+    case CMD_BLOCKLIST:
+      cmd_blocklist (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\
+  hex FILE                  hex dump FILE\n\
+  blocklist 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_LS;
+       }
+      else if (!grub_strcmp (argv[optind], "cp"))
+       {
+         cmd = CMD_CP;
+         nparm = 2;
+       }
+      else if (!grub_strcmp (argv[optind], "cmp"))
+       {
+         cmd = CMD_CMP;
+         nparm = 2;
+       }
+      else if (!grub_strcmp (argv[optind], "hex"))
+       {
+         cmd = CMD_HEX;
+       }
+      else if (!grub_strcmp (argv[optind], "blocklist"))
+       {
+         cmd = CMD_BLOCKLIST;
+       }
+      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 ("filehook", "0");
+
+  /* Do it.  */
+  fstest (image_path + 1, cmd, argv + optind);
+
+  /* Free resources.  */
+  grub_fini_all ();
+
+  grub_hostfs_fini ();
+
+  return 0;
+}

-- 
Bean




reply via email to

[Prev in Thread] Current Thread [Next in Thread]