grub-devel
[Top][All Lists]
Advanced

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

Re: Loopback device


From: Marco Gerards
Subject: Re: Loopback device
Date: Fri, 21 Jan 2005 19:36:36 +0000
User-agent: Gnus/5.1006 (Gnus v5.10.6) Emacs/21.3 (gnu/linux)

"Yoshinori K. Okuji" <address@hidden> writes:

> On Friday 21 January 2005 01:12, Marco Gerards wrote:
>> Here is a patch to add loopback support to GRUB.  Although a lot of
>> people told me they would find it useful, I just wrote it out of
>> boredom without thinking about its use, just to figure out how hard
>> it would be.
>
> That's great. That is the very thing I wanted to have.
>
> BTW, I think it is better to make it possible to choose a device type 
> (i.e. if it has a partition table or not). I'm always annoyed with that 
> Linux cannot deal with a hard disk image.

I did that and the new patch is included with this email.

Unfortunately it does not work well, but I believe that is a
filesystem problem.  Can I commit this patch?  I will put the
filesystem problem on the wiki so it is documented to have a look at
it later.

When the PPC port is mostly finished I plan to have a look at the bugs
in GRUB and do some testing.  I think there are some regressions in
the filesystems, there are a few known bugs and perhaps I can write
some testing tools to make it easier to test filesystems.

Thanks,
Marco

2005-01-21  Marco Gerards  <address@hidden>

        Add the loopback device, a device via which files can be accessed
        as devices.
        
        * conf/i386-pc.rmk (grub_emu_SOURCES): Add `disk/loopback.c'.
        (pkgdata_MODULES): Add loopback.mod.
        (loopback_SOURCES): New variable.
        (loopback_CFLAGS): Likewise.
        * conf/powerpc-ieee1275.rmk (grub_emu_SOURCES): Add
        `disk/loopback.c'.
        (pkgdata_MODULES): Add loopback.mod.
        (loopback_SOURCES): New variable.
        (loopback_CFLAGS): Likewise.
        * disk/loopback.c: new file.
        * include/grub/normal.h (grub_loop_init): New prototype.
        (grub_loop_fini): New prototype.
        (util/grub-emu.c): Initialize and de-initialize loopback support.
        * include/grub/disk.h (grub_disk_dev_id): Add
        `GRUB_DISK_DEVICE_LOOPBACK_ID'.


Index: conf/i386-pc.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/i386-pc.rmk,v
retrieving revision 1.23
diff -u -p -u -p -r1.23 i386-pc.rmk
--- conf/i386-pc.rmk    4 Dec 2004 18:45:45 -0000       1.23
+++ conf/i386-pc.rmk    21 Jan 2005 18:59:54 -0000
@@ -73,7 +73,7 @@ grub_emu_SOURCES = kern/main.c kern/devi
        commands/terminal.c commands/boot.c commands/cmp.c commands/cat.c       
        \
        util/i386/pc/biosdisk.c fs/fat.c fs/ext2.c fs/ufs.c fs/minix.c fs/hfs.c 
fs/jfs.c fs/iso9660.c \
        normal/cmdline.c normal/command.c normal/main.c normal/menu.c 
normal/arg.c      \
-       util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c
+       util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c 
disk/loopback.c
 grub_emu_LDFLAGS = -lncurses
 
 # For genmoddep.
@@ -83,7 +83,7 @@ genmoddep_SOURCES = util/genmoddep.c
 pkgdata_MODULES = _chain.mod _linux.mod linux.mod fat.mod ufs.mod ext2.mod 
minix.mod \
        hfs.mod jfs.mod normal.mod hello.mod vga.mod font.mod _multiboot.mod 
ls.mod \
        boot.mod cmp.mod cat.mod terminal.mod fshelp.mod chain.mod 
multiboot.mod \
-       amiga.mod apple.mod pc.mod
+       amiga.mod apple.mod pc.mod loopback.mod
 
 # For _chain.mod.
 _chain_mod_SOURCES = loader/i386/pc/chainloader.c
@@ -190,3 +190,7 @@ apple_mod_CFLAGS = $(COMMON_CFLAGS)
 # For pc.mod
 pc_mod_SOURCES = partmap/pc.c
 pc_mod_CFLAGS = $(COMMON_CFLAGS)
+
+# For loopback.mod
+loopback_SOURCES = disk/loopback.c
+loopback_CFLAGS = $(COMMON_CFLAGS)
Index: conf/powerpc-ieee1275.rmk
===================================================================
RCS file: /cvsroot/grub/grub2/conf/powerpc-ieee1275.rmk,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 powerpc-ieee1275.rmk
--- conf/powerpc-ieee1275.rmk   4 Jan 2005 14:01:45 -0000       1.19
+++ conf/powerpc-ieee1275.rmk   21 Jan 2005 18:59:55 -0000
@@ -41,7 +41,7 @@ grub_emu_SOURCES = kern/main.c kern/devi
        normal/cmdline.c normal/command.c normal/main.c normal/menu.c   \
        normal/arg.c kern/partition.c   \
        util/console.c util/grub-emu.c util/misc.c util/i386/pc/getroot.c \
-       kern/env.c commands/ls.c                \
+       kern/env.c disk/loopback.c commands/ls.c                \
        commands/terminal.c commands/boot.c commands/cmp.c commands/cat.c
 grub_emu_LDFLAGS = -lncurses
 
@@ -64,7 +64,8 @@ genmoddep_SOURCES = util/genmoddep.c
 # Modules.
 pkgdata_MODULES = _linux.mod linux.mod fat.mod ufs.mod ext2.mod minix.mod \
        hfs.mod jfs.mod normal.mod hello.mod font.mod \
-       boot.mod cmp.mod cat.mod terminal.mod fshelp.mod amiga.mod apple.mod 
pc.mod
+       boot.mod cmp.mod cat.mod terminal.mod fshelp.mod amiga.mod apple.mod \
+       pc.mod loopback.mod
 
 # For fshelp.mod.
 fshelp_mod_SOURCES = fs/fshelp.c
@@ -151,3 +152,7 @@ apple_mod_CFLAGS = $(COMMON_CFLAGS)
 # For pc.mod
 pc_mod_SOURCES = partmap/pc.c
 pc_mod_CFLAGS = $(COMMON_CFLAGS)
+
+# For loopback.mod
+loopback_SOURCES = disk/loopback.c
+loopback_CFLAGS = $(COMMON_CFLAGS)
Index: disk/loopback.c
===================================================================
RCS file: disk/loopback.c
diff -N disk/loopback.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ disk/loopback.c     21 Jan 2005 18:59:55 -0000
@@ -0,0 +1,272 @@
+/* loopback.c - command to add loopback devices.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2005  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 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/arg.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/mm.h>
+
+struct grub_loopback
+{
+  char *devname;
+  char *filename;
+  int has_partitions;
+  struct grub_loopback *next;
+};
+
+static struct grub_loopback *loopback_list; 
+
+static const struct grub_arg_option options[] =
+  {
+    {"delete", 'd', 0, "Delete the loopback device entry", 0, 0},
+    {"partitions", 'p', 0, "Set that the drive has partitions to"
+     " simulate a harddrive", 0, 0},
+    {0, 0, 0, 0, 0, 0}
+  };
+
+/* Delete the loopback device NAME.  */
+static grub_err_t
+delete_loopback (const char *name)
+{
+  struct grub_loopback *dev;
+  struct grub_loopback **prev;
+
+  /* Search for the device.  */
+  for (dev = loopback_list, prev = &loopback_list;
+       dev; prev = &dev->next, dev = dev->next)
+    if (!grub_strcmp (dev->devname, name))
+      break;
+  if (!dev)
+    return grub_error (GRUB_ERR_BAD_DEVICE, "Device not found");
+  
+  /* Remove the device from the list.  */
+  *prev = dev->next;
+
+  grub_free (dev->devname);
+  grub_free (dev->filename);
+  grub_free (dev);
+  
+  return 0;
+}
+
+
+/* The command to add and remove loopback devices.  */
+static grub_err_t
+grub_cmd_loopback (struct grub_arg_list *state,
+                  int argc, char **args)
+{
+  grub_file_t file;
+  struct grub_loopback *newdev;
+  
+  if (argc < 1)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
+  
+  /* Check if `-d' was used.  */
+  if (state[0].set)
+      return delete_loopback (args[0]);
+  
+  if (argc < 2)
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
+
+  file = grub_file_open (args[1]);
+  if (! file)
+    return grub_errno;
+  
+  /* Close the file, the only reason for opening it is validation.  */
+  grub_file_close (file);
+  
+  /* First try to replace the old device.  */
+  for (newdev = loopback_list; newdev; newdev = newdev->next)
+    if (!grub_strcmp (newdev->devname, args[0]))
+      break;
+  if (newdev)
+    {
+      char *newname = grub_strdup (args[1]);
+      if (!newname)
+       return grub_errno;
+      
+      grub_free (newdev->filename);
+      newdev->filename = newname;
+      
+      /* Set has_partitions when `--partitions' was used.  */
+      newdev->has_partitions = state[1].set;
+      
+      return 0;
+    }
+  
+  /* Unable to replace it, make a new entry.  */
+  newdev = grub_malloc (sizeof (struct grub_loopback));
+  if (!newdev)
+    return grub_errno;
+  
+  newdev->devname = grub_strdup (args[0]);
+  if (!newdev->devname)
+    {
+      grub_free (newdev);
+      return grub_errno;
+    }
+  
+  newdev->filename = grub_strdup (args[1]);
+  if (!newdev->devname)
+    {
+      grub_free (newdev->devname);
+      grub_free (newdev);
+      return grub_errno;
+    }
+  
+  /* Set has_partitions when `--partitions' was used.  */
+  newdev->has_partitions = state[1].set;
+  
+  /* Add the new entry to the list.  */
+  newdev->next = loopback_list;
+  loopback_list = newdev;
+  
+  return 0;
+}
+
+
+static int
+grub_loopback_iterate (int (*hook) (const char *name))
+{
+  struct grub_loopback *d;
+  for (d = loopback_list; d; d = d->next)
+    {
+      if (hook (d->devname))
+       return 1;
+    }
+  return 0;
+}
+
+static grub_err_t
+grub_loopback_open (const char *name, grub_disk_t disk)
+{
+  grub_file_t file;
+  struct grub_loopback *dev;
+    
+  for (dev = loopback_list; dev; dev = dev->next)
+    if (!grub_strcmp (dev->devname, name))
+      break;
+  
+  if (! dev)
+    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
+
+  file = grub_file_open (dev->filename);
+  if (! file)
+    return grub_errno;
+  
+  /* Use the filesize for the disk size, round up to a complete sector.  */
+  disk->total_sectors = ((file->size + GRUB_DISK_SECTOR_SIZE - 1)
+                        / GRUB_DISK_SECTOR_SIZE);
+  disk->id = (int) dev;
+  
+  disk->has_partitions = dev->has_partitions;
+  disk->data = file;
+  
+  return 0;
+}
+
+static void
+grub_loopback_close (grub_disk_t disk)
+{
+  grub_file_t file = (grub_file_t) disk->data;
+  
+  grub_file_close (file);
+}
+
+static grub_err_t
+grub_loopback_read (grub_disk_t disk, unsigned long sector,
+                   unsigned long size, char *buf)
+{
+  grub_file_t file = (grub_file_t) disk->data;
+  long pos;
+  
+  grub_file_seek (file, sector * GRUB_DISK_SECTOR_SIZE);
+  
+  grub_file_read (file, buf, size * GRUB_DISK_SECTOR_SIZE);
+  if (grub_errno)
+    return grub_errno;
+  
+  /* In case there is more data read than there is available, in case
+     of files that are not a multiple of GRUB_DISK_SECTOR_SIZE, fill
+     the rest with zeros.  */
+  pos = sector * GRUB_DISK_SECTOR_SIZE + size * GRUB_DISK_SECTOR_SIZE;
+  if (pos > file->size)
+    {
+      unsigned long amount = pos - file->size;
+      grub_memset (buf + pos - amount, amount, 0);
+    }
+  
+  return 0;
+}
+
+static grub_err_t
+grub_loopback_write (grub_disk_t disk __attribute ((unused)),
+                  unsigned long sector __attribute ((unused)),
+                  unsigned long size __attribute ((unused)),
+                  const char *buf __attribute ((unused)))
+{
+  return GRUB_ERR_NOT_IMPLEMENTED_YET;
+}
+
+static struct grub_disk_dev grub_loopback_dev =
+  {
+    .name = "loopback",
+    .id = GRUB_DISK_DEVICE_LOOPBACK_ID,
+    .iterate = grub_loopback_iterate,
+    .open = grub_loopback_open,
+    .close = grub_loopback_close,
+    .read = grub_loopback_read,
+    .write = grub_loopback_write,
+    .next = 0
+  };
+
+
+
+#ifdef GRUB_UTIL
+void
+grub_loop_init (void)
+{
+  grub_register_command ("loopback", grub_cmd_loopback, GRUB_COMMAND_FLAG_BOTH,
+                        "loopback [OPTIONS] DEVICENAME FILE", "Makes a device 
of a file", options);
+  grub_disk_dev_register (&grub_loopback_dev);
+  
+}
+
+void
+grub_loop_fini (void)
+{
+  grub_unregister_command ("loopback");
+}
+#else /* ! GRUB_UTIL */
+GRUB_MOD_INIT
+{
+  (void)mod;                   /* To stop warning. */
+  grub_register_command ("loopback", grub_cmd_loopback, GRUB_COMMAND_FLAG_BOTH,
+                        "loopback [OPTIONS] DEVICENAME FILE", "Makes a device 
of a file", options);
+}
+
+GRUB_MOD_FINI
+{
+  grub_unregister_command ("loopback");
+}
+#endif /* ! GRUB_UTIL */
Index: include/grub/disk.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/disk.h,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 disk.h
--- include/grub/disk.h 21 Aug 2004 13:54:22 -0000      1.5
+++ include/grub/disk.h 21 Jan 2005 18:59:56 -0000
@@ -31,6 +31,7 @@ enum grub_disk_dev_id
   {
     GRUB_DISK_DEVICE_BIOSDISK_ID,
     GRUB_DISK_DEVICE_OFDISK_ID,
+    GRUB_DISK_DEVICE_LOOPBACK_ID
   };
 
 struct grub_disk;
Index: include/grub/normal.h
===================================================================
RCS file: /cvsroot/grub/grub2/include/grub/normal.h,v
retrieving revision 1.9
diff -u -p -u -p -r1.9 normal.h
--- include/grub/normal.h       17 Sep 2004 09:36:52 -0000      1.9
+++ include/grub/normal.h       21 Jan 2005 18:59:56 -0000
@@ -158,6 +158,8 @@ void grub_cmp_init (void);
 void grub_cmp_fini (void);
 void grub_terminal_init (void);
 void grub_terminal_fini (void);
+void grub_loop_init (void);
+void grub_loop_fini (void);
 #endif
 
 #endif /* ! GRUB_NORMAL_HEADER */
Index: util/grub-emu.c
===================================================================
RCS file: /cvsroot/grub/grub2/util/grub-emu.c,v
retrieving revision 1.11
diff -u -p -u -p -r1.11 grub-emu.c
--- util/grub-emu.c     20 Jan 2005 17:25:39 -0000      1.11
+++ util/grub-emu.c     21 Jan 2005 18:59:56 -0000
@@ -176,13 +176,15 @@ main (int argc, char *argv[])
   grub_cmp_init ();
   grub_cat_init ();
   grub_terminal_init ();
-
+  grub_loop_init ();
+  
   /* XXX: Should normal mode be started by default?  */
   grub_normal_init ();
-
+  
   /* Start GRUB!  */
   grub_main ();
 
+  grub_loop_fini ();
   grub_util_biosdisk_fini ();
   grub_normal_fini ();
   grub_ufs_fini ();





reply via email to

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