import vhd-tools from xen-4.0.1

This commit is contained in:
anthony 2011-02-28 19:40:43 -08:00
parent 0ef191bed7
commit fecd83d2b4
37 changed files with 13360 additions and 0 deletions

17
tools/vhd-tools/Makefile Normal file
View File

@ -0,0 +1,17 @@
XEN_ROOT = ../..
include $(XEN_ROOT)/tools/Rules.mk
CFLAGS += $(CFLAGS_libxenctrl)
LDFLAGS += $(LDFLAGS_libxenctrl)
SUBDIRS-y :=
SUBDIRS-y += include
SUBDIRS-y += lvm
SUBDIRS-y += vhd
SUBDIRS-y += drivers
clean:
rm -rf *.a *.so *.o *.rpm $(LIB) *~ $(DEPS) TAGS
.PHONY: all clean install
all clean install: %: subdirs-%

321
tools/vhd-tools/README Normal file
View File

@ -0,0 +1,321 @@
Blktap2 Userspace Tools + Library
================================
Dutch Meyer
4th June 2009
Andrew Warfield and Julian Chesterfield
16th June 2006
The blktap2 userspace toolkit provides a user-level disk I/O
interface. The blktap2 mechanism involves a kernel driver that acts
similarly to the existing Xen/Linux blkback driver, and a set of
associated user-level libraries. Using these tools, blktap2 allows
virtual block devices presented to VMs to be implemented in userspace
and to be backed by raw partitions, files, network, etc.
The key benefit of blktap2 is that it makes it easy and fast to write
arbitrary block backends, and that these user-level backends actually
perform very well. Specifically:
- Metadata disk formats such as Copy-on-Write, encrypted disks, sparse
formats and other compression features can be easily implemented.
- Accessing file-based images from userspace avoids problems related
to flushing dirty pages which are present in the Linux loopback
driver. (Specifically, doing a large number of writes to an
NFS-backed image don't result in the OOM killer going berserk.)
- Per-disk handler processes enable easier userspace policing of block
resources, and process-granularity QoS techniques (disk scheduling
and related tools) may be trivially applied to block devices.
- It's very easy to take advantage of userspace facilities such as
networking libraries, compression utilities, peer-to-peer
file-sharing systems and so on to build more complex block backends.
- Crashes are contained -- incremental development/debugging is very
fast.
How it works (in one paragraph):
Working in conjunction with the kernel blktap2 driver, all disk I/O
requests from VMs are passed to the userspace deamon (using a shared
memory interface) through a character device. Each active disk is
mapped to an individual device node, allowing per-disk processes to
implement individual block devices where desired. The userspace
drivers are implemented using asynchronous (Linux libaio),
O_DIRECT-based calls to preserve the unbuffered, batched and
asynchronous request dispatch achieved with the existing blkback
code. We provide a simple, asynchronous virtual disk interface that
makes it quite easy to add new disk implementations.
As of June 2009 the current supported disk formats are:
- Raw Images (both on partitions and in image files)
- Fast sharable RAM disk between VMs (requires some form of
cluster-based filesystem support e.g. OCFS2 in the guest kernel)
- VHD, including snapshots and sparse images
- Qcow, including snapshots and sparse images
Build and Installation Instructions
===================================
Make to configure the blktap2 backend driver in your dom0 kernel. It
will inter-operate with the existing backend and frontend drivers. It
will also cohabitate with the original blktap driver. However, some
formats (currently aio and qcow) will default to their blktap2
versions when specified in a vm configuration file.
To build the tools separately, "make && make install" in
tools/blktap2.
Using the Tools
===============
Preparing an image for boot:
The userspace disk agent is configured to start automatically via xend
Customize the VM config file to use the 'tap:tapdisk' handler,
followed by the driver type. e.g. for a raw image such as a file or
partition:
disk = ['tap:tapdisk:aio:<FILENAME>,sda1,w']
Alternatively, the vhd-util tool (installed with make install, or in
/blktap2/vhd) can be used to build sparse copy-on-write vhd images.
For example, to build a sparse image -
vhd-util create -n MyVHDFile -s 1024
This creates a sparse 1GB file named "MyVHDFile" that can be mounted
and populated with data.
One can also base the image on a raw file -
vhd-util snapshot -n MyVHDFile -p SomeRawFile -m
This creates a sparse VHD file named "MyVHDFile" using "SomeRawFile"
as a parent image. Copy-on-write semantics ensure that writes will be
stored in "MyVHDFile" while reads will be directed to the most
recently written version of the data, either in "MyVHDFile" or
"SomeRawFile" as is appropriate. Other options exist as well, consult
the vhd-util application for the complete set of VHD tools.
VHD files can be mounted automatically in a guest similarly to the
above AIO example simply by specifying the vhd driver.
disk = ['tap:tapdisk:vhd:<VHD FILENAME>,sda1,w']
Snapshots:
Pausing a guest will also plug the corresponding IO queue for blktap2
devices and stop blktap2 drivers. This can be used to implement a
safe live snapshot of qcow and vhd disks. An example script "xmsnap"
is shown in the tools/blktap2/drivers directory. This script will
perform a live snapshot of a qcow disk. VHD files can use the
"vhd-util snapshot" tool discussed above. If this snapshot command is
applied to a raw file mounted with tap:tapdisk:AIO, include the -m
flag and the driver will be reloaded as VHD. If applied to an already
mounted VHD file, omit the -m flag.
Mounting images in Dom0 using the blktap2 driver
===============================================
Tap (and blkback) disks are also mountable in Dom0 without requiring an
active VM to attach.
The syntax is -
tapdisk2 -n <type>:<full path to file>
For example -
tapdisk2 -n aio:/home/images/rawFile.img
When successful the location of the new device will be provided by
tapdisk2 to stdout and tapdisk2 will terminate. From that point
forward control of the device is provided through sysfs in the
directory-
/sys/class/blktap2/blktap#/
Where # is a blktap2 device number present in the path that tapdisk2
printed before terminating. The sysfs interface is largely intuitive,
for example, to remove tap device 0 one would-
echo 1 > /sys/class/blktap2/blktap0/remove
Similarly, a pause control is available, which is can be used to plug
the request queue of a live running guest.
Previous versions of blktap mounted devices in dom0 by using blkfront
in dom0 and the xm block-attach command. This approach is still
available, though slightly more cumbersome.
Tapdisk Development
===============================================
People regularly ask how to develop their own tapdisk drivers, and
while it has not yet been well documented, the process is relatively
easy. Here I will provide a brief overview. The best reference, of
course, comes from the existing drivers. Specifically,
blktap2/drivers/block-ram.c and blktap2/drivers/block-aio.c provide
the clearest examples of simple drivers.
Setup:
First you need to register your new driver with blktap. This is done
in disktypes.h. There are five things that you must do. To
demonstrate, I will create a disk called "mynewdisk", you can name
yours freely.
1) Forward declare an instance of struct tap_disk.
e.g. -
extern struct tap_disk tapdisk_mynewdisk;
2) Claim one of the unused disk type numbers, take care to observe the
MAX_DISK_TYPES macro, increasing the number if necessary.
e.g. -
#define DISK_TYPE_MYNEWDISK 10
3) Create an instance of disk_info_t. The bulk of this file contains examples of these.
e.g. -
static disk_info_t mynewdisk_disk = {
DISK_TYPE_MYNEWDISK,
"My New Disk (mynewdisk)",
"mynewdisk",
0,
#ifdef TAPDISK
&tapdisk_mynewdisk,
#endif
};
A few words about what these mean. The first field must be the disk
type number you claimed in step (2). The second field is a string
describing your disk, and may contain any relevant info. The third
field is the name of your disk as will be used by the tapdisk2 utility
and xend (for example tapdisk2 -n mynewdisk:/path/to/disk.image, or in
your xm create config file). The forth is binary and determines
whether you will have one instance of your driver, or many. Here, a 1
means that your driver is a singleton and will coordinate access to
any number of tap devices. 0 is more common, meaning that you will
have one driver for each device that is created. The final field
should contain a reference to the struct tap_disk you created in step
(1).
4) Add a reference to your disk info structure (from step (3)) to the
dtypes array. Take care here - you need to place it in the position
corresponding to the device type number you claimed in step (2). So
we would place &mynewdisk_disk in dtypes[10]. Look at the other
devices in this array and pad with "&null_disk," as necessary.
5) Modify the xend python scripts. You need to add your disk name to
the list of disks that xend recognizes.
edit:
tools/python/xen/xend/server/BlktapController.py
And add your disk to the "blktap_disk_types" array near the top of
your file. Use the same name you specified in the third field of step
(3). The order of this list is not important.
Now your driver is ready to be written. Create a block-mynewdisk.c in
tools/blktap2/drivers and add it to the Makefile.
Development:
Copying block-aio.c and block-ram.c would be a good place to start.
Read those files as you go through this, I will be assisting by
commenting on a few useful functions and structures.
struct tap_disk:
Remember the forward declaration in step (1) of the setup phase above?
Now is the time to make that structure a reality. This structure
contains a list of function pointers for all the routines that will be
asked of your driver. Currently the required functions are open,
close, read, write, get_parent_id, validate_parent, and debug.
e.g. -
struct tap_disk tapdisk_mynewdisk = {
.disk_type = "tapdisk_mynewdisk",
.flags = 0,
.private_data_size = sizeof(struct tdmynewdisk_state),
.td_open = tdmynewdisk_open,
....
The private_data_size field is used to provide a structure to store
the state of your device. It is very likely that you will want
something here, but you are free to design whatever structure you
want. Blktap will allocate this space for you, you just need to tell
it how much space you want.
tdmynewdisk_open:
This is the open routine. The first argument is a structure
representing your driver. Two fields in this array are
interesting.
driver->data will contain a block of memory of the size your requested
in in the .private_data_size field of your struct tap_disk (above).
driver->info contains a structure that details information about your
disk. You need to fill this out. By convention this is done with a
_get_image_info() function. Assign a size (the total number of
sectors), sector_size (the size of each sector in bytes, and set
driver->info->info to 0.
The second parameter contains the name that was specified in the
creation of your device, either through xend, or on the command line
with tapdisk2. Usually this specifies a file that you will open in
this routine. The final parameter, flags, contains one of a number of
flags specified in tapdisk.h that may change the way you treat the
disk.
_queue_read/write:
These are your read and write operations. What you do here will
depend on your disk, but you should do exactly one of-
1) call td_complete_request with either error or success code.
2) Call td_forward_request, which will forward the request to the next
driver in the stack.
3) Queue the request for asynchronous processing with
td_prep_read/write. In doing so, you will also register a callback
for request completion. When the request completes you must do one of
options (1) or (2) above. Finally, call td_queue_tiocb to submit the
request to a wait queue.
The above functions are defined in tapdisk-interface.c. If you don't
use them as specified you will run into problems as your driver will
fail to inform blktap of the state of requests that have been
submitted. Blktap keeps track of all requests and does not like losing track.
_close, _get_parent_id, _validate_parent:
These last few tend to be very routine. _close is called when the
device is closed, and also when it is paused (in this case, open will
also be called later). The other functions are used in stacking
drivers. Most often drivers will return TD_NO_PARENT and -EINVAL,
respectively.

View File

@ -0,0 +1,14 @@
XEN_ROOT := ../../..
include $(XEN_ROOT)/tools/Rules.mk
.PHONY: all
all:
.PHONY: install
install:
$(INSTALL_DIR) -p $(DESTDIR)$(INCLUDEDIR)
.PHONY: clean
clean:
@:

View File

@ -0,0 +1,33 @@
/* $OpenBSD: atomicio.h,v 1.6 2005/05/24 17:32:43 avsm Exp $ */
/*
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Ensure all of data on socket comes through. f==read || f==vwrite
*/
size_t atomicio(ssize_t (*)(int, void *, size_t), int, void *, size_t);
#define vwrite (ssize_t (*)(int, void *, size_t))write

View File

@ -0,0 +1,130 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BLKTAP2_UUID_H__
#define __BLKTAP2_UUID_H__
#if defined(__linux__)
#include <uuid/uuid.h>
typedef struct {
uuid_t uuid;
} blk_uuid_t;
static inline int blk_uuid_is_nil(blk_uuid_t *uuid)
{
return uuid_is_null(uuid->uuid);
}
static inline void blk_uuid_generate(blk_uuid_t *uuid)
{
uuid_generate(uuid->uuid);
}
static inline void blk_uuid_to_string(blk_uuid_t *uuid, char *out, size_t size)
{
uuid_unparse(uuid->uuid, out);
}
static inline void blk_uuid_from_string(blk_uuid_t *uuid, const char *in)
{
uuid_parse(in, uuid->uuid);
}
static inline void blk_uuid_copy(blk_uuid_t *dst, blk_uuid_t *src)
{
uuid_copy(dst->uuid, src->uuid);
}
static inline void blk_uuid_clear(blk_uuid_t *uuid)
{
uuid_clear(uuid->uuid);
}
static inline int blk_uuid_compare(blk_uuid_t *uuid1, blk_uuid_t *uuid2)
{
return uuid_compare(uuid1->uuid, uuid2->uuid);
}
#elif defined(__NetBSD__)
#include <uuid.h>
#include <string.h>
#include <stdlib.h>
typedef uuid_t blk_uuid_t;
static inline int blk_uuid_is_nil(blk_uuid_t *uuid)
{
uint32_t status;
return uuid_is_nil((uuid_t *)uuid, &status);
}
static inline void blk_uuid_generate(blk_uuid_t *uuid)
{
uint32_t status;
uuid_create((uuid_t *)uuid, &status);
}
static inline void blk_uuid_to_string(blk_uuid_t *uuid, char *out, size_t size)
{
uint32_t status;
char *_out = NULL;
uuid_to_string((uuid_t *)uuid, &_out, &status);
strlcpy(out, _out, size);
free(_out);
}
static inline void blk_uuid_from_string(blk_uuid_t *uuid, const char *in)
{
uint32_t status;
uuid_from_string(in, (uuid_t *)uuid, &status);
}
static inline void blk_uuid_copy(blk_uuid_t *dst, blk_uuid_t *src)
{
memcpy((uuid_t *)dst, (uuid_t *)src, sizeof(uuid_t));
}
static inline void blk_uuid_clear(blk_uuid_t *uuid)
{
memset((uuid_t *)uuid, 0, sizeof(uuid_t));
}
static inline int blk_uuid_compare(blk_uuid_t *uuid1, blk_uuid_t *uuid2)
{
uint32_t status;
return uuid_compare((uuid_t *)uuid1, (uuid_t *)uuid2, &status);
}
#else
#error "Please update blk_uuid.h for your OS"
#endif
#endif /* __BLKTAP2_UUID_H__ */

View File

@ -0,0 +1,250 @@
/* blktaplib.h
*
* Blktap library userspace code.
*
* Copyright (c) 2007, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __BLKTAPLIB_H__
#define __BLKTAPLIB_H__
#include <syslog.h>
#include <xenctrl.h>
#include <xen/io/blkif.h>
#if 1
#define DPRINTF(_f, _a...) syslog(LOG_INFO, _f, ##_a)
#else
#define DPRINTF(_f, _a...) ((void)0)
#endif
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
#define PERROR(_f, _a...) EPRINTF(_f ": %s", ##_a, strerror(errno))
#define BLK_RING_SIZE __CONST_RING_SIZE(blkif, XC_PAGE_SIZE)
/* size of the extra VMA area to map in attached pages. */
#define BLKTAP_VMA_PAGES BLK_RING_SIZE
/* blktap IOCTLs: These must correspond with the blktap driver ioctls */
#define BLKTAP_IOCTL_KICK_FE 1
#define BLKTAP_IOCTL_KICK_BE 2
#define BLKTAP_IOCTL_SETMODE 3
#define BLKTAP_IOCTL_SENDPID 4
#define BLKTAP_IOCTL_NEWINTF 5
#define BLKTAP_IOCTL_MINOR 6
#define BLKTAP_IOCTL_MAJOR 7
#define BLKTAP_QUERY_ALLOC_REQS 8
#define BLKTAP_IOCTL_FREEINTF 9
#define BLKTAP_IOCTL_PRINT_IDXS 100
#define BLKTAP_IOCTL_BACKDEV_SETUP 200
#define PRIO_SPECIAL_IO -9999
/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE) */
#define BLKTAP_MODE_PASSTHROUGH 0x00000000 /* default */
#define BLKTAP_MODE_INTERCEPT_FE 0x00000001
#define BLKTAP_MODE_INTERCEPT_BE 0x00000002
#define BLKTAP_MODE_INTERPOSE \
(BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
static inline int BLKTAP_MODE_VALID(unsigned long arg)
{
return (
( arg == BLKTAP_MODE_PASSTHROUGH ) ||
( arg == BLKTAP_MODE_INTERCEPT_FE ) ||
( arg == BLKTAP_MODE_INTERPOSE ) );
}
#define MAX_REQUESTS BLK_RING_SIZE
#define BLKTAP_IOCTL_KICK 1
#define MAX_PENDING_REQS BLK_RING_SIZE
#define BLKTAP_DEV_DIR "/dev/xen"
#define BLKTAP_DEV_NAME "blktap"
#define BACKDEV_NAME "backdev"
#define BLKTAP_DEV_MINOR 0
#define BLKTAP_CTRL_DIR "/var/run/tap"
extern int blktap_major;
#define BLKTAP_RING_PAGES 1 /* Front */
#define BLKTAP_MMAP_REGION_SIZE (BLKTAP_RING_PAGES + MMAP_PAGES)
struct blkif;
struct blkif_info;
typedef struct {
blkif_request_t req;
int submitting;
int secs_pending;
int16_t status;
int num_retries;
struct timeval last_try;
} pending_req_t;
typedef struct blkif {
domid_t domid;
long int handle;
long int pdev;
long int readonly;
enum { DISCONNECTED, DISCONNECTING, CONNECTED } state;
struct blkif_ops *ops;
struct blkif *hash_next;
void *prv; /* device-specific data */
struct blkif_info *info; /*Image parameter passing */
pending_req_t pending_list[MAX_REQUESTS];
int devnum;
int fds[2];
int be_id;
char *backend_path;
int major;
int minor;
pid_t tappid;
int drivertype;
uint16_t cookie;
int err;
} blkif_t;
typedef struct blkif_info {
char *params;
int readonly;
int storage;
} blkif_info_t;
typedef struct tapdev_info {
int fd;
char *mem;
blkif_sring_t *sring;
blkif_back_ring_t fe_ring;
unsigned long vstart;
blkif_t *blkif;
} tapdev_info_t;
typedef struct domid_translate {
unsigned short domid;
unsigned short busid;
} domid_translate_t ;
typedef struct image {
unsigned long long size;
unsigned long secsize;
unsigned int info;
} image_t;
typedef struct msg_hdr {
uint16_t type;
uint16_t len;
uint16_t drivertype;
uint16_t cookie;
} msg_hdr_t;
typedef struct msg_params {
uint8_t readonly;
int path_off;
int path_len;
int storage;
} msg_params_t;
typedef struct msg_newdev {
uint8_t devnum;
uint16_t domid;
} msg_newdev_t;
typedef struct msg_pid {
pid_t pid;
} msg_pid_t;
typedef struct msg_cp {
int cp_uuid_off;
int cp_uuid_len;
int cp_drivertype;
} msg_cp_t;
typedef struct msg_lock {
int ro;
int enforce;
int uuid_off;
int uuid_len;
} msg_lock_t;
#define READ 0
#define WRITE 1
/*Control Messages between manager and tapdev*/
#define CTLMSG_PARAMS 1
#define CTLMSG_IMG 2
#define CTLMSG_IMG_FAIL 3
#define CTLMSG_NEWDEV 4
#define CTLMSG_NEWDEV_RSP 5
#define CTLMSG_NEWDEV_FAIL 6
#define CTLMSG_CLOSE 7
#define CTLMSG_CLOSE_RSP 8
#define CTLMSG_PID 9
#define CTLMSG_PID_RSP 10
#define CTLMSG_CHECKPOINT 11
#define CTLMSG_CHECKPOINT_RSP 12
#define CTLMSG_LOCK 13
#define CTLMSG_LOCK_RSP 14
#define CTLMSG_PAUSE 15
#define CTLMSG_PAUSE_RSP 16
#define CTLMSG_RESUME 17
#define CTLMSG_RESUME_RSP 18
#define TAPDISK_STORAGE_TYPE_NFS 1
#define TAPDISK_STORAGE_TYPE_EXT 2
#define TAPDISK_STORAGE_TYPE_LVM 3
#define TAPDISK_STORAGE_TYPE_DEFAULT TAPDISK_STORAGE_TYPE_EXT
/* Abitrary values, must match the underlying driver... */
#define MAX_TAP_DEV 256
/* Accessing attached data page mappings */
#define MMAP_PAGES \
(MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
#define MMAP_VADDR(_vstart,_req,_seg) \
((_vstart) + \
((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * getpagesize()) + \
((_seg) * getpagesize()))
/* Defines that are only used by library clients */
#ifndef __COMPILING_BLKTAP_LIB
static char *blkif_op_name[] = {
[BLKIF_OP_READ] = "READ",
[BLKIF_OP_WRITE] = "WRITE",
};
#endif /* __COMPILING_BLKTAP_LIB */
#endif /* __BLKTAPLIB_H__ */

View File

@ -0,0 +1,68 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VHD_JOURNAL_H_
#define _VHD_JOURNAL_H_
#include <inttypes.h>
#include "libvhd.h"
#define VHD_JOURNAL_METADATA 0x01
#define VHD_JOURNAL_DATA 0x02
#define VHD_JOURNAL_HEADER_COOKIE "vjournal"
#define VHD_JOURNAL_ENTRY_COOKIE 0xaaaa12344321aaaa
typedef struct vhd_journal_header {
char cookie[8];
blk_uuid_t uuid;
uint64_t vhd_footer_offset;
uint32_t journal_data_entries;
uint32_t journal_metadata_entries;
uint64_t journal_data_offset;
uint64_t journal_metadata_offset;
uint64_t journal_eof;
char pad[448];
} vhd_journal_header_t;
typedef struct vhd_journal {
char *jname;
int jfd;
int is_block; /* is jfd a block device */
vhd_journal_header_t header;
vhd_context_t vhd;
} vhd_journal_t;
int vhd_journal_create(vhd_journal_t *, const char *file, const char *jfile);
int vhd_journal_open(vhd_journal_t *, const char *file, const char *jfile);
int vhd_journal_add_block(vhd_journal_t *, uint32_t block, char mode);
int vhd_journal_commit(vhd_journal_t *);
int vhd_journal_revert(vhd_journal_t *);
int vhd_journal_close(vhd_journal_t *);
int vhd_journal_remove(vhd_journal_t *);
#endif

View File

@ -0,0 +1,326 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VHD_LIB_H_
#define _VHD_LIB_H_
#include <string.h>
#if defined(__linux__)
#include <endian.h>
#include <byteswap.h>
#elif defined(__NetBSD__)
#include <sys/endian.h>
#include <sys/bswap.h>
#endif
#include "blk_uuid.h"
#include "vhd.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
#if defined(__linux__)
#define BE16_IN(foo) (*(foo)) = bswap_16(*(foo))
#define BE32_IN(foo) (*(foo)) = bswap_32(*(foo))
#define BE64_IN(foo) (*(foo)) = bswap_64(*(foo))
#define BE16_OUT(foo) (*(foo)) = bswap_16(*(foo))
#define BE32_OUT(foo) (*(foo)) = bswap_32(*(foo))
#define BE64_OUT(foo) (*(foo)) = bswap_64(*(foo))
#elif defined(__NetBSD__)
#define BE16_IN(foo) (*(foo)) = bswap16(*(foo))
#define BE32_IN(foo) (*(foo)) = bswap32(*(foo))
#define BE64_IN(foo) (*(foo)) = bswap64(*(foo))
#define BE16_OUT(foo) (*(foo)) = bswap16(*(foo))
#define BE32_OUT(foo) (*(foo)) = bswap32(*(foo))
#define BE64_OUT(foo) (*(foo)) = bswap64(*(foo))
#endif
#else
#define BE16_IN(foo)
#define BE32_IN(foo)
#define BE64_IN(foo)
#define BE32_OUT(foo)
#define BE32_OUT(foo)
#define BE64_OUT(foo)
#endif
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define VHD_MAX_NAME_LEN 1024
#define VHD_BLOCK_SHIFT 21
#define VHD_BLOCK_SIZE (1ULL << VHD_BLOCK_SHIFT)
#define UTF_16 "UTF-16"
#define UTF_16LE "UTF-16LE"
#define UTF_16BE "UTF-16BE"
#define VHD_OPEN_RDONLY 0x00001
#define VHD_OPEN_RDWR 0x00002
#define VHD_OPEN_FAST 0x00004
#define VHD_OPEN_STRICT 0x00008
#define VHD_OPEN_IGNORE_DISABLED 0x00010
#define VHD_FLAG_CREAT_PARENT_RAW 0x00001
#define vhd_flag_set(word, flag) ((word) |= (flag))
#define vhd_flag_clear(word, flag) ((word) &= ~(flag))
#define vhd_flag_test(word, flag) ((word) & (flag))
#define ENABLE_FAILURE_TESTING
#define FAIL_REPARENT_BEGIN 0
#define FAIL_REPARENT_LOCATOR 1
#define FAIL_REPARENT_END 2
#define FAIL_RESIZE_BEGIN 3
#define FAIL_RESIZE_DATA_MOVED 4
#define FAIL_RESIZE_METADATA_MOVED 5
#define FAIL_RESIZE_END 6
#define NUM_FAIL_TESTS 7
#ifdef ENABLE_FAILURE_TESTING
#define TEST_FAIL_AT(point) \
if (TEST_FAIL[point]) { \
printf("Failing at %s\n", ENV_VAR_FAIL[point]); exit(EINVAL); }
#define TEST_FAIL_EXTERN_VARS \
extern const char* ENV_VAR_FAIL[]; \
extern int TEST_FAIL[];
#else
#define TEST_FAIL_AT(point)
#define TEST_FAIL_EXTERN_VARS
#endif // ENABLE_FAILURE_TESTING
static const char VHD_POISON_COOKIE[] = "v_poison";
typedef struct hd_ftr vhd_footer_t;
typedef struct dd_hdr vhd_header_t;
typedef struct vhd_bat vhd_bat_t;
typedef struct vhd_batmap vhd_batmap_t;
typedef struct dd_batmap_hdr vhd_batmap_header_t;
typedef struct prt_loc vhd_parent_locator_t;
typedef struct vhd_context vhd_context_t;
typedef uint32_t vhd_flag_creat_t;
struct vhd_bat {
uint32_t spb;
uint32_t entries;
uint32_t *bat;
};
struct vhd_batmap {
vhd_batmap_header_t header;
char *map;
};
struct vhd_context {
int fd;
char *file;
int oflags;
int is_block;
uint32_t spb;
uint32_t bm_secs;
vhd_header_t header;
vhd_footer_t footer;
vhd_bat_t bat;
vhd_batmap_t batmap;
};
static inline uint32_t
secs_round_up(uint64_t bytes)
{
return ((bytes + (VHD_SECTOR_SIZE - 1)) >> VHD_SECTOR_SHIFT);
}
static inline uint32_t
secs_round_up_no_zero(uint64_t bytes)
{
return (secs_round_up(bytes) ? : 1);
}
static inline uint64_t
vhd_sectors_to_bytes(uint64_t sectors)
{
return sectors << VHD_SECTOR_SHIFT;
}
static inline uint64_t
vhd_bytes_padded(uint64_t bytes)
{
return vhd_sectors_to_bytes(secs_round_up_no_zero(bytes));
}
static inline int
vhd_type_dynamic(vhd_context_t *ctx)
{
return (ctx->footer.type == HD_TYPE_DYNAMIC ||
ctx->footer.type == HD_TYPE_DIFF);
}
static inline int
vhd_creator_tapdisk(vhd_context_t *ctx)
{
return !strncmp(ctx->footer.crtr_app, "tap", 3);
}
static inline int
vhd_disabled(vhd_context_t *ctx)
{
return (!memcmp(ctx->footer.cookie,
VHD_POISON_COOKIE, sizeof(ctx->footer.cookie)));
}
static inline size_t
vhd_parent_locator_size(vhd_parent_locator_t *loc)
{
/*
* MICROSOFT_COMPAT
* data_space *should* be in sectors,
* but sometimes we find it in bytes
*/
if (loc->data_space < 512)
return vhd_sectors_to_bytes(loc->data_space);
else if (loc->data_space % 512 == 0)
return loc->data_space;
else
return 0;
}
static inline int
vhd_parent_raw(vhd_context_t *ctx)
{
return blk_uuid_is_nil(&ctx->header.prt_uuid);
}
void libvhd_set_log_level(int);
int vhd_test_file_fixed(const char *, int *);
uint32_t vhd_time(time_t time);
size_t vhd_time_to_string(uint32_t timestamp, char *target);
uint32_t vhd_chs(uint64_t size);
uint32_t vhd_checksum_footer(vhd_footer_t *);
uint32_t vhd_checksum_header(vhd_header_t *);
uint32_t vhd_checksum_batmap(vhd_batmap_t *);
void vhd_footer_in(vhd_footer_t *);
void vhd_footer_out(vhd_footer_t *);
void vhd_header_in(vhd_header_t *);
void vhd_header_out(vhd_header_t *);
void vhd_bat_in(vhd_bat_t *);
void vhd_bat_out(vhd_bat_t *);
void vhd_batmap_header_in(vhd_batmap_t *);
void vhd_batmap_header_out(vhd_batmap_t *);
int vhd_validate_footer(vhd_footer_t *footer);
int vhd_validate_header(vhd_header_t *header);
int vhd_validate_batmap_header(vhd_batmap_t *batmap);
int vhd_validate_batmap(vhd_batmap_t *batmap);
int vhd_validate_platform_code(uint32_t code);
int vhd_open(vhd_context_t *, const char *file, int flags);
void vhd_close(vhd_context_t *);
int vhd_create(const char *name, uint64_t bytes, int type, vhd_flag_creat_t);
/* vhd_snapshot: the bytes parameter is optional and can be 0 if the snapshot
* is to have the same size as the (first non-empty) parent */
int vhd_snapshot(const char *snapshot, uint64_t bytes, const char *parent,
vhd_flag_creat_t);
int vhd_hidden(vhd_context_t *, int *);
int vhd_chain_depth(vhd_context_t *, int *);
off_t vhd_position(vhd_context_t *);
int vhd_seek(vhd_context_t *, off_t, int);
int vhd_read(vhd_context_t *, void *, size_t);
int vhd_write(vhd_context_t *, void *, size_t);
int vhd_offset(vhd_context_t *, uint32_t, uint32_t *);
int vhd_end_of_headers(vhd_context_t *ctx, off_t *off);
int vhd_end_of_data(vhd_context_t *ctx, off_t *off);
int vhd_batmap_header_offset(vhd_context_t *ctx, off_t *off);
int vhd_get_header(vhd_context_t *);
int vhd_get_footer(vhd_context_t *);
int vhd_get_bat(vhd_context_t *);
int vhd_get_batmap(vhd_context_t *);
void vhd_put_header(vhd_context_t *);
void vhd_put_footer(vhd_context_t *);
void vhd_put_bat(vhd_context_t *);
void vhd_put_batmap(vhd_context_t *);
int vhd_has_batmap(vhd_context_t *);
int vhd_batmap_test(vhd_context_t *, vhd_batmap_t *, uint32_t);
void vhd_batmap_set(vhd_context_t *, vhd_batmap_t *, uint32_t);
void vhd_batmap_clear(vhd_context_t *, vhd_batmap_t *, uint32_t);
int vhd_get_phys_size(vhd_context_t *, off_t *);
int vhd_set_phys_size(vhd_context_t *, off_t);
int vhd_bitmap_test(vhd_context_t *, char *, uint32_t);
void vhd_bitmap_set(vhd_context_t *, char *, uint32_t);
void vhd_bitmap_clear(vhd_context_t *, char *, uint32_t);
int vhd_parent_locator_count(vhd_context_t *);
int vhd_parent_locator_get(vhd_context_t *, char **);
int vhd_parent_locator_read(vhd_context_t *, vhd_parent_locator_t *, char **);
int vhd_find_parent(vhd_context_t *, const char *, char **);
int vhd_parent_locator_write_at(vhd_context_t *, const char *,
off_t, uint32_t, size_t,
vhd_parent_locator_t *);
int vhd_header_decode_parent(vhd_context_t *, vhd_header_t *, char **);
int vhd_change_parent(vhd_context_t *, char *parent_path, int raw);
int vhd_read_footer(vhd_context_t *, vhd_footer_t *);
int vhd_read_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
int vhd_read_footer_strict(vhd_context_t *, vhd_footer_t *);
int vhd_read_header(vhd_context_t *, vhd_header_t *);
int vhd_read_header_at(vhd_context_t *, vhd_header_t *, off_t);
int vhd_read_bat(vhd_context_t *, vhd_bat_t *);
int vhd_read_batmap(vhd_context_t *, vhd_batmap_t *);
int vhd_read_bitmap(vhd_context_t *, uint32_t block, char **bufp);
int vhd_read_block(vhd_context_t *, uint32_t block, char **bufp);
int vhd_write_footer(vhd_context_t *, vhd_footer_t *);
int vhd_write_footer_at(vhd_context_t *, vhd_footer_t *, off_t);
int vhd_write_header(vhd_context_t *, vhd_header_t *);
int vhd_write_header_at(vhd_context_t *, vhd_header_t *, off_t);
int vhd_write_bat(vhd_context_t *, vhd_bat_t *);
int vhd_write_batmap(vhd_context_t *, vhd_batmap_t *);
int vhd_write_bitmap(vhd_context_t *, uint32_t block, char *bitmap);
int vhd_write_block(vhd_context_t *, uint32_t block, char *data);
int vhd_io_read(vhd_context_t *, char *, uint64_t, uint32_t);
int vhd_io_write(vhd_context_t *, char *, uint64_t, uint32_t);
#endif

View File

@ -0,0 +1,124 @@
/*
* list.h
*
* This is a subset of linux's list.h intended to be used in user-space.
* XXX The namespace conflicts with NetBSD's <sys/queue.h>
*
*/
#ifndef __LIST_H__
#define __LIST_H__
#define LIST_POISON1 ((void *) 0x00100100)
#define LIST_POISON2 ((void *) 0x00200200)
struct list_head {
struct list_head *next, *prev;
};
/* XXX workaround for conflicts. The list API should use its own
* namespace prefix, i.e. BLK_
*/
#ifdef LIST_HEAD_INIT
#undef LIST_HEAD_INIT
#endif
#ifndef LIST_HEAD
#undef LIST_HEAD
#endif
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
INIT_LIST_HEAD(entry);
}
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
static inline int list_is_last(const struct list_head *list,
const struct list_head *head)
{
return list->next == head;
}
static inline void __list_splice(struct list_head *list,
struct list_head *head)
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
struct list_head *at = head->next;
first->prev = head;
head->next = first;
last->next = at;
at->prev = last;
}
static inline void list_splice(struct list_head *list, struct list_head *head)
{
if (!list_empty(list))
__list_splice(list, head);
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
#endif /* __LIST_H__ */

View File

@ -0,0 +1,71 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _LVM_UTIL_H_
#define _LVM_UTIL_H_
#include <inttypes.h>
#define MAX_NAME_SIZE 256
#define LVM_SEG_TYPE_LINEAR 1
#define LVM_SEG_TYPE_UNKNOWN 2
struct lv_segment {
uint8_t type;
char device[MAX_NAME_SIZE];
uint64_t pe_start;
uint64_t pe_size;
};
struct lv {
char name[MAX_NAME_SIZE];
uint64_t size;
uint32_t segments;
struct lv_segment first_segment;
};
struct pv {
char name[MAX_NAME_SIZE];
uint64_t start;
};
struct vg {
char name[MAX_NAME_SIZE];
uint64_t extent_size;
int pv_cnt;
struct pv *pvs;
int lv_cnt;
struct lv *lvs;
};
int lvm_scan_vg(const char *vg_name, struct vg *vg);
void lvm_free_vg(struct vg *vg);
#endif

View File

@ -0,0 +1,43 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _RELATIVE_PATH_H_
#define _RELATIVE_PATH_H_
#include <syslog.h>
#define DELIMITER '/'
#define MAX_NAME_LEN 1000
#define EPRINTF(_f, _a...) syslog(LOG_ERR, "tap-err:%s: " _f, __func__, ##_a)
/*
* returns a relative path from @src to @dest
* result should be freed
*/
char *relative_path_to(char *src, char *dest, int *err);
#endif

View File

@ -0,0 +1,141 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _TAPDISK_MESSAGE_H_
#define _TAPDISK_MESSAGE_H_
#include <inttypes.h>
#define TAPDISK_MESSAGE_MAX_PATH_LENGTH 256
#define TAPDISK_MESSAGE_STRING_LENGTH 256
#define TAPDISK_MESSAGE_FLAG_SHARED 0x01
#define TAPDISK_MESSAGE_FLAG_RDONLY 0x02
#define TAPDISK_MESSAGE_FLAG_ADD_CACHE 0x04
#define TAPDISK_MESSAGE_FLAG_VHD_INDEX 0x08
#define TAPDISK_MESSAGE_FLAG_LOG_DIRTY 0x10
typedef struct tapdisk_message tapdisk_message_t;
typedef uint8_t tapdisk_message_flag_t;
typedef struct tapdisk_message_image tapdisk_message_image_t;
typedef struct tapdisk_message_params tapdisk_message_params_t;
typedef struct tapdisk_message_string tapdisk_message_string_t;
struct tapdisk_message_params {
tapdisk_message_flag_t flags;
uint8_t storage;
uint32_t devnum;
uint32_t domid;
uint16_t path_len;
char path[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
};
struct tapdisk_message_image {
uint64_t sectors;
uint32_t sector_size;
uint32_t info;
};
struct tapdisk_message_string {
char text[TAPDISK_MESSAGE_STRING_LENGTH];
};
struct tapdisk_message {
uint16_t type;
uint16_t cookie;
uint16_t drivertype;
union {
pid_t tapdisk_pid;
tapdisk_message_image_t image;
tapdisk_message_params_t params;
tapdisk_message_string_t string;
} u;
};
enum tapdisk_message_id {
TAPDISK_MESSAGE_ERROR = 1,
TAPDISK_MESSAGE_RUNTIME_ERROR,
TAPDISK_MESSAGE_PID,
TAPDISK_MESSAGE_PID_RSP,
TAPDISK_MESSAGE_OPEN,
TAPDISK_MESSAGE_OPEN_RSP,
TAPDISK_MESSAGE_PAUSE,
TAPDISK_MESSAGE_PAUSE_RSP,
TAPDISK_MESSAGE_RESUME,
TAPDISK_MESSAGE_RESUME_RSP,
TAPDISK_MESSAGE_CLOSE,
TAPDISK_MESSAGE_CLOSE_RSP,
TAPDISK_MESSAGE_EXIT,
};
static inline char *
tapdisk_message_name(enum tapdisk_message_id id)
{
switch (id) {
case TAPDISK_MESSAGE_ERROR:
return "error";
case TAPDISK_MESSAGE_PID:
return "pid";
case TAPDISK_MESSAGE_PID_RSP:
return "pid response";
case TAPDISK_MESSAGE_OPEN:
return "open";
case TAPDISK_MESSAGE_OPEN_RSP:
return "open response";
case TAPDISK_MESSAGE_PAUSE:
return "pause";
case TAPDISK_MESSAGE_PAUSE_RSP:
return "pause response";
case TAPDISK_MESSAGE_RESUME:
return "resume";
case TAPDISK_MESSAGE_RESUME_RSP:
return "resume response";
case TAPDISK_MESSAGE_CLOSE:
return "close";
case TAPDISK_MESSAGE_CLOSE_RSP:
return "close response";
case TAPDISK_MESSAGE_EXIT:
return "exit";
default:
return "unknown";
}
}
#endif

View File

@ -0,0 +1,44 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _VHD_UTIL_H_
#define _VHD_UTIL_H_
int vhd_util_create(int argc, char **argv);
int vhd_util_snapshot(int argc, char **argv);
int vhd_util_query(int argc, char **argv);
int vhd_util_read(int argc, char **argv);
int vhd_util_set_field(int argc, char **argv);
int vhd_util_repair(int argc, char **argv);
int vhd_util_fill(int argc, char **argv);
int vhd_util_resize(int argc, char **argv);
int vhd_util_coalesce(int argc, char **argv);
int vhd_util_modify(int argc, char **argv);
int vhd_util_scan(int argc, char **argv);
int vhd_util_check(int argc, char **argv);
int vhd_util_revert(int argc, char **argv);
#endif

View File

@ -0,0 +1,219 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __VHD_H__
#define __VHD_H__
#include <inttypes.h>
typedef uint32_t u32;
typedef uint64_t u64;
#define DEBUG 1
/* ---------------------------------------------------------------------- */
/* General definitions. */
/* ---------------------------------------------------------------------- */
#define VHD_SECTOR_SIZE 512
#define VHD_SECTOR_SHIFT 9
/* ---------------------------------------------------------------------- */
/* This is the generic disk footer, used by all disks. */
/* ---------------------------------------------------------------------- */
struct hd_ftr {
char cookie[8]; /* Identifies original creator of the disk */
u32 features; /* Feature Support -- see below */
u32 ff_version; /* (major,minor) version of disk file */
u64 data_offset; /* Abs. offset from SOF to next structure */
u32 timestamp; /* Creation time. secs since 1/1/2000GMT */
char crtr_app[4]; /* Creator application */
u32 crtr_ver; /* Creator version (major,minor) */
u32 crtr_os; /* Creator host OS */
u64 orig_size; /* Size at creation (bytes) */
u64 curr_size; /* Current size of disk (bytes) */
u32 geometry; /* Disk geometry */
u32 type; /* Disk type */
u32 checksum; /* 1's comp sum of this struct. */
blk_uuid_t uuid; /* Unique disk ID, used for naming parents */
char saved; /* one-bit -- is this disk/VM in a saved state? */
char hidden; /* tapdisk-specific field: is this vdi hidden? */
char reserved[426]; /* padding */
};
/* VHD cookie string. */
static const char HD_COOKIE[9] = "conectix";
/* Feature fields in hd_ftr */
#define HD_NO_FEATURES 0x00000000
#define HD_TEMPORARY 0x00000001 /* disk can be deleted on shutdown */
#define HD_RESERVED 0x00000002 /* NOTE: must always be set */
/* Version field in hd_ftr */
#define HD_FF_VERSION 0x00010000
/* Known creator OS type fields in hd_ftr.crtr_os */
#define HD_CR_OS_WINDOWS 0x5769326B /* (Wi2k) */
#define HD_CR_OS_MACINTOSH 0x4D616320 /* (Mac ) */
/*
* version 0.1: little endian bitmaps
* version 1.1: big endian bitmaps; batmap
* version 1.2: libvhd
* version 1.3: batmap version bump to 1.2
*/
#define VHD_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF))
#define VHD_CURRENT_VERSION VHD_VERSION(1, 3)
/* Disk geometry accessor macros. */
/* Geometry is a triple of (cylinders (2 bytes), tracks (1 byte), and
* secotrs-per-track (1 byte))
*/
#define GEOM_GET_CYLS(_g) (((_g) >> 16) & 0xffff)
#define GEOM_GET_HEADS(_g) (((_g) >> 8) & 0xff)
#define GEOM_GET_SPT(_g) ((_g) & 0xff)
#define GEOM_ENCODE(_c, _h, _s) (((_c) << 16) | ((_h) << 8) | (_s))
/* type field in hd_ftr */
#define HD_TYPE_NONE 0
#define HD_TYPE_FIXED 2 /* fixed-allocation disk */
#define HD_TYPE_DYNAMIC 3 /* dynamic disk */
#define HD_TYPE_DIFF 4 /* differencing disk */
/* String table for hd.type */
static const char *HD_TYPE_STR[7] = {
"None", /* 0 */
"Reserved (deprecated)", /* 1 */
"Fixed hard disk", /* 2 */
"Dynamic hard disk", /* 3 */
"Differencing hard disk", /* 4 */
"Reserved (deprecated)", /* 5 */
"Reserved (deprecated)" /* 6 */
};
#define HD_TYPE_MAX 6
struct prt_loc {
u32 code; /* Platform code -- see defines below. */
u32 data_space; /* Number of 512-byte sectors to store locator */
u32 data_len; /* Actual length of parent locator in bytes */
u32 res; /* Must be zero */
u64 data_offset; /* Absolute offset of locator data (bytes) */
};
/* Platform Codes */
#define PLAT_CODE_NONE 0x0
#define PLAT_CODE_WI2R 0x57693272 /* deprecated */
#define PLAT_CODE_WI2K 0x5769326B /* deprecated */
#define PLAT_CODE_W2RU 0x57327275 /* Windows relative path (UTF-16) */
#define PLAT_CODE_W2KU 0x57326B75 /* Windows absolute path (UTF-16) */
#define PLAT_CODE_MAC 0x4D616320 /* MacOS alias stored as a blob. */
#define PLAT_CODE_MACX 0x4D616358 /* File URL (UTF-8), see RFC 2396. */
/* ---------------------------------------------------------------------- */
/* This is the dynamic disk header. */
/* ---------------------------------------------------------------------- */
struct dd_hdr {
char cookie[8]; /* Should contain "cxsparse" */
u64 data_offset; /* Byte offset of next record. (Unused) 0xffs */
u64 table_offset; /* Absolute offset to the BAT. */
u32 hdr_ver; /* Version of the dd_hdr (major,minor) */
u32 max_bat_size; /* Maximum number of entries in the BAT */
u32 block_size; /* Block size in bytes. Must be power of 2. */
u32 checksum; /* Header checksum. 1's comp of all fields. */
blk_uuid_t prt_uuid; /* ID of the parent disk. */
u32 prt_ts; /* Modification time of the parent disk */
u32 res1; /* Reserved. */
char prt_name[512]; /* Parent unicode name. */
struct prt_loc loc[8]; /* Parent locator entries. */
char res2[256]; /* Reserved. */
};
/* VHD cookie string. */
static const char DD_COOKIE[9] = "cxsparse";
/* Version field in hd_ftr */
#define DD_VERSION 0x00010000
/* Default blocksize is 2 meg. */
#define DD_BLOCKSIZE_DEFAULT 0x00200000
#define DD_BLK_UNUSED 0xFFFFFFFF
struct dd_batmap_hdr {
char cookie[8]; /* should contain "tdbatmap" */
u64 batmap_offset; /* byte offset to batmap */
u32 batmap_size; /* batmap size in sectors */
u32 batmap_version; /* version of batmap */
u32 checksum; /* batmap checksum -- 1's complement of batmap */
};
static const char VHD_BATMAP_COOKIE[9] = "tdbatmap";
/*
* version 1.1: signed char checksum
*/
#define VHD_BATMAP_VERSION(major, minor) (((major) << 16) | ((minor) & 0x0000FFFF))
#define VHD_BATMAP_CURRENT_VERSION VHD_BATMAP_VERSION(1, 2)
/* Layout of a dynamic disk:
*
* +-------------------------------------------------+
* | Mirror image of HD footer (hd_ftr) (512 bytes) |
* +-------------------------------------------------+
* | Sparse drive header (dd_hdr) (1024 bytes) |
* +-------------------------------------------------+
* | BAT (Block allocation table) |
* | - Array of absolute sector offsets into the |
* | file (u32). |
* | - Rounded up to a sector boundary. |
* | - Unused entries are marked as 0xFFFFFFFF |
* | - max entries in dd_hdr->max_bat_size |
* +-------------------------------------------------+
* | Data Block 0 |
* | Bitmap (padded to 512 byte sector boundary) |
* | - each bit indicates whether the associated |
* | sector within this block is used. |
* | Data |
* | - power-of-two multiple of sectors. |
* | - default 2MB (4096 * 512) |
* | - Any entries with zero in bitmap should be |
* | zero on disk |
* +-------------------------------------------------+
* | Data Block 1 |
* +-------------------------------------------------+
* | ... |
* +-------------------------------------------------+
* | Data Block n |
* +-------------------------------------------------+
* | HD Footer (511 bytes) |
* +-------------------------------------------------+
*/
#endif

View File

@ -0,0 +1,38 @@
XEN_ROOT = ../../..
BLKTAP_ROOT := ..
include $(XEN_ROOT)/tools/Rules.mk
ifeq ($(LVM_UTIL_TEST),y)
TEST := lvm-util
endif
CFLAGS += -Werror
CFLAGS += -Wno-unused
CFLAGS += -I../include
CFLAGS += -D_GNU_SOURCE
ifeq ($(CONFIG_X86_64),y)
CFLAGS += -fPIC
endif
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,.$(@F).d
DEPS = .*.d
LVM-OBJS := lvm-util.o
all: build
build: $(TEST) $(LVM-OBJS)
install: all
lvm-util: lvm-util.o
$(CC) $(CFLAGS) -DLVM_UTIL $(LDFLAGS) -o lvm-util lvm-util.c
clean:
rm -rf *.o *~ $(DEPS) $(IBIN)
.PHONY: all build clean install lvm-util
-include $(DEPS)

View File

@ -0,0 +1,349 @@
/*
* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "lvm-util.h"
#define _NAME "%255s"
static char line[1024];
static inline int
lvm_read_line(FILE *scan)
{
memset(line, 0, sizeof(line));
return (fscanf(scan, "%1023[^\n]", line) != 1);
}
static inline int
lvm_next_line(FILE *scan)
{
return (fscanf(scan, "%1023[\n]", line) != 1);
}
static int
lvm_copy_name(char *dst, const char *src, size_t size)
{
if (strnlen(src, size) == size)
return -ENAMETOOLONG;
strcpy(dst, src);
return 0;
}
static int
lvm_parse_pv(struct vg *vg, const char *name, int pvs, uint64_t start)
{
int i, err;
struct pv *pv;
pv = NULL;
if (!vg->pvs) {
vg->pvs = calloc(pvs, sizeof(struct pv));
if (!vg->pvs)
return -ENOMEM;
}
for (i = 0; i < pvs; i++) {
pv = vg->pvs + i;
if (!pv->name[0])
break;
if (!strcmp(pv->name, name))
return -EEXIST;
}
if (!pv)
return -ENOENT;
if (i == pvs)
return -ENOMEM;
err = lvm_copy_name(pv->name, name, sizeof(pv->name) - 1);
if (err)
return err;
pv->start = start;
return 0;
}
static int
lvm_open_vg(const char *vgname, struct vg *vg)
{
FILE *scan;
int i, err, pvs, lvs;
char *cmd, pvname[256];
uint64_t size, pv_start;
memset(vg, 0, sizeof(*vg));
err = asprintf(&cmd, "/usr/sbin/vgs %s --noheadings --nosuffix --units=b "
"--options=vg_name,vg_extent_size,lv_count,pv_count,"
"pv_name,pe_start --unbuffered 2> /dev/null", vgname);
if (err == -1)
return -ENOMEM;
errno = 0;
scan = popen(cmd, "r");
if (!scan) {
err = (errno ? -errno : ENOMEM);
goto out;
}
for (;;) {
if (lvm_read_line(scan))
break;
err = -EINVAL;
if (sscanf(line, _NAME" %"SCNu64" %d %d "_NAME" %"SCNu64,
vg->name, &size, &lvs, &pvs, pvname, &pv_start) != 6)
goto out;
if (strcmp(vg->name, vgname))
goto out;
err = lvm_parse_pv(vg, pvname, pvs, pv_start);
if (err)
goto out;
if (lvm_next_line(scan))
break;
}
err = -EINVAL;
if (strcmp(vg->name, vgname))
goto out;
for (i = 0; i < pvs; i++)
if (!vg->pvs[i].name[0])
goto out;
err = -ENOMEM;
vg->lvs = calloc(lvs, sizeof(struct lv));
if (!vg->lvs)
goto out;
err = 0;
vg->lv_cnt = lvs;
vg->pv_cnt = pvs;
vg->extent_size = size;
out:
if (scan)
pclose(scan);
if (err)
lvm_free_vg(vg);
free(cmd);
return err;
}
static int
lvm_parse_lv_devices(struct vg *vg, struct lv_segment *seg, char *devices)
{
int i;
uint64_t start, pe_start;
for (i = 0; i < strlen(devices); i++)
if (strchr(",()", devices[i]))
devices[i] = ' ';
if (sscanf(devices, _NAME" %"SCNu64, seg->device, &start) != 2)
return -EINVAL;
pe_start = -1;
for (i = 0; i < vg->pv_cnt; i++)
if (!strcmp(vg->pvs[i].name, seg->device)) {
pe_start = vg->pvs[i].start;
break;
}
if (pe_start == -1)
return -EINVAL;
seg->pe_start = (start * vg->extent_size) + pe_start;
return 0;
}
static int
lvm_scan_lvs(struct vg *vg)
{
char *cmd;
FILE *scan;
int i, err;
err = asprintf(&cmd, "/usr/sbin/lvs %s --noheadings --nosuffix --units=b "
"--options=lv_name,lv_size,segtype,seg_count,seg_start,"
"seg_size,devices --unbuffered 2> /dev/null", vg->name);
if (err == -1)
return -ENOMEM;
errno = 0;
scan = popen(cmd, "r");
if (!scan) {
err = (errno ? -errno : -ENOMEM);
goto out;
}
for (i = 0;;) {
int segs;
struct lv *lv;
struct lv_segment seg;
uint64_t size, seg_start;
char type[32], name[256], dev[256], devices[1024];
if (i >= vg->lv_cnt)
break;
if (lvm_read_line(scan)) {
vg->lv_cnt = i;
break;
}
err = -EINVAL;
lv = vg->lvs + i;
if (sscanf(line, _NAME" %"SCNu64" %31s %u %"SCNu64" %"SCNu64" %1023s",
name, &size, type, &segs, &seg_start,
&seg.pe_size, devices) != 7)
goto out;
if (seg_start)
goto next;
if (!strcmp(type, "linear"))
seg.type = LVM_SEG_TYPE_LINEAR;
else
seg.type = LVM_SEG_TYPE_UNKNOWN;
if (lvm_parse_lv_devices(vg, &seg, devices))
goto out;
i++;
lv->size = size;
lv->segments = segs;
lv->first_segment = seg;
err = lvm_copy_name(lv->name, name, sizeof(lv->name) - 1);
if (err)
goto out;
err = -EINVAL;
next:
if (lvm_next_line(scan))
goto out;
}
err = 0;
out:
if (scan)
pclose(scan);
free(cmd);
return err;
}
void
lvm_free_vg(struct vg *vg)
{
free(vg->lvs);
free(vg->pvs);
memset(vg, 0, sizeof(*vg));
}
int
lvm_scan_vg(const char *vg_name, struct vg *vg)
{
int err;
memset(vg, 0, sizeof(*vg));
err = lvm_open_vg(vg_name, vg);
if (err)
return err;
err = lvm_scan_lvs(vg);
if (err) {
lvm_free_vg(vg);
return err;
}
return 0;
}
#ifdef LVM_UTIL
static int
usage(void)
{
printf("usage: lvm-util <vgname>\n");
exit(EINVAL);
}
int
main(int argc, char **argv)
{
int i, err;
struct vg vg;
struct pv *pv;
struct lv *lv;
struct lv_segment *seg;
if (argc != 2)
usage();
err = lvm_scan_vg(argv[1], &vg);
if (err) {
printf("scan failed: %d\n", err);
return (err >= 0 ? err : -err);
}
printf("vg %s: extent_size: %"PRIu64", pvs: %d, lvs: %d\n",
vg.name, vg.extent_size, vg.pv_cnt, vg.lv_cnt);
for (i = 0; i < vg.pv_cnt; i++) {
pv = vg.pvs + i;
printf("pv %s: start %"PRIu64"\n", pv->name, pv->start);
}
for (i = 0; i < vg.lv_cnt; i++) {
lv = vg.lvs + i;
seg = &lv->first_segment;
printf("lv %s: size: %"PRIu64", segments: %u, type: %u, "
"dev: %s, pe_start: %"PRIu64", pe_size: %"PRIu64"\n",
lv->name, lv->size, lv->segments, seg->type,
seg->device, seg->pe_start, seg->pe_size);
}
lvm_free_vg(&vg);
return 0;
}
#endif

View File

@ -0,0 +1,56 @@
XEN_ROOT=../../..
BLKTAP_ROOT := ..
include $(XEN_ROOT)/tools/Rules.mk
SUBDIRS-y :=
SUBDIRS-y += lib
IBIN = vhd-util vhd-update
INST_DIR = $(SBINDIR)
CFLAGS += -Werror
CFLAGS += -Wno-unused
CFLAGS += -I../include
CFLAGS += -D_GNU_SOURCE
ifeq ($(CONFIG_X86_64),y)
CFLAGS += -fPIC
endif
ifeq ($(VHD_STATIC),y)
CFLAGS += -static
endif
LIBS := -Llib -lvhd
ifeq ($(CONFIG_Linux),y)
LIBS += -luuid
endif
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,.$(@F).d
DEPS = .*.d
all: subdirs-all build
build: $(IBIN)
LIBS_DEPENDS := lib/libvhd.so lib/vhd.a
$(LIBS_DEPENDS):subdirs-all
vhd-util: vhd-util.o $(LIBS_DEPENDS)
$(CC) $(CFLAGS) -o vhd-util vhd-util.o $(LDFLAGS) $(LIBS)
vhd-update: vhd-update.o $(LIBS_DEPENDS)
$(CC) $(CFLAGS) -o vhd-update vhd-update.o $(LDFLAGS) $(LIBS)
install: all
$(MAKE) subdirs-install
$(INSTALL_DIR) -p $(DESTDIR)$(INST_DIR)
$(INSTALL_PROG) $(IBIN) $(DESTDIR)$(INST_DIR)
clean: subdirs-clean
rm -rf *.o *~ $(DEPS) $(IBIN)
.PHONY: all build clean install vhd-util vhd-update
-include $(DEPS)

View File

@ -0,0 +1,75 @@
XEN_ROOT=../../../..
BLKTAP_ROOT := ../..
include $(XEN_ROOT)/tools/Rules.mk
LIBVHD-MAJOR = 1.0
LIBVHD-MINOR = 0
LIBVHD-SONAME = libvhd.so.$(LIBVHD-MAJOR)
LVM-UTIL-OBJ := $(BLKTAP_ROOT)/lvm/lvm-util.o
LIBVHD-BUILD := libvhd.a
INST-DIR = $(LIBDIR)
CFLAGS += -Werror
CFLAGS += -Wno-unused
CFLAGS += -I../../include
CFLAGS += -D_GNU_SOURCE
CFLAGS += -fPIC
CFLAGS += -g
ifeq ($(CONFIG_Linux),y)
LIBS := -luuid
endif
# Get gcc to generate the dependencies for us.
CFLAGS += -Wp,-MD,.$(@F).d
DEPS = .*.d
LIB-SRCS := libvhd.c
LIB-SRCS += libvhd-journal.c
LIB-SRCS += vhd-util-coalesce.c
LIB-SRCS += vhd-util-create.c
LIB-SRCS += vhd-util-fill.c
LIB-SRCS += vhd-util-modify.c
LIB-SRCS += vhd-util-query.c
LIB-SRCS += vhd-util-read.c
LIB-SRCS += vhd-util-repair.c
LIB-SRCS += vhd-util-resize.c
LIB-SRCS += vhd-util-revert.c
LIB-SRCS += vhd-util-set-field.c
LIB-SRCS += vhd-util-snapshot.c
LIB-SRCS += vhd-util-scan.c
LIB-SRCS += vhd-util-check.c
LIB-SRCS += relative-path.c
LIB-SRCS += atomicio.c
LIB-OBJS = $(patsubst %.c,%.o,$(LIB-SRCS))
LIB-OBJS += $(LVM-UTIL-OBJ)
LIBVHD = libvhd.a libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR)
all: build
build: $(LIBVHD-BUILD)
libvhd.a: $(LIB-OBJS)
$(CC) $(CFLAGS) -Wl,$(SONAME_LDFLAG),$(LIBVHD-SONAME) $(SHLIB_CFLAGS) \
$(LDFLAGS) -o libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR) $(LIBS) $^
ln -sf libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR) libvhd.so.$(LIBVHD-MAJOR)
ln -sf libvhd.so.$(LIBVHD-MAJOR) libvhd.so
$(AR) rc $@ $^
install: all
$(INSTALL_DIR) -p $(DESTDIR)$(INST-DIR)
$(INSTALL_DATA) $(LIBVHD) $(DESTDIR)$(INST-DIR)
ln -sf libvhd.so.$(LIBVHD-MAJOR).$(LIBVHD-MINOR) $(DESTDIR)$(INST-DIR)/libvhd.so.$(LIBVHD-MAJOR)
ln -sf libvhd.so.$(LIBVHD-MAJOR) $(DESTDIR)$(INST-DIR)/libvhd.so
clean:
rm -rf *.a *.so* *.o *~ $(DEPS) $(LIBVHD)
.PHONY: all build clean install libvhd
-include $(DEPS)

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) 2005 Anil Madhavapeddy. All rights reserved.
* Copyright (c) 1995,1999 Theo de Raadt. All rights reserved.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <errno.h>
#include "atomicio.h"
/*
* ensure all of data on socket comes through. f==read || f==vwrite
*/
size_t
atomicio(f, fd, _s, n)
ssize_t (*f) (int, void *, size_t);
int fd;
void *_s;
size_t n;
{
char *s = _s;
size_t pos = 0;
ssize_t res;
while (n > pos) {
res = (f) (fd, s + pos, n - pos);
switch (res) {
case -1:
if (errno == EINTR || errno == EAGAIN)
continue;
return 0;
case 0:
errno = EPIPE;
return pos;
default:
pos += (size_t)res;
}
}
return (pos);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,299 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "relative-path.h"
#define sfree(ptr) \
do { \
free(ptr); \
ptr = NULL; \
} while (0)
/*
* count number of tokens between DELIMETER characters
*/
static int
count_nodes(char *path)
{
int i;
char *tmp;
if (!path)
return 0;
for (i = 0, tmp = path; *tmp != '\0'; tmp++)
if (*tmp == DELIMITER)
i++;
return i;
}
/*
* return copy of next node in @path, or NULL
* @path is moved to the end of the next node
* @err is set to -errno on failure
* copy should be freed
*/
static char *
next_node(char **path, int *err)
{
int ret;
char *tmp, *start;
if (!path || !*path) {
*err = -EINVAL;
return NULL;
}
*err = 0;
start = *path;
for (tmp = *path; *tmp != '\0'; tmp++)
if (*tmp == DELIMITER) {
int size;
char *node;
size = tmp - start + 1;
node = malloc(size);
if (!node) {
*err = -ENOMEM;
return NULL;
}
ret = snprintf(node, size, "%s", start);
if (ret < 0) {
free(node);
*err = -EINVAL;
return NULL;
}
*path = tmp;
return node;
}
return NULL;
}
/*
* count number of nodes in common betwee @to and @from
* returns number of common nodes, or -errno on failure
*/
static int
count_common_nodes(char *to, char *from)
{
int err, common;
char *to_node, *from_node;
if (!to || !from)
return -EINVAL;
err = 0;
common = 0;
to_node = NULL;
from_node = NULL;
do {
to_node = next_node(&to, &err);
if (err || !to_node)
break;
from_node = next_node(&from, &err);
if (err || !from_node)
break;
if (strncmp(to_node, from_node, MAX_NAME_LEN))
break;
++to;
++from;
++common;
sfree(to_node);
sfree(from_node);
} while (1);
sfree(to_node);
sfree(from_node);
if (err)
return err;
return common;
}
/*
* construct path of @count '../', './' if @count is zero, or NULL on error
* result should be freed
*/
static char *
up_nodes(int count)
{
char *path, *tmp;
int i, ret, len, size;
if (!count)
return strdup("./");
len = strlen("../");
size = len * count;
if (size >= MAX_NAME_LEN)
return NULL;
path = malloc(size + 1);
if (!path)
return NULL;
tmp = path;
for (i = 0; i < count; i++) {
ret = sprintf(tmp, "../");
if (ret < 0 || ret != len) {
free(path);
return NULL;
}
tmp += ret;
}
return path;
}
/*
* return pointer to @offset'th node of path or NULL on error
*/
static char *
node_offset(char *from, int offset)
{
char *path;
if (!from || !offset)
return NULL;
for (path = from; *path != '\0'; path++) {
if (*path == DELIMITER)
if (--offset == 0)
return path + 1;
}
return NULL;
}
/*
* return a relative path from @from to @to
* result should be freed
*/
char *
relative_path_to(char *from, char *to, int *err)
{
int from_nodes, common;
char *to_absolute, *from_absolute;
char *up, *common_target_path, *relative_path;
*err = 0;
up = NULL;
to_absolute = NULL;
from_absolute = NULL;
relative_path = NULL;
if (strnlen(to, MAX_NAME_LEN) == MAX_NAME_LEN ||
strnlen(from, MAX_NAME_LEN) == MAX_NAME_LEN) {
EPRINTF("invalid input; max path length is %d\n",
MAX_NAME_LEN);
*err = -ENAMETOOLONG;
return NULL;
}
to_absolute = realpath(to, NULL);
if (!to_absolute) {
EPRINTF("failed to get absolute path of %s\n", to);
*err = -errno;
goto out;
}
from_absolute = realpath(from, NULL);
if (!from_absolute) {
EPRINTF("failed to get absolute path of %s\n", from);
*err = -errno;
goto out;
}
if (strnlen(to_absolute, MAX_NAME_LEN) == MAX_NAME_LEN ||
strnlen(from_absolute, MAX_NAME_LEN) == MAX_NAME_LEN) {
EPRINTF("invalid input; max path length is %d\n",
MAX_NAME_LEN);
*err = -ENAMETOOLONG;
goto out;
}
/* count nodes in source path */
from_nodes = count_nodes(from_absolute);
/* count nodes in common */
common = count_common_nodes(to_absolute + 1, from_absolute + 1);
if (common < 0) {
EPRINTF("failed to count common nodes of %s and %s: %d\n",
to_absolute, from_absolute, common);
*err = common;
goto out;
}
/* move up to common node */
up = up_nodes(from_nodes - common - 1);
if (!up) {
EPRINTF("failed to allocate relative path for %s: %d\n",
from_absolute, -ENOMEM);
*err = -ENOMEM;
goto out;
}
/* get path from common node to target */
common_target_path = node_offset(to_absolute, common + 1);
if (!common_target_path) {
EPRINTF("failed to find common target path to %s: %d\n",
to_absolute, -EINVAL);
*err = -EINVAL;
goto out;
}
/* get relative path */
if (asprintf(&relative_path, "%s%s", up, common_target_path) == -1) {
EPRINTF("failed to construct final path %s%s: %d\n",
up, common_target_path, -ENOMEM);
relative_path = NULL;
*err = -ENOMEM;
goto out;
}
out:
sfree(up);
sfree(to_absolute);
sfree(from_absolute);
return relative_path;
}

View File

@ -0,0 +1,980 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <libgen.h>
#include <inttypes.h>
#include <sys/stat.h>
#include "libvhd.h"
#include "vhd-util.h"
// allow the VHD timestamp to be at most this many seconds into the future to
// account for time skew with NFS servers
#define TIMESTAMP_MAX_SLACK 1800
static int
vhd_util_check_zeros(void *buf, size_t size)
{
int i;
char *p;
p = buf;
for (i = 0; i < size; i++)
if (p[i])
return i;
return 0;
}
static int
vhd_util_check_footer_opened(vhd_footer_t *footer)
{
int i, n;
uint32_t *buf;
buf = (uint32_t *)footer;
n = sizeof(*footer) / sizeof(uint32_t);
for (i = 0; i < n; i++)
if (buf[i] != 0xc7c7c7c7)
return 0;
return 1;
}
static char *
vhd_util_check_validate_footer(vhd_footer_t *footer)
{
int size;
uint32_t checksum, now;
size = sizeof(footer->cookie);
if (memcmp(footer->cookie, HD_COOKIE, size))
return "invalid cookie";
checksum = vhd_checksum_footer(footer);
if (checksum != footer->checksum) {
if (footer->hidden &&
!strncmp(footer->crtr_app, "tap", 3) &&
(footer->crtr_ver == VHD_VERSION(0, 1) ||
footer->crtr_ver == VHD_VERSION(1, 1))) {
char tmp = footer->hidden;
footer->hidden = 0;
checksum = vhd_checksum_footer(footer);
footer->hidden = tmp;
if (checksum == footer->checksum)
goto ok;
}
return "invalid checksum";
}
ok:
if (!(footer->features & HD_RESERVED))
return "invalid 'reserved' feature";
if (footer->features & ~(HD_TEMPORARY | HD_RESERVED))
return "invalid extra features";
if (footer->ff_version != HD_FF_VERSION)
return "invalid file format version";
if (footer->type != HD_TYPE_DYNAMIC &&
footer->type != HD_TYPE_DIFF &&
footer->data_offset != ~(0ULL))
return "invalid data offset";
now = vhd_time(time(NULL));
if (footer->timestamp > now + TIMESTAMP_MAX_SLACK)
return "creation time in future";
if (!strncmp(footer->crtr_app, "tap", 3) &&
footer->crtr_ver > VHD_CURRENT_VERSION)
return "unsupported tap creator version";
if (vhd_chs(footer->curr_size) < footer->geometry)
return "geometry too large";
if (footer->type != HD_TYPE_FIXED &&
footer->type != HD_TYPE_DYNAMIC &&
footer->type != HD_TYPE_DIFF)
return "invalid type";
if (footer->saved && footer->saved != 1)
return "invalid 'saved' state";
if (footer->hidden && footer->hidden != 1)
return "invalid 'hidden' state";
if (vhd_util_check_zeros(footer->reserved,
sizeof(footer->reserved)))
return "invalid 'reserved' bits";
return NULL;
}
static char *
vhd_util_check_validate_header(int fd, vhd_header_t *header)
{
off_t eof;
int i, cnt, size;
uint32_t checksum;
size = sizeof(header->cookie);
if (memcmp(header->cookie, DD_COOKIE, size))
return "invalid cookie";
checksum = vhd_checksum_header(header);
if (checksum != header->checksum)
return "invalid checksum";
if (header->hdr_ver != 0x00010000)
return "invalid header version";
if (header->data_offset != ~(0ULL))
return "invalid data offset";
eof = lseek(fd, 0, SEEK_END);
if (eof == (off_t)-1)
return "error finding eof";
if (header->table_offset <= 0 ||
header->table_offset % 512 ||
(header->table_offset +
(header->max_bat_size * sizeof(uint32_t)) >
eof - sizeof(vhd_footer_t)))
return "invalid table offset";
for (cnt = 0, i = 0; i < sizeof(header->block_size) * 8; i++)
if ((header->block_size >> i) & 1)
cnt++;
if (cnt != 1)
return "invalid block size";
if (header->res1)
return "invalid reserved bits";
if (vhd_util_check_zeros(header->res2, sizeof(header->res2)))
return "invalid reserved bits";
return NULL;
}
static char *
vhd_util_check_validate_differencing_header(vhd_context_t *vhd)
{
vhd_header_t *header;
header = &vhd->header;
if (vhd->footer.type == HD_TYPE_DIFF) {
char *parent;
uint32_t now;
now = vhd_time(time(NULL));
if (header->prt_ts > now + TIMESTAMP_MAX_SLACK)
return "parent creation time in future";
if (vhd_header_decode_parent(vhd, header, &parent))
return "invalid parent name";
free(parent);
} else {
if (vhd_util_check_zeros(header->prt_name,
sizeof(header->prt_name)))
return "invalid non-null parent name";
if (vhd_util_check_zeros(header->loc, sizeof(header->loc)))
return "invalid non-null parent locators";
if (!blk_uuid_is_nil(&header->prt_uuid))
return "invalid non-null parent uuid";
if (header->prt_ts)
return "invalid non-zero parent timestamp";
}
return NULL;
}
static char *
vhd_util_check_validate_batmap(vhd_context_t *vhd, vhd_batmap_t *batmap)
{
int size;
off_t eof;
uint32_t checksum;
size = sizeof(batmap->header.cookie);
if (memcmp(batmap->header.cookie, VHD_BATMAP_COOKIE, size))
return "invalid cookie";
if (batmap->header.batmap_version > VHD_BATMAP_CURRENT_VERSION)
return "unsupported batmap version";
checksum = vhd_checksum_batmap(batmap);
if (checksum != batmap->header.checksum)
return "invalid checksum";
if (!batmap->header.batmap_size)
return "invalid size zero";
eof = lseek(vhd->fd, 0, SEEK_END);
if (eof == (off_t)-1)
return "error finding eof";
if (!batmap->header.batmap_offset ||
batmap->header.batmap_offset % 512)
return "invalid batmap offset";
if ((batmap->header.batmap_offset +
vhd_sectors_to_bytes(batmap->header.batmap_size)) >
eof - sizeof(vhd_footer_t))
return "invalid batmap size";
return NULL;
}
static char *
vhd_util_check_validate_parent_locator(vhd_context_t *vhd,
vhd_parent_locator_t *loc)
{
off_t eof;
if (vhd_validate_platform_code(loc->code))
return "invalid platform code";
if (loc->code == PLAT_CODE_NONE) {
if (vhd_util_check_zeros(loc, sizeof(*loc)))
return "non-zero locator";
return NULL;
}
if (!loc->data_offset)
return "invalid data offset";
if (!loc->data_space)
return "invalid data space";
if (!loc->data_len)
return "invalid data length";
eof = lseek(vhd->fd, 0, SEEK_END);
if (eof == (off_t)-1)
return "error finding eof";
if (loc->data_offset + vhd_parent_locator_size(loc) >
eof - sizeof(vhd_footer_t))
return "invalid size";
if (loc->res)
return "invalid reserved bits";
return NULL;
}
static const char *
vhd_util_check_validate_parent(vhd_context_t *vhd, const char *ppath)
{
const char *msg;
vhd_context_t parent;
uint32_t status;
msg = NULL;
if (vhd_parent_raw(vhd))
return msg;
if (vhd_open(&parent, ppath,
VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED))
return "error opening parent";
if (blk_uuid_compare(&vhd->header.prt_uuid, &parent.footer.uuid)) {
msg = "invalid parent uuid";
goto out;
}
out:
vhd_close(&parent);
return msg;
}
static int
vhd_util_check_footer(int fd, vhd_footer_t *footer, int ignore)
{
size_t size;
int err, opened;
char *msg, *buf;
off_t eof, off;
vhd_footer_t primary, backup;
memset(&primary, 0, sizeof(primary));
memset(&backup, 0, sizeof(backup));
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(primary));
if (err) {
printf("error allocating buffer: %d\n", err);
return -err;
}
memset(buf, 0, sizeof(primary));
eof = lseek(fd, 0, SEEK_END);
if (eof == (off_t)-1) {
err = -errno;
printf("error calculating end of file: %d\n", err);
goto out;
}
size = ((eof % 512) ? 511 : 512);
eof = lseek(fd, eof - size, SEEK_SET);
if (eof == (off_t)-1) {
err = -errno;
printf("error calculating end of file: %d\n", err);
goto out;
}
err = read(fd, buf, 512);
if (err != size) {
err = (errno ? -errno : -EIO);
printf("error reading primary footer: %d\n", err);
goto out;
}
memcpy(&primary, buf, sizeof(primary));
opened = vhd_util_check_footer_opened(&primary);
vhd_footer_in(&primary);
msg = vhd_util_check_validate_footer(&primary);
if (msg) {
if (opened && ignore)
goto check_backup;
err = -EINVAL;
printf("primary footer invalid: %s\n", msg);
goto out;
}
if (primary.type == HD_TYPE_FIXED) {
err = 0;
goto out;
}
check_backup:
off = lseek(fd, 0, SEEK_SET);
if (off == (off_t)-1) {
err = -errno;
printf("error seeking to backup footer: %d\n", err);
goto out;
}
size = 512;
memset(buf, 0, sizeof(primary));
err = read(fd, buf, size);
if (err != size) {
err = (errno ? -errno : -EIO);
printf("error reading backup footer: %d\n", err);
goto out;
}
memcpy(&backup, buf, sizeof(backup));
vhd_footer_in(&backup);
msg = vhd_util_check_validate_footer(&backup);
if (msg) {
err = -EINVAL;
printf("backup footer invalid: %s\n", msg);
goto out;
}
if (memcmp(&primary, &backup, sizeof(primary))) {
if (opened && ignore) {
memcpy(&primary, &backup, sizeof(primary));
goto ok;
}
if (backup.hidden &&
!strncmp(backup.crtr_app, "tap", 3) &&
(backup.crtr_ver == VHD_VERSION(0, 1) ||
backup.crtr_ver == VHD_VERSION(1, 1))) {
char cmp, tmp = backup.hidden;
backup.hidden = 0;
cmp = memcmp(&primary, &backup, sizeof(primary));
backup.hidden = tmp;
if (!cmp)
goto ok;
}
err = -EINVAL;
printf("primary and backup footers do not match\n");
goto out;
}
ok:
err = 0;
memcpy(footer, &primary, sizeof(primary));
out:
free(buf);
return err;
}
static int
vhd_util_check_header(int fd, vhd_footer_t *footer)
{
int err;
off_t off;
char *msg, *buf;
vhd_header_t header;
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, sizeof(header));
if (err) {
printf("error allocating header: %d\n", err);
return err;
}
off = footer->data_offset;
off = lseek(fd, off, SEEK_SET);
if (off == (off_t)-1) {
err = -errno;
printf("error seeking to header: %d\n", err);
goto out;
}
err = read(fd, buf, sizeof(header));
if (err != sizeof(header)) {
err = (errno ? -errno : -EIO);
printf("error reading header: %d\n", err);
goto out;
}
memcpy(&header, buf, sizeof(header));
vhd_header_in(&header);
msg = vhd_util_check_validate_header(fd, &header);
if (msg) {
err = -EINVAL;
printf("header is invalid: %s\n", msg);
goto out;
}
err = 0;
out:
free(buf);
return err;
}
static int
vhd_util_check_differencing_header(vhd_context_t *vhd)
{
char *msg;
msg = vhd_util_check_validate_differencing_header(vhd);
if (msg) {
printf("differencing header is invalid: %s\n", msg);
return -EINVAL;
}
return 0;
}
static int
vhd_util_check_bat(vhd_context_t *vhd)
{
off_t eof, eoh;
int i, j, err, block_size;
err = vhd_seek(vhd, 0, SEEK_END);
if (err) {
printf("error calculating eof: %d\n", err);
return err;
}
eof = vhd_position(vhd);
if (eof == (off_t)-1) {
printf("error calculating eof: %d\n", -errno);
return -errno;
}
/* adjust eof for vhds with short footers */
if (eof % 512) {
if (eof % 512 != 511) {
printf("invalid file size: 0x%"PRIx64"\n", eof);
return -EINVAL;
}
eof++;
}
err = vhd_get_bat(vhd);
if (err) {
printf("error reading bat: %d\n", err);
return err;
}
err = vhd_end_of_headers(vhd, &eoh);
if (err) {
printf("error calculating end of metadata: %d\n", err);
return err;
}
eof -= sizeof(vhd_footer_t);
eof >>= VHD_SECTOR_SHIFT;
eoh >>= VHD_SECTOR_SHIFT;
block_size = vhd->spb + vhd->bm_secs;
for (i = 0; i < vhd->header.max_bat_size; i++) {
uint32_t off = vhd->bat.bat[i];
if (off == DD_BLK_UNUSED)
continue;
if (off < eoh) {
printf("block %d (offset 0x%x) clobbers headers\n",
i, off);
return -EINVAL;
}
if (off + block_size > eof) {
printf("block %d (offset 0x%x) clobbers footer\n",
i, off);
return -EINVAL;
}
for (j = 0; j < vhd->header.max_bat_size; j++) {
uint32_t joff = vhd->bat.bat[j];
if (i == j)
continue;
if (joff == DD_BLK_UNUSED)
continue;
if (off == joff)
err = -EINVAL;
if (off > joff && off < joff + block_size)
err = -EINVAL;
if (off + block_size > joff &&
off + block_size < joff + block_size)
err = -EINVAL;
if (err) {
printf("block %d (offset 0x%x) clobbers "
"block %d (offset 0x%x)\n",
i, off, j, joff);
return err;
}
}
}
return 0;
}
static int
vhd_util_check_batmap(vhd_context_t *vhd)
{
char *msg;
int i, err;
err = vhd_get_bat(vhd);
if (err) {
printf("error reading bat: %d\n", err);
return err;
}
err = vhd_get_batmap(vhd);
if (err) {
printf("error reading batmap: %d\n", err);
return err;
}
msg = vhd_util_check_validate_batmap(vhd, &vhd->batmap);
if (msg) {
printf("batmap is invalid: %s\n", msg);
return -EINVAL;
}
for (i = 0; i < vhd->header.max_bat_size; i++) {
if (!vhd_batmap_test(vhd, &vhd->batmap, i))
continue;
if (vhd->bat.bat[i] == DD_BLK_UNUSED) {
printf("batmap shows unallocated block %d full\n", i);
return -EINVAL;
}
}
return 0;
}
static int
vhd_util_check_parent_locators(vhd_context_t *vhd)
{
int i, n, err;
vhd_parent_locator_t *loc;
char *file, *ppath, *location, *pname;
const char *msg;
int mac, macx, w2ku, w2ru, wi2r, wi2k, found;
mac = 0;
macx = 0;
w2ku = 0;
w2ru = 0;
wi2r = 0;
wi2k = 0;
found = 0;
pname = NULL;
ppath = NULL;
location = NULL;
err = vhd_header_decode_parent(vhd, &vhd->header, &pname);
if (err) {
printf("error decoding parent name: %d\n", err);
return err;
}
n = sizeof(vhd->header.loc) / sizeof(vhd->header.loc[0]);
for (i = 0; i < n; i++) {
ppath = NULL;
location = NULL;
loc = vhd->header.loc + i;
msg = vhd_util_check_validate_parent_locator(vhd, loc);
if (msg) {
err = -EINVAL;
printf("invalid parent locator %d: %s\n", i, msg);
goto out;
}
if (loc->code == PLAT_CODE_NONE)
continue;
switch (loc->code) {
case PLAT_CODE_MACX:
if (macx++)
goto dup;
break;
case PLAT_CODE_MAC:
if (mac++)
goto dup;
break;
case PLAT_CODE_W2KU:
if (w2ku++)
goto dup;
break;
case PLAT_CODE_W2RU:
if (w2ru++)
goto dup;
break;
case PLAT_CODE_WI2R:
if (wi2r++)
goto dup;
break;
case PLAT_CODE_WI2K:
if (wi2k++)
goto dup;
break;
default:
err = -EINVAL;
printf("invalid platform code for locator %d\n", i);
goto out;
}
if (loc->code != PLAT_CODE_MACX &&
loc->code != PLAT_CODE_W2RU &&
loc->code != PLAT_CODE_W2KU)
continue;
err = vhd_parent_locator_read(vhd, loc, &ppath);
if (err) {
printf("error reading parent locator %d: %d\n", i, err);
goto out;
}
file = basename(ppath);
if (strcmp(pname, file)) {
err = -EINVAL;
printf("parent locator %d name (%s) does not match "
"header name (%s)\n", i, file, pname);
goto out;
}
err = vhd_find_parent(vhd, ppath, &location);
if (err) {
printf("error resolving %s: %d\n", ppath, err);
goto out;
}
err = access(location, R_OK);
if (err && loc->code == PLAT_CODE_MACX) {
err = -errno;
printf("parent locator %d points to missing file %s "
"(resolved to %s)\n", i, ppath, location);
goto out;
}
msg = vhd_util_check_validate_parent(vhd, location);
if (msg) {
err = -EINVAL;
printf("invalid parent %s: %s\n", location, msg);
goto out;
}
found++;
free(ppath);
free(location);
ppath = NULL;
location = NULL;
continue;
dup:
printf("duplicate platform code in locator %d: 0x%x\n",
i, loc->code);
err = -EINVAL;
goto out;
}
if (!found) {
err = -EINVAL;
printf("could not find parent %s\n", pname);
goto out;
}
err = 0;
out:
free(pname);
free(ppath);
free(location);
return err;
}
static void
vhd_util_dump_headers(const char *name)
{
char *argv[] = { "read", "-p", "-n", (char *)name };
int argc = sizeof(argv) / sizeof(argv[0]);
printf("%s appears invalid; dumping metadata\n", name);
vhd_util_read(argc, argv);
}
static int
vhd_util_check_vhd(const char *name, int ignore)
{
int fd, err;
vhd_context_t vhd;
struct stat stats;
vhd_footer_t footer;
fd = -1;
memset(&vhd, 0, sizeof(vhd));
memset(&footer, 0, sizeof(footer));
err = stat(name, &stats);
if (err == -1) {
printf("cannot stat %s: %d\n", name, errno);
return -errno;
}
if (!S_ISREG(stats.st_mode) && !S_ISBLK(stats.st_mode)) {
printf("%s is not a regular file or block device\n", name);
return -EINVAL;
}
fd = open(name, O_RDONLY | O_DIRECT | O_LARGEFILE);
if (fd == -1) {
printf("error opening %s\n", name);
return -errno;
}
err = vhd_util_check_footer(fd, &footer, ignore);
if (err)
goto out;
if (footer.type != HD_TYPE_DYNAMIC && footer.type != HD_TYPE_DIFF)
goto out;
err = vhd_util_check_header(fd, &footer);
if (err)
goto out;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err)
goto out;
err = vhd_util_check_differencing_header(&vhd);
if (err)
goto out;
err = vhd_util_check_bat(&vhd);
if (err)
goto out;
if (vhd_has_batmap(&vhd)) {
err = vhd_util_check_batmap(&vhd);
if (err)
goto out;
}
if (vhd.footer.type == HD_TYPE_DIFF) {
err = vhd_util_check_parent_locators(&vhd);
if (err)
goto out;
}
err = 0;
printf("%s is valid\n", name);
out:
if (err)
vhd_util_dump_headers(name);
if (fd != -1)
close(fd);
vhd_close(&vhd);
return err;
}
static int
vhd_util_check_parents(const char *name, int ignore)
{
int err;
vhd_context_t vhd;
char *cur, *parent;
cur = (char *)name;
for (;;) {
err = vhd_open(&vhd, cur,
VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err)
goto out;
if (vhd.footer.type != HD_TYPE_DIFF || vhd_parent_raw(&vhd)) {
vhd_close(&vhd);
goto out;
}
err = vhd_parent_locator_get(&vhd, &parent);
vhd_close(&vhd);
if (err) {
printf("error getting parent: %d\n", err);
goto out;
}
if (cur != name)
free(cur);
cur = parent;
err = vhd_util_check_vhd(cur, ignore);
if (err)
goto out;
}
out:
if (err)
printf("error checking parents: %d\n", err);
if (cur != name)
free(cur);
return err;
}
int
vhd_util_check(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
int c, err, ignore, parents;
if (!argc || !argv) {
err = -EINVAL;
goto usage;
}
ignore = 0;
parents = 0;
name = NULL;
optind = 0;
while ((c = getopt(argc, argv, "n:iph")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'i':
ignore = 1;
break;
case 'p':
parents = 1;
break;
case 'h':
err = 0;
goto usage;
default:
err = -EINVAL;
goto usage;
}
}
if (!name || optind != argc) {
err = -EINVAL;
goto usage;
}
err = vhd_util_check_vhd(name, ignore);
if (err)
goto out;
if (parents)
err = vhd_util_check_parents(name, ignore);
out:
return err;
usage:
printf("options: -n <file> [-i ignore missing primary footers] "
"[-p check parents] [-h help]\n");
return err;
}

View File

@ -0,0 +1,218 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
static int
__raw_io_write(int fd, char* buf, uint64_t sec, uint32_t secs)
{
off_t off;
size_t ret;
errno = 0;
off = lseek(fd, vhd_sectors_to_bytes(sec), SEEK_SET);
if (off == (off_t)-1) {
printf("raw parent: seek(0x%08"PRIx64") failed: %d\n",
vhd_sectors_to_bytes(sec), -errno);
return -errno;
}
ret = write(fd, buf, vhd_sectors_to_bytes(secs));
if (ret == vhd_sectors_to_bytes(secs))
return 0;
printf("raw parent: write of 0x%"PRIx64" returned %zd, errno: %d\n",
vhd_sectors_to_bytes(secs), ret, -errno);
return (errno ? -errno : -EIO);
}
/*
* Use 'parent' if the parent is VHD, and 'parent_fd' if the parent is raw
*/
static int
vhd_util_coalesce_block(vhd_context_t *vhd, vhd_context_t *parent,
int parent_fd, uint64_t block)
{
int i, err;
char *buf, *map;
uint64_t sec, secs;
buf = NULL;
map = NULL;
sec = block * vhd->spb;
if (vhd->bat.bat[block] == DD_BLK_UNUSED)
return 0;
err = posix_memalign((void **)&buf, 4096, vhd->header.block_size);
if (err)
return -err;
err = vhd_io_read(vhd, buf, sec, vhd->spb);
if (err)
goto done;
if (vhd_has_batmap(vhd) && vhd_batmap_test(vhd, &vhd->batmap, block)) {
if (parent->file)
err = vhd_io_write(parent, buf, sec, vhd->spb);
else
err = __raw_io_write(parent_fd, buf, sec, vhd->spb);
goto done;
}
err = vhd_read_bitmap(vhd, block, &map);
if (err)
goto done;
for (i = 0; i < vhd->spb; i++) {
if (!vhd_bitmap_test(vhd, map, i))
continue;
for (secs = 0; i + secs < vhd->spb; secs++)
if (!vhd_bitmap_test(vhd, map, i + secs))
break;
if (parent->file)
err = vhd_io_write(parent,
buf + vhd_sectors_to_bytes(i),
sec + i, secs);
else
err = __raw_io_write(parent_fd,
buf + vhd_sectors_to_bytes(i),
sec + i, secs);
if (err)
goto done;
i += secs;
}
err = 0;
done:
free(buf);
free(map);
return err;
}
int
vhd_util_coalesce(int argc, char **argv)
{
int err, c;
uint64_t i;
char *name, *pname;
vhd_context_t vhd, parent;
int parent_fd = -1;
name = NULL;
pname = NULL;
parent.file = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
err = vhd_parent_locator_get(&vhd, &pname);
if (err) {
printf("error finding %s parent: %d\n", name, err);
vhd_close(&vhd);
return err;
}
if (vhd_parent_raw(&vhd)) {
parent_fd = open(pname, O_RDWR | O_DIRECT | O_LARGEFILE, 0644);
if (parent_fd == -1) {
err = -errno;
printf("failed to open parent %s: %d\n", pname, err);
vhd_close(&vhd);
return err;
}
} else {
err = vhd_open(&parent, pname, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", pname, err);
free(pname);
vhd_close(&vhd);
return err;
}
}
err = vhd_get_bat(&vhd);
if (err)
goto done;
if (vhd_has_batmap(&vhd)) {
err = vhd_get_batmap(&vhd);
if (err)
goto done;
}
for (i = 0; i < vhd.bat.entries; i++) {
err = vhd_util_coalesce_block(&vhd, &parent, parent_fd, i);
if (err)
goto done;
}
err = 0;
done:
free(pname);
vhd_close(&vhd);
if (parent.file)
vhd_close(&parent);
else
close(parent_fd);
return err;
usage:
printf("options: <-n name> [-h help]\n");
return -EINVAL;
}

View File

@ -0,0 +1,80 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
int
vhd_util_create(int argc, char **argv)
{
char *name;
uint64_t size;
int c, sparse, err;
vhd_flag_creat_t flags;
err = -EINVAL;
size = 0;
sparse = 1;
name = NULL;
flags = 0;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:s:rh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 's':
err = 0;
size = strtoull(optarg, NULL, 10);
break;
case 'r':
sparse = 0;
break;
case 'h':
default:
goto usage;
}
}
if (err || !name || optind != argc)
goto usage;
return vhd_create(name, size << 20,
(sparse ? HD_TYPE_DYNAMIC : HD_TYPE_FIXED),
flags);
usage:
printf("options: <-n name> <-s size (MB)> [-r reserve] [-h help]\n");
return -EINVAL;
}

View File

@ -0,0 +1,105 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
int
vhd_util_fill(int argc, char **argv)
{
int err, c;
char *buf, *name;
vhd_context_t vhd;
uint64_t i, sec, secs;
buf = NULL;
name = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
err = vhd_get_bat(&vhd);
if (err)
goto done;
err = posix_memalign((void **)&buf, 4096, vhd.header.block_size);
if (err) {
err = -err;
goto done;
}
sec = 0;
secs = vhd.header.block_size >> VHD_SECTOR_SHIFT;
for (i = 0; i < vhd.header.max_bat_size; i++) {
err = vhd_io_read(&vhd, buf, sec, secs);
if (err)
goto done;
err = vhd_io_write(&vhd, buf, sec, secs);
if (err)
goto done;
sec += secs;
}
err = 0;
done:
free(buf);
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> [-h help]\n");
return -EINVAL;
}

View File

@ -0,0 +1,132 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Altering operations:
*
* 1. Change the parent pointer to another file.
* 2. Change the size of the file containing the VHD image. This does NOT
* affect the VHD disk capacity, only the physical size of the file containing
* the VHD. Naturally, it is not possible to set the file size to be less than
* the what VHD utilizes.
* The operation doesn't actually change the file size, but it writes the
* footer in the right location such that resizing the file (manually, as a
* separate step) will produce the correct results. If the new file size is
* greater than the current file size, the file must first be expanded and then
* altered with this operation. If the new size is smaller than the current
* size, the VHD must first be altered with this operation and then the file
* must be shrunk. Failing to resize the file will result in a corrupted VHD.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
TEST_FAIL_EXTERN_VARS;
int
vhd_util_modify(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
int err, c, size, parent, parent_raw;
off_t newsize = 0;
char *newparent = NULL;
name = NULL;
size = 0;
parent = 0;
parent_raw = 0;
optind = 0;
while ((c = getopt(argc, argv, "n:s:p:mh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 's':
size = 1;
errno = 0;
newsize = strtoll(optarg, NULL, 10);
if (errno) {
fprintf(stderr, "Invalid size '%s'\n", optarg);
goto usage;
}
break;
case 'p':
parent = 1;
newparent = optarg;
break;
case 'm':
parent_raw = 1;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
if (size) {
err = vhd_set_phys_size(&vhd, newsize);
if (err)
printf("failed to set physical size to %"PRIu64":"
" %d\n", newsize, err);
}
if (parent) {
TEST_FAIL_AT(FAIL_REPARENT_BEGIN);
err = vhd_change_parent(&vhd, newparent, parent_raw);
if (err) {
printf("failed to set parent to '%s': %d\n",
newparent, err);
goto done;
}
TEST_FAIL_AT(FAIL_REPARENT_END);
}
done:
vhd_close(&vhd);
return err;
usage:
printf("*** Dangerous operations, use with care ***\n");
printf("options: <-n name> [-p NEW_PARENT set parent [-m raw]] "
"[-s NEW_SIZE set size] [-h help]\n");
return -EINVAL;
}

View File

@ -0,0 +1,159 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
int
vhd_util_query(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
off_t currsize;
int ret, err, c, size, physize, parent, fields, depth;
name = NULL;
size = 0;
physize = 0;
parent = 0;
fields = 0;
depth = 0;
if (!argc || !argv) {
err = -EINVAL;
goto usage;
}
optind = 0;
while ((c = getopt(argc, argv, "n:vspfdh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'v':
size = 1;
break;
case 's':
physize = 1;
break;
case 'p':
parent = 1;
break;
case 'f':
fields = 1;
break;
case 'd':
depth = 1;
break;
case 'h':
err = 0;
goto usage;
default:
err = -EINVAL;
goto usage;
}
}
if (!name || optind != argc) {
err = -EINVAL;
goto usage;
}
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
if (size)
printf("%"PRIu64"\n", vhd.footer.curr_size >> 20);
if (physize) {
err = vhd_get_phys_size(&vhd, &currsize);
if (err)
printf("failed to get physical size: %d\n", err);
else
printf("%"PRIu64"\n", currsize);
}
if (parent) {
ret = 0;
if (vhd.footer.type != HD_TYPE_DIFF)
printf("%s has no parent\n", name);
else {
char *pname;
ret = vhd_parent_locator_get(&vhd, &pname);
if (ret)
printf("query failed\n");
else {
printf("%s\n", pname);
free(pname);
}
}
err = (err ? : ret);
}
if (fields) {
int hidden;
ret = vhd_hidden(&vhd, &hidden);
if (ret)
printf("error checking 'hidden' field: %d\n", ret);
else
printf("hidden: %d\n", hidden);
err = (err ? : ret);
}
if (depth) {
int length;
ret = vhd_chain_depth(&vhd, &length);
if (ret)
printf("error checking chain depth: %d\n", ret);
else
printf("chain depth: %d\n", length);
err = (err ? : ret);
}
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> [-v print virtual size (in MB)] "
"[-s print physical utilization (bytes)] [-p print parent] "
"[-f print fields] [-d print chain depth] [-h help]\n");
return err;
}

View File

@ -0,0 +1,742 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <inttypes.h>
#include "libvhd.h"
#include "vhd-util.h"
#define nsize 15
static char nbuf[nsize];
static inline char *
__xconv(uint64_t num)
{
snprintf(nbuf, nsize, "%#" PRIx64 , num);
return nbuf;
}
static inline char *
__dconv(uint64_t num)
{
snprintf(nbuf, nsize, "%" PRIu64, num);
return nbuf;
}
#define conv(hex, num) \
(hex ? __xconv((uint64_t)num) : __dconv((uint64_t)num))
static void
vhd_print_header(vhd_context_t *vhd, vhd_header_t *h, int hex)
{
int err;
uint32_t cksm;
char uuid[39], time_str[26], cookie[9], out[512], *name;
printf("VHD Header Summary:\n-------------------\n");
snprintf(cookie, sizeof(cookie), "%s", h->cookie);
printf("Cookie : %s\n", cookie);
printf("Data offset (unusd) : %s\n", conv(hex, h->data_offset));
printf("Table offset : %s\n", conv(hex, h->table_offset));
printf("Header version : 0x%08x\n", h->hdr_ver);
printf("Max BAT size : %s\n", conv(hex, h->max_bat_size));
printf("Block size : %s ", conv(hex, h->block_size));
printf("(%s MB)\n", conv(hex, h->block_size >> 20));
err = vhd_header_decode_parent(vhd, h, &name);
printf("Parent name : %s\n",
(err ? "failed to read name" : name));
free(name);
blk_uuid_to_string(&h->prt_uuid, uuid, sizeof(uuid));
printf("Parent UUID : %s\n", uuid);
vhd_time_to_string(h->prt_ts, time_str);
printf("Parent timestamp : %s\n", time_str);
cksm = vhd_checksum_header(h);
printf("Checksum : 0x%x|0x%x (%s)\n", h->checksum, cksm,
h->checksum == cksm ? "Good!" : "Bad!");
printf("\n");
}
static void
vhd_print_footer(vhd_footer_t *f, int hex)
{
uint64_t c, h, s;
uint32_t ff_maj, ff_min, cr_maj, cr_min, cksm, cksm_save;
char time_str[26], creator[5], uuid[39], cookie[9];
printf("VHD Footer Summary:\n-------------------\n");
snprintf(cookie, sizeof(cookie), "%s", f->cookie);
printf("Cookie : %s\n", cookie);
printf("Features : (0x%08x) %s%s\n", f->features,
(f->features & HD_TEMPORARY) ? "<TEMP>" : "",
(f->features & HD_RESERVED) ? "<RESV>" : "");
ff_maj = f->ff_version >> 16;
ff_min = f->ff_version & 0xffff;
printf("File format version : Major: %d, Minor: %d\n",
ff_maj, ff_min);
printf("Data offset : %s\n", conv(hex, f->data_offset));
vhd_time_to_string(f->timestamp, time_str);
printf("Timestamp : %s\n", time_str);
memcpy(creator, f->crtr_app, 4);
creator[4] = '\0';
printf("Creator Application : '%s'\n", creator);
cr_maj = f->crtr_ver >> 16;
cr_min = f->crtr_ver & 0xffff;
printf("Creator version : Major: %d, Minor: %d\n",
cr_maj, cr_min);
printf("Creator OS : %s\n",
((f->crtr_os == HD_CR_OS_WINDOWS) ? "Windows" :
((f->crtr_os == HD_CR_OS_MACINTOSH) ? "Macintosh" :
"Unknown!")));
printf("Original disk size : %s MB ", conv(hex, f->orig_size >> 20));
printf("(%s Bytes)\n", conv(hex, f->orig_size));
printf("Current disk size : %s MB ", conv(hex, f->curr_size >> 20));
printf("(%s Bytes)\n", conv(hex, f->curr_size));
c = f->geometry >> 16;
h = (f->geometry & 0x0000FF00) >> 8;
s = f->geometry & 0x000000FF;
printf("Geometry : Cyl: %s, ", conv(hex, c));
printf("Hds: %s, ", conv(hex, h));
printf("Sctrs: %s\n", conv(hex, s));
printf(" : = %s MB ", conv(hex, (c * h * s) >> 11));
printf("(%s Bytes)\n", conv(hex, c * h * s << 9));
printf("Disk type : %s\n",
f->type <= HD_TYPE_MAX ?
HD_TYPE_STR[f->type] : "Unknown type!\n");
cksm = vhd_checksum_footer(f);
printf("Checksum : 0x%x|0x%x (%s)\n", f->checksum, cksm,
f->checksum == cksm ? "Good!" : "Bad!");
blk_uuid_to_string(&f->uuid, uuid, sizeof(uuid));
printf("UUID : %s\n", uuid);
printf("Saved state : %s\n", f->saved == 0 ? "No" : "Yes");
printf("Hidden : %d\n", f->hidden);
printf("\n");
}
static inline char *
code_name(uint32_t code)
{
switch(code) {
case PLAT_CODE_NONE:
return "PLAT_CODE_NONE";
case PLAT_CODE_WI2R:
return "PLAT_CODE_WI2R";
case PLAT_CODE_WI2K:
return "PLAT_CODE_WI2K";
case PLAT_CODE_W2RU:
return "PLAT_CODE_W2RU";
case PLAT_CODE_W2KU:
return "PLAT_CODE_W2KU";
case PLAT_CODE_MAC:
return "PLAT_CODE_MAC";
case PLAT_CODE_MACX:
return "PLAT_CODE_MACX";
default:
return "UNKOWN";
}
}
static void
vhd_print_parent(vhd_context_t *vhd, vhd_parent_locator_t *loc)
{
int err;
char *buf;
err = vhd_parent_locator_read(vhd, loc, &buf);
if (err) {
printf("failed to read parent name\n");
return;
}
printf(" decoded name : %s\n", buf);
}
static void
vhd_print_parent_locators(vhd_context_t *vhd, int hex)
{
int i, n;
vhd_parent_locator_t *loc;
printf("VHD Parent Locators:\n--------------------\n");
n = sizeof(vhd->header.loc) / sizeof(struct prt_loc);
for (i = 0; i < n; i++) {
loc = &vhd->header.loc[i];
if (loc->code == PLAT_CODE_NONE)
continue;
printf("locator: : %d\n", i);
printf(" code : %s\n",
code_name(loc->code));
printf(" data_space : %s\n",
conv(hex, loc->data_space));
printf(" data_length : %s\n",
conv(hex, loc->data_len));
printf(" data_offset : %s\n",
conv(hex, loc->data_offset));
vhd_print_parent(vhd, loc);
printf("\n");
}
}
static void
vhd_print_batmap_header(vhd_batmap_t *batmap, int hex)
{
uint32_t cksm;
printf("VHD Batmap Summary:\n-------------------\n");
printf("Batmap offset : %s\n",
conv(hex, batmap->header.batmap_offset));
printf("Batmap size (secs) : %s\n",
conv(hex, batmap->header.batmap_size));
printf("Batmap version : 0x%08x\n",
batmap->header.batmap_version);
cksm = vhd_checksum_batmap(batmap);
printf("Checksum : 0x%x|0x%x (%s)\n",
batmap->header.checksum, cksm,
(batmap->header.checksum == cksm ? "Good!" : "Bad!"));
printf("\n");
}
static inline int
check_block_range(vhd_context_t *vhd, uint64_t block, int hex)
{
if (block > vhd->header.max_bat_size) {
fprintf(stderr, "block %s past end of file\n",
conv(hex, block));
return -ERANGE;
}
return 0;
}
static int
vhd_print_headers(vhd_context_t *vhd, int hex)
{
int err;
vhd_print_footer(&vhd->footer, hex);
if (vhd_type_dynamic(vhd)) {
vhd_print_header(vhd, &vhd->header, hex);
if (vhd->footer.type == HD_TYPE_DIFF)
vhd_print_parent_locators(vhd, hex);
if (vhd_has_batmap(vhd)) {
err = vhd_get_batmap(vhd);
if (err) {
printf("failed to get batmap header\n");
return err;
}
vhd_print_batmap_header(&vhd->batmap, hex);
}
}
return 0;
}
static int
vhd_dump_headers(const char *name, int hex)
{
vhd_context_t vhd;
libvhd_set_log_level(1);
memset(&vhd, 0, sizeof(vhd));
printf("\n%s appears invalid; dumping headers\n\n", name);
vhd.fd = open(name, O_DIRECT | O_LARGEFILE | O_RDONLY);
if (vhd.fd == -1)
return -errno;
vhd.file = strdup(name);
vhd_read_footer(&vhd, &vhd.footer);
vhd_read_header(&vhd, &vhd.header);
vhd_print_footer(&vhd.footer, hex);
vhd_print_header(&vhd, &vhd.header, hex);
close(vhd.fd);
free(vhd.file);
return 0;
}
static int
vhd_print_logical_to_physical(vhd_context_t *vhd,
uint64_t sector, int count, int hex)
{
int i;
uint32_t blk, lsec;
uint64_t cur, offset;
if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
fprintf(stderr, "sector %s past end of file\n",
conv(hex, sector + count));
return -ERANGE;
}
for (i = 0; i < count; i++) {
cur = sector + i;
blk = cur / vhd->spb;
lsec = cur % vhd->spb;
offset = vhd->bat.bat[blk];
if (offset != DD_BLK_UNUSED) {
offset += lsec + 1;
offset = vhd_sectors_to_bytes(offset);
}
printf("logical sector %s: ", conv(hex, cur));
printf("block number: %s, ", conv(hex, blk));
printf("sector offset: %s, ", conv(hex, lsec));
printf("file offset: %s\n", (offset == DD_BLK_UNUSED ?
"not allocated" : conv(hex, offset)));
}
return 0;
}
static int
vhd_print_bat(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
int i;
uint64_t cur, offset;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
for (i = 0; i < count; i++) {
cur = block + i;
offset = vhd->bat.bat[cur];
printf("block: %s: ", conv(hex, cur));
printf("offset: %s\n",
(offset == DD_BLK_UNUSED ? "not allocated" :
conv(hex, vhd_sectors_to_bytes(offset))));
}
return 0;
}
static inline void
write_full(int fd, void* buf, size_t count)
{
ssize_t num_written = 0;
if (!buf) return;
while(count > 0) {
num_written = write(fd, buf, count);
if (num_written == -1) {
if (errno == EINTR)
continue;
else
return;
}
count -= num_written;
buf += num_written;
}
}
static int
vhd_print_bitmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
char *buf;
int i, err;
uint64_t cur;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
for (i = 0; i < count; i++) {
cur = block + i;
if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
printf("block %s not allocated\n", conv(hex, cur));
continue;
}
err = vhd_read_bitmap(vhd, cur, &buf);
if (err)
goto out;
write_full(STDOUT_FILENO, buf,
vhd_sectors_to_bytes(vhd->bm_secs));
free(buf);
}
err = 0;
out:
return err;
}
static int
vhd_test_bitmap(vhd_context_t *vhd, uint64_t sector, int count, int hex)
{
char *buf;
uint64_t cur;
int i, err, bit;
uint32_t blk, bm_blk, sec;
if (vhd_sectors_to_bytes(sector + count) > vhd->footer.curr_size) {
printf("sector %s past end of file\n", conv(hex, sector));
return -ERANGE;
}
bm_blk = -1;
buf = NULL;
for (i = 0; i < count; i++) {
cur = sector + i;
blk = cur / vhd->spb;
sec = cur % vhd->spb;
if (blk != bm_blk) {
bm_blk = blk;
free(buf);
buf = NULL;
if (vhd->bat.bat[blk] != DD_BLK_UNUSED) {
err = vhd_read_bitmap(vhd, blk, &buf);
if (err)
goto out;
}
}
if (vhd->bat.bat[blk] == DD_BLK_UNUSED)
bit = 0;
else
bit = vhd_bitmap_test(vhd, buf, blk);
print:
printf("block %s: ", conv(hex, blk));
printf("sec: %s: %d\n", conv(hex, sec), bit);
}
err = 0;
out:
free(buf);
return err;
}
static int
vhd_print_batmap(vhd_context_t *vhd)
{
int err;
size_t size;
err = vhd_get_batmap(vhd);
if (err) {
printf("failed to read batmap: %d\n", err);
return err;
}
size = vhd_sectors_to_bytes(vhd->batmap.header.batmap_size);
write_full(STDOUT_FILENO, vhd->batmap.map, size);
return 0;
}
static int
vhd_test_batmap(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
int i, err;
uint64_t cur;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
err = vhd_get_batmap(vhd);
if (err) {
fprintf(stderr, "failed to get batmap\n");
return err;
}
for (i = 0; i < count; i++) {
cur = block + i;
fprintf(stderr, "batmap for block %s: %d\n", conv(hex, cur),
vhd_batmap_test(vhd, &vhd->batmap, cur));
}
return 0;
}
static int
vhd_print_data(vhd_context_t *vhd, uint64_t block, int count, int hex)
{
char *buf;
int i, err;
uint64_t cur;
err = 0;
if (check_block_range(vhd, block + count, hex))
return -ERANGE;
for (i = 0; i < count; i++) {
cur = block + i;
if (vhd->bat.bat[cur] == DD_BLK_UNUSED) {
printf("block %s not allocated\n", conv(hex, cur));
continue;
}
err = vhd_read_block(vhd, cur, &buf);
if (err)
break;
write_full(STDOUT_FILENO, buf, vhd->header.block_size);
free(buf);
}
return err;
}
static int
vhd_read_data(vhd_context_t *vhd, uint64_t sec, int count, int hex)
{
char *buf;
uint64_t cur;
int err, max, secs;
if (vhd_sectors_to_bytes(sec + count) > vhd->footer.curr_size)
return -ERANGE;
max = MIN(vhd_sectors_to_bytes(count), VHD_BLOCK_SIZE);
err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, max);
if (err)
return -err;
cur = sec;
while (count) {
secs = MIN((max >> VHD_SECTOR_SHIFT), count);
err = vhd_io_read(vhd, buf, cur, secs);
if (err)
break;
write_full(STDOUT_FILENO, buf, vhd_sectors_to_bytes(secs));
cur += secs;
count -= secs;
}
free(buf);
return err;
}
int
vhd_util_read(int argc, char **argv)
{
char *name;
vhd_context_t vhd;
int c, err, headers, hex;
uint64_t bat, bitmap, tbitmap, batmap, tbatmap, data, lsec, count, read;
err = 0;
hex = 0;
headers = 0;
count = 1;
bat = -1;
bitmap = -1;
tbitmap = -1;
batmap = -1;
tbatmap = -1;
data = -1;
lsec = -1;
read = -1;
name = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:pt:b:m:i:aj:d:c:r:xh")) != -1) {
switch(c) {
case 'n':
name = optarg;
break;
case 'p':
headers = 1;
break;
case 't':
lsec = strtoul(optarg, NULL, 10);
break;
case 'b':
bat = strtoull(optarg, NULL, 10);
break;
case 'm':
bitmap = strtoull(optarg, NULL, 10);
break;
case 'i':
tbitmap = strtoul(optarg, NULL, 10);
break;
case 'a':
batmap = 1;
break;
case 'j':
tbatmap = strtoull(optarg, NULL, 10);
break;
case 'd':
data = strtoull(optarg, NULL, 10);
break;
case 'r':
read = strtoull(optarg, NULL, 10);
break;
case 'c':
count = strtoul(optarg, NULL, 10);
break;
case 'x':
hex = 1;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED);
if (err) {
printf("Failed to open %s: %d\n", name, err);
vhd_dump_headers(name, hex);
return err;
}
err = vhd_get_bat(&vhd);
if (err) {
printf("Failed to get bat for %s: %d\n", name, err);
goto out;
}
if (headers)
vhd_print_headers(&vhd, hex);
if (lsec != -1) {
err = vhd_print_logical_to_physical(&vhd, lsec, count, hex);
if (err)
goto out;
}
if (bat != -1) {
err = vhd_print_bat(&vhd, bat, count, hex);
if (err)
goto out;
}
if (bitmap != -1) {
err = vhd_print_bitmap(&vhd, bitmap, count, hex);
if (err)
goto out;
}
if (tbitmap != -1) {
err = vhd_test_bitmap(&vhd, tbitmap, count, hex);
if (err)
goto out;
}
if (batmap != -1) {
err = vhd_print_batmap(&vhd);
if (err)
goto out;
}
if (tbatmap != -1) {
err = vhd_test_batmap(&vhd, tbatmap, count, hex);
if (err)
goto out;
}
if (data != -1) {
err = vhd_print_data(&vhd, data, count, hex);
if (err)
goto out;
}
if (read != -1) {
err = vhd_read_data(&vhd, read, count, hex);
if (err)
goto out;
}
err = 0;
out:
vhd_close(&vhd);
return err;
usage:
printf("options:\n"
"-h help\n"
"-n name\n"
"-p print VHD headers\n"
"-t sec translate logical sector to VHD location\n"
"-b blk print bat entry\n"
"-m blk print bitmap\n"
"-i sec test bitmap for logical sector\n"
"-a print batmap\n"
"-j blk test batmap for block\n"
"-d blk print data\n"
"-c num num units\n"
"-r sec read num sectors at sec\n"
"-x print in hex\n");
return EINVAL;
}

View File

@ -0,0 +1,84 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
int
vhd_util_repair(int argc, char **argv)
{
char *name;
int err, c;
off_t eof;
vhd_context_t vhd;
name = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || optind != argc)
goto usage;
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
err = vhd_end_of_data(&vhd, &eof);
if (err) {
printf("error finding end of data: %d\n", err);
goto done;
}
err = vhd_write_footer_at(&vhd, &vhd.footer, eof);
done:
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> [-h help]\n");
return -EINVAL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Altering operations:
*
* 1. Change the parent pointer to another file.
* 2. Change the size of the file containing the VHD image. This does NOT
* affect the VHD disk capacity, only the physical size of the file containing
* the VHD. Naturally, it is not possible to set the file size to be less than
* the what VHD utilizes.
* The operation doesn't actually change the file size, but it writes the
* footer in the right location such that resizing the file (manually, as a
* separate step) will produce the correct results. If the new file size is
* greater than the current file size, the file must first be expanded and then
* altered with this operation. If the new size is smaller than the current
* size, the VHD must first be altered with this operation and then the file
* must be shrunk. Failing to resize the file will result in a corrupted VHD.
*/
#include <errno.h>
//#include <fcntl.h>
#include <stdio.h>
//#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
#include "libvhd-journal.h"
int
vhd_util_revert(int argc, char **argv)
{
char *name, *jname;
vhd_journal_t journal;
int c, err;
name = NULL;
jname = NULL;
optind = 0;
while ((c = getopt(argc, argv, "n:j:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'j':
jname = optarg;
break;
case 'h':
default:
goto usage;
}
}
if (!name || !jname || argc != optind)
goto usage;
libvhd_set_log_level(1);
err = vhd_journal_open(&journal, name, jname);
if (err) {
printf("opening journal failed: %d\n", err);
return err;
}
err = vhd_journal_revert(&journal);
if (err) {
printf("reverting journal failed: %d\n", err);
vhd_journal_close(&journal);
return err;
}
err = vhd_journal_remove(&journal);
if (err) {
printf("removing journal failed: %d\n", err);
vhd_journal_close(&journal);
return err;
}
return 0;
usage:
printf("options: <-n name> <-j journal> [-h help]\n");
return -EINVAL;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
int
vhd_util_set_field(int argc, char **argv)
{
long value;
int err, c;
off_t eof;
vhd_context_t vhd;
char *name, *field;
err = -EINVAL;
value = 0;
name = NULL;
field = NULL;
if (!argc || !argv)
goto usage;
optind = 0;
while ((c = getopt(argc, argv, "n:f:v:h")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'f':
field = optarg;
break;
case 'v':
err = 0;
value = strtol(optarg, NULL, 10);
break;
case 'h':
default:
goto usage;
}
}
if (!name || !field || optind != argc || err)
goto usage;
if (strnlen(field, 25) >= 25) {
printf("invalid field\n");
goto usage;
}
if (strcmp(field, "hidden")) {
printf("invalid field %s\n", field);
goto usage;
}
if (value < 0 || value > 255) {
printf("invalid value %ld\n", value);
goto usage;
}
err = vhd_open(&vhd, name, VHD_OPEN_RDWR);
if (err) {
printf("error opening %s: %d\n", name, err);
return err;
}
vhd.footer.hidden = (char)value;
err = vhd_write_footer(&vhd, &vhd.footer);
done:
vhd_close(&vhd);
return err;
usage:
printf("options: <-n name> <-f field> <-v value> [-h help]\n");
return -EINVAL;
}

View File

@ -0,0 +1,216 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "libvhd.h"
static int
vhd_util_find_snapshot_target(const char *name, char **result, int *parent_raw)
{
int i, err;
char *target;
vhd_context_t vhd;
*parent_raw = 0;
*result = NULL;
target = strdup(name);
if (!target)
return -ENOMEM;
for (;;) {
err = vhd_open(&vhd, target, VHD_OPEN_RDONLY);
if (err)
return err;
if (vhd.footer.type != HD_TYPE_DIFF)
goto out;
err = vhd_get_bat(&vhd);
if (err)
goto out;
for (i = 0; i < vhd.bat.entries; i++)
if (vhd.bat.bat[i] != DD_BLK_UNUSED)
goto out;
free(target);
err = vhd_parent_locator_get(&vhd, &target);
if (err)
goto out;
if (vhd_parent_raw(&vhd)) {
*parent_raw = 1;
goto out;
}
vhd_close(&vhd);
}
out:
vhd_close(&vhd);
if (err)
free(target);
else
*result = target;
return err;
}
static int
vhd_util_check_depth(const char *name, int *depth)
{
int err;
vhd_context_t vhd;
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY);
if (err)
return err;
err = vhd_chain_depth(&vhd, depth);
vhd_close(&vhd);
return err;
}
int
vhd_util_snapshot(int argc, char **argv)
{
vhd_flag_creat_t flags;
int c, err, prt_raw, limit;
char *name, *pname, *ppath, *backing;
uint64_t size;
vhd_context_t vhd;
name = NULL;
pname = NULL;
ppath = NULL;
backing = NULL;
size = 0;
flags = 0;
limit = 0;
if (!argc || !argv) {
err = -EINVAL;
goto usage;
}
optind = 0;
while ((c = getopt(argc, argv, "n:p:l:mh")) != -1) {
switch (c) {
case 'n':
name = optarg;
break;
case 'p':
pname = optarg;
break;
case 'l':
limit = strtol(optarg, NULL, 10);
break;
case 'm':
vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
break;
case 'h':
err = 0;
goto usage;
default:
err = -EINVAL;
goto usage;
}
}
if (!name || !pname || optind != argc) {
err = -EINVAL;
goto usage;
}
ppath = realpath(pname, NULL);
if (!ppath)
return -errno;
if (vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
backing = strdup(ppath);
if (!backing) {
err = -ENOMEM;
goto out;
}
} else {
err = vhd_util_find_snapshot_target(ppath, &backing, &prt_raw);
if (err) {
backing = NULL;
goto out;
}
/*
* if the sizes of the parent chain are non-uniform, we need to
* pick the right size: that of the supplied parent
*/
if (strcmp(ppath, backing)) {
err = vhd_open(&vhd, ppath, VHD_OPEN_RDONLY);
if (err)
goto out;
size = vhd.footer.curr_size;
vhd_close(&vhd);
}
if (prt_raw)
vhd_flag_set(flags, VHD_FLAG_CREAT_PARENT_RAW);
}
if (limit && !vhd_flag_test(flags, VHD_FLAG_CREAT_PARENT_RAW)) {
int depth;
err = vhd_util_check_depth(backing, &depth);
if (err)
printf("error checking snapshot depth: %d\n", err);
else if (depth + 1 > limit) {
err = -ENOSPC;
printf("snapshot depth exceeded: "
"current depth: %d, limit: %d\n", depth, limit);
}
if (err)
goto out;
}
err = vhd_snapshot(name, size, backing, flags);
out:
free(ppath);
free(backing);
return err;
usage:
printf("options: <-n name> <-p parent name> [-l snapshot depth limit]"
" [-m parent_is_raw] [-h help]\n");
return err;
}

View File

@ -0,0 +1,259 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Before updating a VHD file, we create a journal consisting of:
* - all data at the beginning of the file, up to and including the BAT
* - each allocated bitmap (existing at the same offset in the journal as
* its corresponding bitmap in the original file)
* Updates are performed in place by writing appropriately
* transformed versions of journaled bitmaps to the original file.
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include "atomicio.h"
#include "libvhd.h"
#include "libvhd-journal.h"
static void
usage(void)
{
printf("usage: vhd-update <-n name> [-j existing journal] [-h]\n");
exit(EINVAL);
}
/*
* update vhd creator version to reflect its new bitmap ordering
*/
static inline int
update_creator_version(vhd_journal_t *journal)
{
journal->vhd.footer.crtr_ver = VHD_VERSION(1, 1);
return vhd_write_footer(&journal->vhd, &journal->vhd.footer);
}
static int
journal_bitmaps(vhd_journal_t *journal)
{
int i, err;
for (i = 0; i < journal->vhd.bat.entries; i++) {
err = vhd_journal_add_block(journal, i, VHD_JOURNAL_METADATA);
if (err)
return err;
}
return 0;
}
/*
* older VHD bitmaps were little endian
* and bits within a word were set from right to left
*/
static inline int
old_test_bit(int nr, volatile void * addr)
{
return (((unsigned long*)addr)[nr/(sizeof(unsigned long)*8)] >>
(nr % (sizeof(unsigned long)*8))) & 1;
}
/*
* new VHD bitmaps are big endian
* and bits within a word are set from left to right
*/
#define BIT_MASK 0x80
static inline void
new_set_bit (int nr, volatile char *addr)
{
addr[nr >> 3] |= (BIT_MASK >> (nr & 7));
}
static void
convert_bitmap(char *in, char *out, int bytes)
{
int i;
memset(out, 0, bytes);
for (i = 0; i < bytes << 3; i++)
if (old_test_bit(i, (void *)in))
new_set_bit(i, out);
}
static int
update_vhd(vhd_journal_t *journal, int rollback)
{
int i, err;
size_t size;
char *buf, *converted;
buf = NULL;
converted = NULL;
size = vhd_bytes_padded(journal->vhd.spb / 8);
err = posix_memalign((void **)&converted, 512, size);
if (err) {
converted = NULL;
goto out;
}
for (i = 0; i < journal->vhd.bat.entries; i++) {
if (journal->vhd.bat.bat[i] == DD_BLK_UNUSED)
continue;
err = vhd_read_bitmap(&journal->vhd, i, &buf);
if (err)
goto out;
if (rollback)
memcpy(converted, buf, size);
else
convert_bitmap(buf, converted, size);
free(buf);
err = vhd_write_bitmap(&journal->vhd, i, converted);
if (err)
goto out;
}
err = 0;
out:
free(converted);
return err;
}
static int
open_journal(vhd_journal_t *journal, const char *file, const char *jfile)
{
int err;
err = vhd_journal_create(journal, file, jfile);
if (err) {
printf("error creating journal for %s: %d\n", file, err);
return err;
}
return 0;
}
static int
close_journal(vhd_journal_t *journal, int err)
{
if (err)
err = vhd_journal_revert(journal);
else
err = vhd_journal_commit(journal);
if (err)
return vhd_journal_close(journal);
else
return vhd_journal_remove(journal);
}
int
main(int argc, char **argv)
{
char *file, *jfile;
int c, err, rollback;
vhd_journal_t journal;
file = NULL;
jfile = NULL;
rollback = 0;
while ((c = getopt(argc, argv, "n:j:rh")) != -1) {
switch(c) {
case 'n':
file = optarg;
break;
case 'j':
jfile = optarg;
err = access(jfile, R_OK);
if (err == -1) {
printf("invalid journal arg %s\n", jfile);
return -errno;
}
break;
case 'r':
/* add a rollback option for debugging which
* pushes journalled bitmaps to original file
* without transforming them */
rollback = 1;
break;
default:
usage();
}
}
if (!file)
usage();
if (rollback && !jfile) {
printf("rollback requires a journal argument\n");
usage();
}
err = open_journal(&journal, file, jfile);
if (err)
return err;
if (!vhd_creator_tapdisk(&journal.vhd) ||
journal.vhd.footer.crtr_ver != VHD_VERSION(0, 1) ||
journal.vhd.footer.type == HD_TYPE_FIXED) {
err = 0;
goto out;
}
err = journal_bitmaps(&journal);
if (err) {
/* no changes to vhd file yet,
* so close the journal and bail */
vhd_journal_close(&journal);
return err;
}
err = update_vhd(&journal, rollback);
if (err) {
printf("update failed: %d; saving journal\n", err);
goto out;
}
err = update_creator_version(&journal);
if (err) {
printf("failed to udpate creator version: %d\n", err);
goto out;
}
err = 0;
out:
err = close_journal(&journal, err);
return err;
}

View File

@ -0,0 +1,160 @@
/* Copyright (c) 2008, XenSource Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of XenSource Inc. nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libvhd.h"
#include "vhd-util.h"
#if 1
#define DFPRINTF(_f, _a...) fprintf(stdout, _f , ##_a)
#else
#define DFPRINTF(_f, _a...) ((void)0)
#endif
typedef int (*vhd_util_func_t) (int, char **);
struct command {
char *name;
vhd_util_func_t func;
};
struct command commands[] = {
{ .name = "create", .func = vhd_util_create },
{ .name = "snapshot", .func = vhd_util_snapshot },
{ .name = "query", .func = vhd_util_query },
{ .name = "read", .func = vhd_util_read },
{ .name = "set", .func = vhd_util_set_field },
{ .name = "repair", .func = vhd_util_repair },
{ .name = "resize", .func = vhd_util_resize },
{ .name = "fill", .func = vhd_util_fill },
{ .name = "coalesce", .func = vhd_util_coalesce },
{ .name = "modify", .func = vhd_util_modify },
{ .name = "scan", .func = vhd_util_scan },
{ .name = "check", .func = vhd_util_check },
{ .name = "revert", .func = vhd_util_revert },
};
#define print_commands() \
do { \
int i, n; \
n = sizeof(commands) / sizeof(struct command); \
printf("COMMAND := { "); \
printf("%s", commands[0].name); \
for (i = 1; i < n; i++) \
printf(" | %s", commands[i].name); \
printf(" }\n"); \
} while (0)
TEST_FAIL_EXTERN_VARS;
void
help(void)
{
printf("usage: vhd-util COMMAND [OPTIONS]\n");
print_commands();
exit(0);
}
struct command *
get_command(char *command)
{
int i, n;
if (strnlen(command, 25) >= 25)
return NULL;
n = sizeof(commands) / sizeof (struct command);
for (i = 0; i < n; i++)
if (!strcmp(command, commands[i].name))
return &commands[i];
return NULL;
}
int
main(int argc, char *argv[])
{
char **cargv;
struct command *cmd;
int cargc, i, cnt, ret;
#ifdef CORE_DUMP
#include <sys/resource.h>
struct rlimit rlim;
rlim.rlim_cur = RLIM_INFINITY;
rlim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
fprintf(stderr, "setrlimit failed: %d\n", errno);
#endif
ret = 0;
if (argc < 2)
help();
cargc = argc - 1;
cmd = get_command(argv[1]);
if (!cmd) {
fprintf(stderr, "invalid COMMAND %s\n", argv[1]);
help();
}
cargv = malloc(sizeof(char *) * cargc);
if (!cargv)
exit(ENOMEM);
cnt = 1;
cargv[0] = cmd->name;
for (i = 1; i < cargc; i++) {
char *arg = argv[i + (argc - cargc)];
if (!strcmp(arg, "--debug")) {
libvhd_set_log_level(1);
continue;
}
cargv[cnt++] = arg;
}
#ifdef ENABLE_FAILURE_TESTING
for (i = 0; i < NUM_FAIL_TESTS; i++) {
TEST_FAIL[i] = 0;
if (getenv(ENV_VAR_FAIL[i]))
TEST_FAIL[i] = 1;
}
#endif // ENABLE_FAILURE_TESTING
ret = cmd->func(cnt, cargv);
free(cargv);
return (ret >= 0 ? ret : -ret);
}