Can now use libvirt virDomainBlockPeek to access devices remotely
[virt-df.git] / lib / diskimage.mli
1 (** Diskimage library for reading disk images. *)
2 (* (C) Copyright 2007-2008 Richard W.M. Jones, Red Hat Inc.
3    http://libvirt.org/
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *)
19
20 (**
21    {2 Examples}
22
23 {[
24   let machine = open_machine "host" ["hda", "/dev/hda"] in
25   let machine = scan_machine machine in
26   (* do what you want with the scan results ... *)
27   close_machine machine
28 ]}
29 *)
30
31 (** {2 Device class and specialized subclasses} *)
32
33 class virtual device :
34   object
35     method virtual name : string
36       (** Return some printable name for the device. *)
37
38     method virtual size : Int63.t
39       (** Return the size of the device in bytes.
40
41           Note: For some types of devices, the device may have
42           "holes", alignment requirements, etc. so this method doesn't
43           imply that every byte from [0..size-1] is readable. *)
44     method read : Int63.t -> Int63.t -> string
45       (** [read offset len] reads len bytes starting at offset.
46
47           Note: A default implementation is provided for [read],
48           but it is fairly inefficient because it uses {!map_block} to
49           map each block in the request. *)
50     method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
51       (** [read_bitstring] is the same as [read] but returns
52           a pa_bitmatch-style bitstring. *)
53
54     method virtual blocksize : Int63.t
55       (** [blocksize] returns the natural block size of the device. *)
56     method virtual map_block : Int63.t -> (device * Int63.t) list
57       (** [map_block] describes how a block in this device is
58           mapped down to any underlying device(s).
59
60           Returns [[]] (empty list) if there is no underlying
61           device for this block.  Otherwise returns a list of
62           [(device, byte-offset)] locations where this block is mapped.
63
64           Normally the returned list has length 1, but in cases
65           such as mirroring you can have the same block mapped
66           to several underlying devices. *)
67
68     method virtual contiguous : Int63.t -> Int63.t
69       (** [contiguous offset] returns the number of contiguous
70           {i bytes} starting at byte [offset] on this device,
71           before (eg.) end of device or some discontinuity in
72           the mapping table occurs.
73
74           This method and {!map_block} allow callers to determine how
75           high level blocks map to low level disk images efficiently
76           (complex striping and interleaving patterns can make the
77           process much less efficient however). *)
78   end
79   (**
80      A virtual (or physical!) device, encapsulating any translation
81      that has to be done to access the device.  eg. For partitions
82      there is a simple offset, but for LVM you may need complicated
83      table lookups.
84      
85      Note this very rare use of OOP in OCaml!
86   *)
87
88 class block_device : string -> Int63.t ->
89   object
90     method name : string
91     method size : Int63.t
92     method read : Int63.t -> Int63.t -> string
93     method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
94     method blocksize : Int63.t
95     method map_block : Int63.t -> (device * Int63.t) list
96     method contiguous : Int63.t -> Int63.t
97     method close : unit -> unit
98       (** Close the device, freeing up the file descriptor. *)
99   end
100     (** A concrete device which just direct-maps a file or /dev device.
101
102         Create the device with [new block_device filename blocksize]
103         where [filename] is the path to the file or device and
104         [blocksize] is the blocksize of the device. *)
105
106 class offset_device : string -> Int63.t -> Int63.t -> Int63.t -> device ->
107   object
108     method name : string
109     method size : Int63.t
110     method read : Int63.t -> Int63.t -> string
111     method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
112     method blocksize : Int63.t
113     method map_block : Int63.t -> (device * Int63.t) list
114     method contiguous : Int63.t -> Int63.t
115   end
116     (** A concrete device which maps a linear part of an underlying device.
117
118         [new offset_device name start size blocksize dev] creates a new
119         device which maps bytes from [start] to [start+size-1]
120         of the underlying device [dev] (ie. in this device they
121         appear as bytes [0] to [size-1]).
122
123         Useful for things like partitions.
124     *)
125
126 class blocksize_overlay : Int63.t -> device ->
127   object
128     method name : string
129     method size : Int63.t
130     method read : Int63.t -> Int63.t -> string
131     method read_bitstring : Int63.t -> Int63.t -> Bitmatch.bitstring
132     method blocksize : Int63.t
133     method contiguous : Int63.t -> Int63.t
134     method map_block : Int63.t -> (device * Int63.t) list
135   end
136     (** Change the blocksize of an existing device. *)
137
138 val null_device : device
139     (** The null device.  Any attempt to read generates an error. *)
140
141 (**
142    {2 Structures used to describe machines, disks, partitions and filesystems}
143
144    {3 Machine/device model}
145
146    The "machine/device model" that we currently understand looks
147    like this:
148
149 {v
150 machines
151   |
152   \--- host partitions / disk image files
153          ||
154        guest block devices
155          |
156          +--> guest partitions (eg. using MBR)
157          |      |
158          \-(1)->+--- filesystems (eg. ext3)
159                 |
160                 \--- PVs for LVM
161                        |||
162                      VGs and LVs
163 v}
164
165    (1) Filesystems and PVs may also appear directly on guest
166    block devices.
167
168    Partition schemes (eg. MBR) and filesystems register themselves
169    with this main module and they are queried first to get an idea
170    of the physical devices, partitions and filesystems potentially
171    available to the guest.
172
173    Volume management schemes (eg. LVM2) register themselves here
174    and are called later with "spare" physical devices and partitions
175    to see if they contain LVM data.  If this results in additional
176    logical volumes then these are checked for filesystems.
177
178    Swap space is considered to be a dumb filesystem for the purposes
179    of this discussion.
180 *)
181
182 type machine = {
183   m_name : string;                      (** Machine name. *)
184   m_disks : disk list;                  (** Machine disks. *)
185   m_lv_filesystems :
186     (lv * filesystem) list;             (** Machine LV filesystems. *)
187 }
188     (** A 'machine' is just a convenient holder for collections of disks. *)
189
190 and disk = {
191   d_name : string;                      (** Device name (eg "hda") *)
192   d_dev : block_device;                 (** Disk device. *)
193   d_content : disk_content;             (** What's on it. *)
194 }
195     (** A single physical disk image. *)
196
197 and disk_content =
198     [ `Filesystem of filesystem         (** Contains a direct filesystem. *)
199     | `Partitions of partitions         (** Contains partitions. *)
200     | `PhysicalVolume of pv             (** Contains an LVM PV. *)
201     | `Unknown                          (** Not probed or unknown. *)
202     ]
203
204 and partitions = {
205   parts_cb : partitioner_callbacks;     (** Partitioning scheme. *)
206   parts_dev : device;                   (** Partitions (whole) device. *)
207   parts : partition list;               (** Partitions. *)
208 }
209 and partition = {
210   part_status : partition_status;       (** Bootable, etc. *)
211   part_type : int;                      (** Partition filesystem type. *)
212   part_dev : device;                    (** Partition device. *)
213   part_content : partition_content;     (** What's on it. *)
214 }
215     (** Partitions as found on a disk image. *)
216
217 and partition_status = Bootable | Nonbootable | Malformed | NullEntry
218 and partition_content =
219     [ `Filesystem of filesystem         (** Filesystem. *)
220     | `PhysicalVolume of pv             (** Contains an LVM PV. *)
221     | `Unknown                          (** Not probed or unknown. *)
222     ]
223
224 and filesystem = {
225   fs_cb : filesystem_callbacks;         (** Filesystem type. *)
226   fs_dev : device;                      (** Device containing the filesystem. *)
227   fs_blocksize : Int63.t;               (** Block size (bytes). *)
228   fs_blocks_total : Int63.t;            (** Total blocks. *)
229   fs_is_swap : bool;                    (** If swap, following not valid. *)
230   fs_blocks_reserved : Int63.t;         (** Blocks reserved for super-user. *)
231   fs_blocks_avail : Int63.t;            (** Blocks free (available). *)
232   fs_blocks_used : Int63.t;             (** Blocks in use. *)
233   fs_inodes_total : Int63.t;            (** Total inodes. *)
234   fs_inodes_reserved : Int63.t;         (** Inodes reserved for super-user. *)
235   fs_inodes_avail : Int63.t;            (** Inodes free (available). *)
236   fs_inodes_used : Int63.t;             (** Inodes in use. *)
237 }
238     (** A filesystem, with superblock contents. *)
239
240 and pv = {
241   pv_cb : lvm_callbacks;                (** The LVM plug-in which detected
242                                             this. *)
243   pv_dev : device;                      (** Device covering whole PV. *)
244   pv_uuid : string;                     (** UUID. *)
245 }
246 and lv = {
247   lv_dev : device;                      (** Logical volume device. *)
248 }
249     (** Physical and logical volumes as used by LVM plug-ins. *)
250
251 and partitioner_callbacks
252 and filesystem_callbacks
253 and lvm_callbacks
254
255 (** {2 Functions} *)
256
257 val name_of_filesystem : filesystem -> string
258   (** [name_of_filesystem fs] returns a printable name for
259       the filesystem.
260   *)
261
262 (** {3 Create 'machine'} *)
263
264 val open_machine : string -> (string * string) list -> machine
265   (** [open_machine m_name devs]
266       creates a {!machine} containing the devices listed.
267
268       [devs] is a list of pairs of [(name, path)] elements
269       where [name] is something like ["hda"] and [path]
270       is a path to a disk image or [/dev] device.
271
272       This function does not do any scanning, so all disk
273       contents are just set to [`Unknown] and there are no
274       LV filesystems in the returned structure.
275   *)
276
277 val open_machine_from_devices : string -> (string * block_device) list ->
278   machine
279   (** This is the same as {!open_machine} except that instead
280       of passing a path you should pass a {!block_device} object. *)
281
282 val close_machine : machine -> unit
283   (** This is a convenience function which calls the [dev#close]
284       method on any open {!block_device}s owned by the machine.  This just
285       has the effect of closing any file descriptors which are
286       opened by these devices.
287   *)
288
289 (** {3 Scanning for filesystems} *)
290
291 val scan_machine : machine -> machine
292   (** This does a complete scan of all devices owned by a machine,
293       identifying all partitions, filesystems, physical and logical
294       volumes that are known to this library.
295
296       This scans down to the level of the filesystem superblocks.
297
298       Returns an updated {!machine} structure with the scan results.
299   *)
300
301 (** {3 Create ownership tables} *)
302
303 type ownership
304
305 val create_ownership : machine -> ownership
306   (** This creates the ownership tables (mapping disk blocks to the
307       ultimate filesystem, etc., which owns each one).
308   *)
309
310 type owner =
311     [ `Filesystem of filesystem
312     | `Partitions of partitions
313     | `PhysicalVolume of pv ]
314
315 val get_owners_lookup : machine -> ownership -> block_device ->
316   (Int63.t -> (owner * Int63.t) list)
317   (** [get_owners_lookup machine disk] returns a specialized
318       function for looking up owners (filesystems, etc.)
319       which reside on block device [disk].
320
321       [disk] must be a block device of the machine.
322
323       The specialized lookup function that is returned
324       can be called as [lookup offset] to look up the
325       owners of byte offset [offset].
326
327       Returns a list of [(owner, owner_offset)] where [owner]
328       is the filesystem, etc., and [owner_offset] is the byte
329       offset relative to the owner.
330
331       It is common for there to be multiple owners: for example
332       in the case where a filesystem is created on a partition,
333       both the filesystem ([`Filesystem fs]) and
334       partition scheme ([`Partitions parts]) will be returned.
335
336       The specialized function is efficient.  {!create_ownership}
337       creates a tree structure which allows ownership to be determined
338       in just a few steps. *)
339
340 val offset_is_free : (owner * Int63.t) list -> bool
341   (** [offset_is_free owners] tests if the offset is free (unused).
342
343       If an offset is free, then it may be discarded without
344       changing the semantics of the disk image.  In normal cases
345       this extends to the end of the current block, but blocksize
346       will differ for each owner, so what this really means is
347       tricky in practice. *)
348
349 (** {2 Debugging} *)
350
351 val debug : bool ref
352   (** If set to true, functions emit debugging information to stderr. *)