mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
fish: Add -N option for making prepared disk images.
Previously you might have typed: $ guestfish ><fs> alloc test1.img 100M ><fs> run ><fs> part-disk /dev/sda mbr ><fs> mkfs ext4 /dev/sda1 now you can do the same with: $ guestfish -N fs:ext4 Some tests have also been updated to use this new functionality.
This commit is contained in:
10
TODO
10
TODO
@@ -212,16 +212,6 @@ ntfsclone
|
||||
Useful imaging tool:
|
||||
http://man.linux-ntfs.org/ntfsclone.8.html
|
||||
|
||||
Standard images
|
||||
---------------
|
||||
|
||||
Equip guestfish with some standard images that it can load
|
||||
quickly, eg:
|
||||
|
||||
load ext2
|
||||
|
||||
Maybe it's better to create these on the fly?
|
||||
|
||||
virt-rescue pty
|
||||
---------------
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ guestfish_SOURCES = \
|
||||
glob.c \
|
||||
lcd.c \
|
||||
more.c \
|
||||
prep.c \
|
||||
rc.c \
|
||||
reopen.c \
|
||||
tilde.c \
|
||||
|
||||
149
fish/alloc.c
149
fish/alloc.c
@@ -28,88 +28,47 @@
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
static int parse_size (const char *str, off_t *size_rtn);
|
||||
|
||||
int
|
||||
do_alloc (const char *cmd, int argc, char *argv[])
|
||||
{
|
||||
off_t size;
|
||||
int fd;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf (stderr, _("use 'alloc file size' to create an image\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_size (argv[1], &size) == -1)
|
||||
if (alloc_disk (argv[0], argv[1], 1, 0) == -1)
|
||||
return -1;
|
||||
|
||||
if (!guestfs_is_config (g)) {
|
||||
fprintf (stderr, _("can't allocate or add disks after launching\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open (argv[0], O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
|
||||
if (fd == -1) {
|
||||
perror (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_POSIX_FALLOCATE
|
||||
int err = posix_fallocate (fd, 0, size);
|
||||
if (err != 0) {
|
||||
errno = err;
|
||||
perror ("fallocate");
|
||||
close (fd);
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
/* Slow emulation of posix_fallocate on platforms which don't have it. */
|
||||
char buffer[BUFSIZ];
|
||||
memset (buffer, 0, sizeof buffer);
|
||||
|
||||
size_t remaining = size;
|
||||
while (remaining > 0) {
|
||||
size_t n = remaining > sizeof buffer ? sizeof buffer : remaining;
|
||||
ssize_t r = write (fd, buffer, n);
|
||||
if (r == -1) {
|
||||
perror ("write");
|
||||
close (fd);
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
remaining -= r;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (close (fd) == -1) {
|
||||
perror (argv[0]);
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (guestfs_add_drive (g, argv[0]) == -1) {
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
do_sparse (const char *cmd, int argc, char *argv[])
|
||||
{
|
||||
off_t size;
|
||||
int fd;
|
||||
char c = 0;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf (stderr, _("use 'sparse file size' to create a sparse image\n"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (parse_size (argv[1], &size) == -1)
|
||||
if (alloc_disk (argv[0], argv[1], 1, 1) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_size (const char *str, off_t *size_rtn);
|
||||
|
||||
/* This is the underlying allocation function. It's called from
|
||||
* a few other places in guestfish.
|
||||
*/
|
||||
int
|
||||
alloc_disk (const char *filename, const char *size_str, int add, int sparse)
|
||||
{
|
||||
off_t size;
|
||||
int fd;
|
||||
char c = 0;
|
||||
|
||||
if (parse_size (size_str, &size) == -1)
|
||||
return -1;
|
||||
|
||||
if (!guestfs_is_config (g)) {
|
||||
@@ -117,35 +76,67 @@ do_sparse (const char *cmd, int argc, char *argv[])
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open (argv[0], O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
|
||||
fd = open (filename, O_WRONLY|O_CREAT|O_NOCTTY|O_TRUNC, 0666);
|
||||
if (fd == -1) {
|
||||
perror (argv[0]);
|
||||
perror (filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (lseek (fd, size-1, SEEK_SET) == (off_t) -1) {
|
||||
perror ("lseek");
|
||||
close (fd);
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
if (!sparse) { /* Not sparse */
|
||||
#ifdef HAVE_POSIX_FALLOCATE
|
||||
int err = posix_fallocate (fd, 0, size);
|
||||
if (err != 0) {
|
||||
errno = err;
|
||||
perror ("fallocate");
|
||||
close (fd);
|
||||
unlink (filename);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
/* Slow emulation of posix_fallocate on platforms which don't have it. */
|
||||
char buffer[BUFSIZ];
|
||||
memset (buffer, 0, sizeof buffer);
|
||||
|
||||
if (write (fd, &c, 1) != 1) {
|
||||
perror ("write");
|
||||
close (fd);
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
size_t remaining = size;
|
||||
while (remaining > 0) {
|
||||
size_t n = remaining > sizeof buffer ? sizeof buffer : remaining;
|
||||
ssize_t r = write (fd, buffer, n);
|
||||
if (r == -1) {
|
||||
perror ("write");
|
||||
close (fd);
|
||||
unlink (filename);
|
||||
return -1;
|
||||
}
|
||||
remaining -= r;
|
||||
}
|
||||
#endif
|
||||
} else { /* Sparse */
|
||||
if (lseek (fd, size-1, SEEK_SET) == (off_t) -1) {
|
||||
perror ("lseek");
|
||||
close (fd);
|
||||
unlink (filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (write (fd, &c, 1) != 1) {
|
||||
perror ("write");
|
||||
close (fd);
|
||||
unlink (filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (close (fd) == -1) {
|
||||
perror (argv[0]);
|
||||
unlink (argv[0]);
|
||||
perror (filename);
|
||||
unlink (filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (guestfs_add_drive (g, argv[0]) == -1) {
|
||||
unlink (argv[0]);
|
||||
return -1;
|
||||
if (add) {
|
||||
if (guestfs_add_drive (g, filename) == -1) {
|
||||
unlink (filename);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
72
fish/fish.c
72
fish/fish.c
@@ -42,18 +42,21 @@
|
||||
#include "closeout.h"
|
||||
#include "progname.h"
|
||||
|
||||
struct drv {
|
||||
struct drv *next;
|
||||
char *filename; /* disk filename (for -a or -N options) */
|
||||
prep_data *data; /* prepared type (for -N option only) */
|
||||
char *device; /* device inside the appliance */
|
||||
};
|
||||
|
||||
struct mp {
|
||||
struct mp *next;
|
||||
char *device;
|
||||
char *mountpoint;
|
||||
};
|
||||
|
||||
struct drv {
|
||||
struct drv *next;
|
||||
char *filename;
|
||||
};
|
||||
|
||||
static void add_drives (struct drv *drv);
|
||||
static void prepare_drives (struct drv *drv);
|
||||
static void mount_mps (struct mp *mp);
|
||||
static void interactive (void);
|
||||
static void shell_script (void);
|
||||
@@ -119,6 +122,7 @@ usage (int status)
|
||||
" --listen Listen for remote commands\n"
|
||||
" -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
|
||||
" -n|--no-sync Don't autosync\n"
|
||||
" -N|--new type Create prepared disk (test1.img, ...)\n"
|
||||
" --remote[=pid] Send commands to remote %s\n"
|
||||
" -r|--ro Mount read-only\n"
|
||||
" --selinux Enable SELinux support\n"
|
||||
@@ -147,7 +151,7 @@ main (int argc, char *argv[])
|
||||
|
||||
enum { HELP_OPTION = CHAR_MAX + 1 };
|
||||
|
||||
static const char *options = "a:Df:h::im:nrv?Vx";
|
||||
static const char *options = "a:Df:h::im:nN:rv?Vx";
|
||||
static const struct option long_options[] = {
|
||||
{ "add", 1, 0, 'a' },
|
||||
{ "cmd-help", 2, 0, 'h' },
|
||||
@@ -156,6 +160,7 @@ main (int argc, char *argv[])
|
||||
{ "inspector", 0, 0, 'i' },
|
||||
{ "listen", 0, 0, 0 },
|
||||
{ "mount", 1, 0, 'm' },
|
||||
{ "new", 1, 0, 'N' },
|
||||
{ "no-dest-paths", 0, 0, 'D' },
|
||||
{ "no-sync", 0, 0, 'n' },
|
||||
{ "remote", 2, 0, 0 },
|
||||
@@ -174,6 +179,8 @@ main (int argc, char *argv[])
|
||||
int inspector = 0;
|
||||
int option_index;
|
||||
struct sigaction sa;
|
||||
char next_drive = 'a';
|
||||
int next_prepared_drive = 1;
|
||||
|
||||
initialize_readline ();
|
||||
|
||||
@@ -259,6 +266,36 @@ main (int argc, char *argv[])
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->filename = optarg;
|
||||
drv->data = NULL;
|
||||
/* We could fill the device field in, but in fact we
|
||||
* only use it for the -N option at present.
|
||||
*/
|
||||
drv->device = NULL;
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
next_drive++;
|
||||
break;
|
||||
|
||||
case 'N':
|
||||
if (STRCASEEQ (optarg, "list")) {
|
||||
list_prepared_drives ();
|
||||
exit (EXIT_SUCCESS);
|
||||
}
|
||||
drv = malloc (sizeof (struct drv));
|
||||
if (!drv) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
if (asprintf (&drv->filename, "test%d.img",
|
||||
next_prepared_drive++) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->data = create_prepared_file (optarg, drv->filename);
|
||||
if (asprintf (&drv->device, "/dev/sd%c", next_drive++) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
drv->next = drvs;
|
||||
drvs = drv;
|
||||
break;
|
||||
@@ -342,8 +379,8 @@ main (int argc, char *argv[])
|
||||
|
||||
if (drvs || mps || remote_control_listen || remote_control ||
|
||||
guestfs_get_selinux (g)) {
|
||||
fprintf (stderr, _("%s: cannot use -i option with -a, -m,"
|
||||
" --listen, --remote or --selinux\n"),
|
||||
fprintf (stderr, _("%s: cannot use -i option with -a, -m, -N, "
|
||||
"--listen, --remote or --selinux\n"),
|
||||
program_name);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
@@ -396,9 +433,12 @@ main (int argc, char *argv[])
|
||||
/* If we've got drives to add, add them now. */
|
||||
add_drives (drvs);
|
||||
|
||||
/* If we've got mountpoints, we must launch the guest and mount them. */
|
||||
if (mps != NULL) {
|
||||
/* If we've got mountpoints or prepared drives, we must launch the
|
||||
* guest and mount them.
|
||||
*/
|
||||
if (next_prepared_drive > 1 || mps != NULL) {
|
||||
if (launch (g) == -1) exit (EXIT_FAILURE);
|
||||
prepare_drives (drvs);
|
||||
mount_mps (mps);
|
||||
}
|
||||
|
||||
@@ -495,7 +535,8 @@ add_drives (struct drv *drv)
|
||||
|
||||
if (drv) {
|
||||
add_drives (drv->next);
|
||||
if (!read_only)
|
||||
|
||||
if (drv->data /* -N option is not affected by --ro */ || !read_only)
|
||||
r = guestfs_add_drive (g, drv->filename);
|
||||
else
|
||||
r = guestfs_add_drive_ro (g, drv->filename);
|
||||
@@ -504,6 +545,15 @@ add_drives (struct drv *drv)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
prepare_drives (struct drv *drv)
|
||||
{
|
||||
if (drv) {
|
||||
prepare_drives (drv->next);
|
||||
prepare_drive (drv->filename, drv->data, drv->device);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
interactive (void)
|
||||
{
|
||||
|
||||
10
fish/fish.h
10
fish/fish.h
@@ -85,6 +85,8 @@ extern char *complete_dest_paths_generator (const char *text, int state);
|
||||
/* in alloc.c */
|
||||
extern int do_alloc (const char *cmd, int argc, char *argv[]);
|
||||
extern int do_sparse (const char *cmd, int argc, char *argv[]);
|
||||
extern int alloc_disk (const char *filename, const char *size,
|
||||
int add, int sparse);
|
||||
|
||||
/* in echo.c */
|
||||
extern int do_echo (const char *cmd, int argc, char *argv[]);
|
||||
@@ -101,6 +103,14 @@ extern int do_glob (const char *cmd, int argc, char *argv[]);
|
||||
/* in more.c */
|
||||
extern int do_more (const char *cmd, int argc, char *argv[]);
|
||||
|
||||
/* in prep.c */
|
||||
typedef struct prep_data prep_data;
|
||||
extern void list_prepared_drives (void);
|
||||
extern prep_data *create_prepared_file (const char *type_string,
|
||||
const char *filename);
|
||||
extern void prepare_drive (const char *filename, prep_data *data,
|
||||
const char *device);
|
||||
|
||||
/* in rc.c (remote control) */
|
||||
extern void rc_listen (void) __attribute__((noreturn));
|
||||
extern int rc_remote (int pid, const char *cmd, int argc, char *argv[],
|
||||
|
||||
@@ -75,14 +75,25 @@ in the virtual machine:
|
||||
|
||||
=head2 As a script interpreter
|
||||
|
||||
Create a 50MB disk containing an ext2-formatted partition:
|
||||
Create a 100MB disk containing an ext2-formatted partition:
|
||||
|
||||
#!/usr/bin/guestfish -f
|
||||
alloc /tmp/output.img 50M
|
||||
sparse test1.img 100M
|
||||
run
|
||||
part-disk /dev/sda mbr
|
||||
mkfs ext2 /dev/sda1
|
||||
|
||||
=head2 Start with a prepared disk
|
||||
|
||||
An alternate way to create a 100MB disk called C<test1.img> containing
|
||||
a single ext2-formatted partition:
|
||||
|
||||
guestfish -N fs
|
||||
|
||||
To list what is available do:
|
||||
|
||||
guestfish -N list | less
|
||||
|
||||
=head2 Remote control
|
||||
|
||||
eval `guestfish --listen --ro`
|
||||
@@ -159,9 +170,9 @@ Typical usage is either:
|
||||
|
||||
guestfish -i /dev/Guests/MyGuest
|
||||
|
||||
You cannot use I<-a>, I<-m>, I<--listen>, I<--remote> or I<--selinux>
|
||||
in conjunction with this option, and options other than I<--ro> might
|
||||
not behave correctly.
|
||||
You cannot use I<-a>, I<-m>, I<-N>, I<--listen>, I<--remote> or
|
||||
I<--selinux> in conjunction with this option, and options other than
|
||||
I<--ro> might not behave correctly.
|
||||
|
||||
See also: L<virt-inspector(1)>.
|
||||
|
||||
@@ -191,6 +202,13 @@ or you can use the L<virt-list-filesystems(1)> program.
|
||||
Disable autosync. This is enabled by default. See the discussion
|
||||
of autosync in the L<guestfs(3)> manpage.
|
||||
|
||||
=item B<-N type> | B<--new type> | B<-N list>
|
||||
|
||||
Prepare a fresh disk image formatted as "type". This is an
|
||||
alternative to the I<-a> option: whereas I<-a> adds an existing disk,
|
||||
I<-N> creates a preformatted disk with a filesystem and adds it.
|
||||
See L</PREPARED DISK IMAGES> below.
|
||||
|
||||
=item B<--remote[=pid]>
|
||||
|
||||
Send remote commands to C<$GUESTFISH_PID> or C<pid>. See section
|
||||
@@ -205,6 +223,9 @@ The option must always be used if the disk image or virtual machine
|
||||
might be running, and is generally recommended in cases where you
|
||||
don't need write access to the disk.
|
||||
|
||||
Note that prepared disk images created with I<-N> are not affected by
|
||||
the I<--ro> option.
|
||||
|
||||
=item B<--selinux>
|
||||
|
||||
Enable SELinux support for the guest. See L<guestfs(3)/SELINUX>.
|
||||
@@ -486,6 +507,51 @@ user ID of the process, and C<$PID> is the process ID of the server.
|
||||
|
||||
Guestfish client and server versions must match exactly.
|
||||
|
||||
=head1 PREPARED DISK IMAGES
|
||||
|
||||
Use the I<-N type> or I<--new type> parameter to select one of a set
|
||||
of preformatted disk images that guestfish can make for you to save
|
||||
typing. This is particularly useful for testing purposes. This
|
||||
option is used instead of the I<-a> option, and like I<-a> can appear
|
||||
multiple times (and can be mixed with I<-a>).
|
||||
|
||||
The new disk is called C<test1.img> for the first I<-N>, C<test2.img>
|
||||
for the second and so on. Existing files in the current directory are
|
||||
not overwritten, so you may need to do C<rm -f test1.img>.
|
||||
|
||||
The type briefly describes how the disk should be sized, partitioned,
|
||||
how filesystem(s) should be created, and how content should be added.
|
||||
Optionally the type can be followed by extra parameters, separated by
|
||||
C<:> (colon) characters. For example, I<-N fs> creates a default
|
||||
100MB, sparsely-allocated disk, containing a single partition, with
|
||||
the partition formatted as ext2. I<-N fs:ext4:1G> is the same, but
|
||||
for an ext4 filesystem on a 1GB disk instead.
|
||||
|
||||
To list the available types and any extra parameters they take, run:
|
||||
|
||||
guestfish -N list | less
|
||||
|
||||
Note that the prepared filesystem is not mounted. You would usually
|
||||
have to use the C<mount /dev/sda1 /> command or add the
|
||||
I<-m /dev/sda1> option.
|
||||
|
||||
If any I<-N> or I<--new> options are given, the guest is automatically
|
||||
launched.
|
||||
|
||||
=head2 EXAMPLES
|
||||
|
||||
Create a 100MB disk with an ext4-formatted partition:
|
||||
|
||||
guestfish -N fs:ext4
|
||||
|
||||
Create a 32MB disk with a VFAT-formatted partition, and mount it:
|
||||
|
||||
guestfish -N fs:vfat:32M -m /dev/sda1
|
||||
|
||||
Create a blank 200MB disk:
|
||||
|
||||
guestfish -N disk:200M
|
||||
|
||||
=head1 UPLOADING AND DOWNLOADING FILES
|
||||
|
||||
For commands such as C<upload>, C<download>, C<tar-in>, C<tar-out> and
|
||||
|
||||
305
fish/prep.c
Normal file
305
fish/prep.c
Normal file
@@ -0,0 +1,305 @@
|
||||
/* guestfish - the filesystem interactive shell
|
||||
* Copyright (C) 2010 Red Hat Inc.
|
||||
*
|
||||
* This program 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 this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "fish.h"
|
||||
|
||||
static prep_data *parse_type_string (const char *type_string);
|
||||
static void prep_error (prep_data *data, const char *filename, const char *fs, ...) __attribute__((noreturn, format (printf,3,4)));
|
||||
|
||||
struct prep {
|
||||
const char *name; /* eg. "fs" */
|
||||
|
||||
size_t nr_params; /* optional parameters */
|
||||
struct param *params;
|
||||
|
||||
const char *shortdesc; /* short description */
|
||||
const char *longdesc; /* long description */
|
||||
|
||||
/* functions to implement it */
|
||||
void (*prelaunch) (const char *filename, prep_data *);
|
||||
void (*postlaunch) (const char *filename, prep_data *, const char *device);
|
||||
};
|
||||
|
||||
struct param {
|
||||
const char *pname; /* parameter name */
|
||||
const char *pdefault; /* parameter default */
|
||||
const char *pdesc; /* parameter description */
|
||||
};
|
||||
|
||||
static void prelaunch_disk (const char *filename, prep_data *data);
|
||||
static struct param disk_params[] = {
|
||||
{ "size", "100M", "the size of the disk image" },
|
||||
};
|
||||
|
||||
static void prelaunch_part (const char *filename, prep_data *data);
|
||||
static void postlaunch_part (const char *filename, prep_data *data, const char *device);
|
||||
static struct param part_params[] = {
|
||||
{ "size", "100M", "the size of the disk image" },
|
||||
{ "partition", "mbr", "partition table type" },
|
||||
};
|
||||
|
||||
static void prelaunch_fs (const char *filename, prep_data *data);
|
||||
static void postlaunch_fs (const char *filename, prep_data *data, const char *device);
|
||||
static struct param fs_params[] = {
|
||||
{ "filesystem", "ext2", "the type of filesystem to use" },
|
||||
{ "size", "100M", "the size of the disk image" },
|
||||
{ "partition", "mbr", "partition table type" },
|
||||
};
|
||||
|
||||
static const struct prep preps[] = {
|
||||
{ "disk",
|
||||
1, disk_params,
|
||||
"create a blank disk",
|
||||
"\
|
||||
Create a blank disk, size 100MB (by default).\n\
|
||||
\n\
|
||||
The default size can be changed by supplying an optional parameter.",
|
||||
prelaunch_disk, NULL
|
||||
},
|
||||
{ "part",
|
||||
2, part_params,
|
||||
"create a partitioned disk",
|
||||
"\
|
||||
Create a disk with a single partition. By default the size of the disk\n\
|
||||
is 100MB (the available space in the partition will be a tiny bit smaller)\n\
|
||||
and the partition table will be MBR (old DOS-style).\n\
|
||||
\n\
|
||||
These defaults can be changed by supplying optional parameters.",
|
||||
prelaunch_part, postlaunch_part
|
||||
},
|
||||
{ "fs",
|
||||
3, fs_params,
|
||||
"create a filesystem",
|
||||
"\
|
||||
Create a disk with a single partition, with the partition containing\n\
|
||||
an empty filesystem. This defaults to creating a 100MB disk (the available\n\
|
||||
space in the filesystem will be a tiny bit smaller) with an MBR (old\n\
|
||||
DOS-style) partition table and an ext2 filesystem.\n\
|
||||
\n\
|
||||
These defaults can be changed by supplying optional parameters.",
|
||||
prelaunch_fs, postlaunch_fs
|
||||
},
|
||||
};
|
||||
|
||||
void
|
||||
list_prepared_drives (void)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
printf (_("List of available prepared disk images:\n\n"));
|
||||
|
||||
for (i = 0; i < sizeof preps / sizeof preps[0]; ++i) {
|
||||
printf (_("\
|
||||
guestfish -N %-16s %s\n\
|
||||
\n\
|
||||
%s\n"),
|
||||
preps[i].name, preps[i].shortdesc, preps[i].longdesc);
|
||||
|
||||
if (preps[i].nr_params > 0) {
|
||||
printf ("\n");
|
||||
printf (_(" Optional parameters:\n"));
|
||||
printf (" -N %s", preps[i].name);
|
||||
for (j = 0; j < preps[i].nr_params; ++j)
|
||||
printf (":<%s>", preps[i].params[j].pname);
|
||||
printf ("\n");
|
||||
for (j = 0; j < preps[i].nr_params; ++j) {
|
||||
printf (" ");
|
||||
printf (_("<%s> %s (default: %s)\n"),
|
||||
preps[i].params[j].pname,
|
||||
preps[i].params[j].pdesc,
|
||||
preps[i].params[j].pdefault);
|
||||
}
|
||||
}
|
||||
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
printf (_("\
|
||||
Prepared disk images are written to file \"test1.img\" in the local\n\
|
||||
directory. (\"test2.img\" etc if -N option is given multiple times).\n\
|
||||
For more information see the guestfish(1) manual.\n"));
|
||||
}
|
||||
|
||||
struct prep_data {
|
||||
const struct prep *prep;
|
||||
const char *orig_type_string;
|
||||
const char **params;
|
||||
};
|
||||
|
||||
/* Parse the type string (from the command line) and create the output
|
||||
* file 'filename'. This is called before launch. Return the opaque
|
||||
* prep_data which will be passed back to us in prepare_drive below.
|
||||
*/
|
||||
prep_data *
|
||||
create_prepared_file (const char *type_string, const char *filename)
|
||||
{
|
||||
if (access (filename, F_OK) == 0) {
|
||||
fprintf (stderr, _("guestfish: file '%s' exists and the '-N' option will not overwrite it\n"),
|
||||
filename);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
prep_data *data = parse_type_string (type_string);
|
||||
if (data->prep->prelaunch)
|
||||
data->prep->prelaunch (filename, data);
|
||||
return data;
|
||||
}
|
||||
|
||||
static prep_data *
|
||||
parse_type_string (const char *type_string)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/* Match on the type part (without parameters). */
|
||||
size_t len = strcspn (type_string, ":");
|
||||
for (i = 0; i < sizeof preps / sizeof preps[0]; ++i)
|
||||
if (STRCASEEQLEN (type_string, preps[i].name, len))
|
||||
break;
|
||||
|
||||
if (preps[i].name == NULL) {
|
||||
fprintf (stderr, _("\
|
||||
guestfish: -N parameter '%s': no such prepared disk image known.\n\
|
||||
Use 'guestfish -N list' to list possible values for the -N parameter.\n"),
|
||||
type_string);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
prep_data *data = malloc (sizeof *data);
|
||||
if (data == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
data->prep = &preps[i];
|
||||
data->orig_type_string = type_string;
|
||||
|
||||
/* Set up the optional parameters to all-defaults. */
|
||||
data->params = malloc (data->prep->nr_params * sizeof (char *));
|
||||
if (data->params == NULL) {
|
||||
perror ("malloc");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < data->prep->nr_params; ++i)
|
||||
data->params[i] = data->prep->params[i].pdefault;
|
||||
|
||||
/* Parse the optional parameters. */
|
||||
const char *p = type_string + len;
|
||||
if (*p) p++; /* skip colon char */
|
||||
|
||||
i = 0;
|
||||
while (*p) {
|
||||
len = strcspn (p, ":");
|
||||
data->params[i] = strndup (p, len);
|
||||
if (data->params[i] == NULL) {
|
||||
perror ("strndup");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
p += len;
|
||||
if (*p) p++; /* skip colon char */
|
||||
i++;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/* Prepare a drive. The appliance has been launched, and 'device' is
|
||||
* the libguestfs device. 'data' is the requested type. 'filename'
|
||||
* is just used for error messages.
|
||||
*/
|
||||
void
|
||||
prepare_drive (const char *filename, prep_data *data,
|
||||
const char *device)
|
||||
{
|
||||
if (data->prep->postlaunch)
|
||||
data->prep->postlaunch (filename, data, device);
|
||||
}
|
||||
|
||||
static void
|
||||
prep_error (prep_data *data, const char *filename, const char *fs, ...)
|
||||
{
|
||||
fprintf (stderr,
|
||||
_("guestfish: error creating prepared disk image '%s' on '%s': "),
|
||||
data->orig_type_string, filename);
|
||||
|
||||
va_list args;
|
||||
va_start (args, fs);
|
||||
vfprintf (stderr, fs, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
prelaunch_disk (const char *filename, prep_data *data)
|
||||
{
|
||||
if (alloc_disk (filename, data->params[0], 0, 1) == -1)
|
||||
prep_error (data, filename, _("failed to allocate disk"));
|
||||
}
|
||||
|
||||
static void
|
||||
prelaunch_part (const char *filename, prep_data *data)
|
||||
{
|
||||
if (alloc_disk (filename, data->params[0], 0, 1) == -1)
|
||||
prep_error (data, filename, _("failed to allocate disk"));
|
||||
}
|
||||
|
||||
static void
|
||||
postlaunch_part (const char *filename, prep_data *data, const char *device)
|
||||
{
|
||||
if (guestfs_part_disk (g, device, data->params[2]) == -1)
|
||||
prep_error (data, filename, _("failed to partition disk: %s"),
|
||||
guestfs_last_error (g));
|
||||
}
|
||||
|
||||
static void
|
||||
prelaunch_fs (const char *filename, prep_data *data)
|
||||
{
|
||||
if (alloc_disk (filename, data->params[1], 0, 1) == -1)
|
||||
prep_error (data, filename, _("failed to allocate disk"));
|
||||
}
|
||||
|
||||
static void
|
||||
postlaunch_fs (const char *filename, prep_data *data, const char *device)
|
||||
{
|
||||
if (guestfs_part_disk (g, device, data->params[2]) == -1)
|
||||
prep_error (data, filename, _("failed to partition disk: %s"),
|
||||
guestfs_last_error (g));
|
||||
|
||||
char *part;
|
||||
if (asprintf (&part, "%s1", device) == -1) {
|
||||
perror ("asprintf");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (guestfs_mkfs (g, data->params[0], part) == -1)
|
||||
prep_error (data, filename, _("failed to create filesystem (%s): %s"),
|
||||
data->params[0], guestfs_last_error (g));
|
||||
|
||||
free (part);
|
||||
}
|
||||
@@ -76,6 +76,7 @@ fish/fish.c
|
||||
fish/glob.c
|
||||
fish/lcd.c
|
||||
fish/more.c
|
||||
fish/prep.c
|
||||
fish/rc.c
|
||||
fish/reopen.c
|
||||
fish/tilde.c
|
||||
|
||||
@@ -23,12 +23,7 @@ set -e
|
||||
|
||||
rm -f test1.img
|
||||
|
||||
../fish/guestfish <<EOF
|
||||
sparse test1.img 10M
|
||||
launch
|
||||
part-disk /dev/sda mbr
|
||||
mkfs ext2 /dev/sda1
|
||||
mount-options "" /dev/sda1 /
|
||||
../fish/guestfish -N fs -m /dev/sda1 <<EOF
|
||||
ll /../dev/console
|
||||
ll /../dev/full
|
||||
ll /../dev/mapper/
|
||||
|
||||
@@ -28,12 +28,7 @@ set -e
|
||||
|
||||
rm -f test1.img
|
||||
|
||||
../fish/guestfish <<EOF
|
||||
sparse test1.img 10M
|
||||
run
|
||||
part-disk /dev/sda mbr
|
||||
mkfs ext2 /dev/sda1
|
||||
mount-options "" /dev/sda1 /
|
||||
../fish/guestfish -N fs -m /dev/sda1 <<EOF
|
||||
mkdir /dev
|
||||
-command /ignore-this-error
|
||||
unmount-all
|
||||
|
||||
@@ -49,13 +49,7 @@ get-memsize
|
||||
-set-memsize 123L
|
||||
EOF
|
||||
|
||||
../fish/guestfish >> test.out 2>> test.err <<EOF
|
||||
alloc test1.img 10M
|
||||
run
|
||||
part-disk /dev/sda mbr
|
||||
mkfs ext2 /dev/sda1
|
||||
mount /dev/sda1 /
|
||||
|
||||
../fish/guestfish -N fs -m /dev/sda1 >> test.out 2>> test.err <<EOF
|
||||
touch /test
|
||||
|
||||
# truncate-size takes an Int64 argument
|
||||
|
||||
@@ -24,9 +24,7 @@ set -e
|
||||
|
||||
rm -f test1.img
|
||||
|
||||
../fish/guestfish <<EOF
|
||||
alloc test1.img 10M
|
||||
run
|
||||
../fish/guestfish -N disk <<EOF
|
||||
-upload $srcdir/rhbz576879.sh /test.sh
|
||||
# Shouldn't lose synchronization, so next command should work:
|
||||
ping-daemon
|
||||
|
||||
@@ -32,7 +32,7 @@ export LIBGUESTFS_DEBUG=1
|
||||
|
||||
for i in $(seq 1 $n); do
|
||||
echo Test boot $i of $n ...
|
||||
../fish/guestfish sparse test1.img 500M : run
|
||||
../fish/guestfish -N disk </dev/null
|
||||
done
|
||||
|
||||
rm test1.img
|
||||
|
||||
@@ -22,16 +22,9 @@
|
||||
|
||||
set -e
|
||||
|
||||
rm -f test.img
|
||||
|
||||
../fish/guestfish <<'EOF'
|
||||
alloc test.img 10M
|
||||
run
|
||||
|
||||
part-disk /dev/sda mbr
|
||||
mkfs ext2 /dev/sda1
|
||||
mount-options "" /dev/sda1 /
|
||||
rm -f test1.img
|
||||
|
||||
../fish/guestfish -N fs -m /dev/sda1 <<'EOF'
|
||||
# Upload image, daemon should cancel because the image is too large
|
||||
# to upload into itself.
|
||||
echo "Expect: write: /test: No space left on device"
|
||||
@@ -40,4 +33,4 @@ echo "Expect: write: /test: No space left on device"
|
||||
ping-daemon
|
||||
EOF
|
||||
|
||||
rm -f test.img
|
||||
rm -f test1.img
|
||||
|
||||
@@ -20,12 +20,9 @@
|
||||
|
||||
set -e
|
||||
|
||||
rm -f test.img
|
||||
|
||||
../fish/guestfish <<'EOF'
|
||||
alloc test.img 10M
|
||||
run
|
||||
rm -f test1.img
|
||||
|
||||
../fish/guestfish -N disk <<'EOF'
|
||||
# Kill the subprocess.
|
||||
kill-subprocess
|
||||
|
||||
@@ -38,4 +35,4 @@ run
|
||||
ping-daemon
|
||||
EOF
|
||||
|
||||
rm -f test.img
|
||||
rm -f test1.img
|
||||
|
||||
@@ -20,12 +20,9 @@
|
||||
|
||||
set -e
|
||||
|
||||
rm -f test.pid test.img
|
||||
|
||||
../fish/guestfish <<'EOF'
|
||||
alloc test.img 10M
|
||||
run
|
||||
rm -f test.pid test1.img
|
||||
|
||||
../fish/guestfish -N disk <<'EOF'
|
||||
# Kill the subprocess after a short wait.
|
||||
pid | cat > test.pid
|
||||
! sleep 2 ; kill $(cat test.pid) &
|
||||
@@ -38,4 +35,4 @@ run
|
||||
ping-daemon
|
||||
EOF
|
||||
|
||||
rm -f test.pid test.img
|
||||
rm -f test.pid test1.img
|
||||
|
||||
@@ -20,12 +20,9 @@
|
||||
|
||||
set -e
|
||||
|
||||
rm -f test.pid test.img
|
||||
|
||||
../fish/guestfish <<'EOF'
|
||||
alloc test.img 10M
|
||||
run
|
||||
rm -f test.pid test1.img
|
||||
|
||||
../fish/guestfish -N disk <<'EOF'
|
||||
# Kill subprocess.
|
||||
pid | cat > test.pid
|
||||
! kill $(cat test.pid) ; sleep 2
|
||||
@@ -39,4 +36,4 @@ run
|
||||
ping-daemon
|
||||
EOF
|
||||
|
||||
rm -f test.pid test.img
|
||||
rm -f test.pid test1.img
|
||||
|
||||
Reference in New Issue
Block a user