1
/* loopback.c - command to add loopback devices. */
3
* GRUB -- GRand Unified Bootloader
4
* Copyright (C) 2005 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 2 of the License, or
9
* (at your option) any later version.
11
* This program 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, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
#include <grub/normal.h>
24
#include <grub/misc.h>
25
#include <grub/file.h>
26
#include <grub/disk.h>
34
struct grub_loopback *next;
37
static struct grub_loopback *loopback_list;
39
static const struct grub_arg_option options[] =
41
{"delete", 'd', 0, "delete the loopback device entry", 0, 0},
42
{"partitions", 'p', 0, "set that the drive has partitions to"
43
" simulate a harddrive", 0, 0},
47
/* Delete the loopback device NAME. */
49
delete_loopback (const char *name)
51
struct grub_loopback *dev;
52
struct grub_loopback **prev;
54
/* Search for the device. */
55
for (dev = loopback_list, prev = &loopback_list;
56
dev; prev = &dev->next, dev = dev->next)
57
if (!grub_strcmp (dev->devname, name))
60
return grub_error (GRUB_ERR_BAD_DEVICE, "Device not found");
62
/* Remove the device from the list. */
65
grub_free (dev->devname);
66
grub_free (dev->filename);
72
/* The command to add and remove loopback devices. */
74
grub_cmd_loopback (struct grub_arg_list *state,
75
int argc, char **args)
78
struct grub_loopback *newdev;
81
return grub_error (GRUB_ERR_BAD_ARGUMENT, "device name required");
83
/* Check if `-d' was used. */
85
return delete_loopback (args[0]);
88
return grub_error (GRUB_ERR_BAD_ARGUMENT, "file name required");
90
file = grub_file_open (args[1]);
94
/* Close the file, the only reason for opening it is validation. */
95
grub_file_close (file);
97
/* First try to replace the old device. */
98
for (newdev = loopback_list; newdev; newdev = newdev->next)
99
if (!grub_strcmp (newdev->devname, args[0]))
103
char *newname = grub_strdup (args[1]);
107
grub_free (newdev->filename);
108
newdev->filename = newname;
110
/* Set has_partitions when `--partitions' was used. */
111
newdev->has_partitions = state[1].set;
116
/* Unable to replace it, make a new entry. */
117
newdev = grub_malloc (sizeof (struct grub_loopback));
121
newdev->devname = grub_strdup (args[0]);
122
if (!newdev->devname)
128
newdev->filename = grub_strdup (args[1]);
129
if (!newdev->devname)
131
grub_free (newdev->devname);
136
/* Set has_partitions when `--partitions' was used. */
137
newdev->has_partitions = state[1].set;
139
/* Add the new entry to the list. */
140
newdev->next = loopback_list;
141
loopback_list = newdev;
148
grub_loopback_iterate (int (*hook) (const char *name))
150
struct grub_loopback *d;
151
for (d = loopback_list; d; d = d->next)
153
if (hook (d->devname))
160
grub_loopback_open (const char *name, grub_disk_t disk)
163
struct grub_loopback *dev;
165
for (dev = loopback_list; dev; dev = dev->next)
166
if (!grub_strcmp (dev->devname, name))
170
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Can't open device");
172
file = grub_file_open (dev->filename);
176
/* Use the filesize for the disk size, round up to a complete sector. */
177
disk->total_sectors = ((file->size + GRUB_DISK_SECTOR_SIZE - 1)
178
/ GRUB_DISK_SECTOR_SIZE);
179
disk->id = (int) dev;
181
disk->has_partitions = dev->has_partitions;
188
grub_loopback_close (grub_disk_t disk)
190
grub_file_t file = (grub_file_t) disk->data;
192
grub_file_close (file);
196
grub_loopback_read (grub_disk_t disk, unsigned long sector,
197
unsigned long size, char *buf)
199
grub_file_t file = (grub_file_t) disk->data;
202
grub_file_seek (file, sector * GRUB_DISK_SECTOR_SIZE);
204
grub_file_read (file, buf, size * GRUB_DISK_SECTOR_SIZE);
208
/* In case there is more data read than there is available, in case
209
of files that are not a multiple of GRUB_DISK_SECTOR_SIZE, fill
210
the rest with zeros. */
211
pos = sector * GRUB_DISK_SECTOR_SIZE + size * GRUB_DISK_SECTOR_SIZE;
212
if (pos > file->size)
214
unsigned long amount = pos - file->size;
215
grub_memset (buf + pos - amount, amount, 0);
222
grub_loopback_write (grub_disk_t disk __attribute ((unused)),
223
unsigned long sector __attribute ((unused)),
224
unsigned long size __attribute ((unused)),
225
const char *buf __attribute ((unused)))
227
return GRUB_ERR_NOT_IMPLEMENTED_YET;
230
static struct grub_disk_dev grub_loopback_dev =
233
.id = GRUB_DISK_DEVICE_LOOPBACK_ID,
234
.iterate = grub_loopback_iterate,
235
.open = grub_loopback_open,
236
.close = grub_loopback_close,
237
.read = grub_loopback_read,
238
.write = grub_loopback_write,
246
(void)mod; /* To stop warning. */
247
grub_register_command ("loopback", grub_cmd_loopback, GRUB_COMMAND_FLAG_BOTH,
248
"loopback [-d|-p] DEVICENAME FILE",
249
"Make a device of a file.", options);
250
grub_disk_dev_register (&grub_loopback_dev);
255
grub_unregister_command ("loopback");
256
grub_disk_dev_unregister (&grub_loopback_dev);