Updated deps for i386.
[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_plugin_id : parts_plugin_id;    (** 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_plugin_id : fs_plugin_id;          (** 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   lvm_plugin_id : lvm_plugin_id;        (** 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 parts_plugin_id
252 and fs_plugin_id
253 and lvm_plugin_id
254   (** Opaque IDs used to refer to the plug-ins. *)
255
256 val name_of_parts : parts_plugin_id -> string
257 val name_of_filesystem : fs_plugin_id -> string
258 val name_of_lvm : lvm_plugin_id -> string
259   (** Convert plug-in IDs to printable strings. *)
260
261 (** {2 Functions} *)
262
263 (** {3 Create 'machine'} *)
264
265 val open_machine : string -> (string * string) list -> machine
266   (** [open_machine m_name devs]
267       creates a {!machine} containing the devices listed.
268
269       [devs] is a list of pairs of [(name, path)] elements
270       where [name] is something like ["hda"] and [path]
271       is a path to a disk image or [/dev] device.
272
273       This function does not do any scanning, so all disk
274       contents are just set to [`Unknown] and there are no
275       LV filesystems in the returned structure.
276   *)
277
278 val close_machine : machine -> unit
279   (** This is a convenience function which calls the [dev#close]
280       method on any open {!block_device}s owned by the machine.  This just
281       has the effect of closing any file descriptors which are
282       opened by these devices.
283   *)
284
285 (** {3 Scanning for filesystems} *)
286
287 val scan_machine : machine -> machine
288   (** This does a complete scan of all devices owned by a machine,
289       identifying all partitions, filesystems, physical and logical
290       volumes that are known to this library.
291
292       This scans down to the level of the filesystem superblocks.
293
294       Returns an updated {!machine} structure with the scan results.
295   *)
296
297 (** {3 Create ownership tables} *)
298
299 type ownership
300
301 val create_ownership : machine -> ownership
302   (** This creates the ownership tables (mapping disk blocks to the
303       ultimate filesystem, etc., which owns each one).
304   *)
305
306 type owner =
307     [ `Filesystem of filesystem
308     | `Partitions of partitions
309     | `PhysicalVolume of pv ]
310
311 val get_owners_lookup : machine -> ownership -> block_device ->
312   (Int63.t -> (owner * Int63.t) list)
313   (** [get_owners_lookup machine disk] returns a specialized
314       function for looking up owners (filesystems, etc.)
315       which reside on block device [disk].
316
317       [disk] must be a block device of the machine.
318
319       The specialized lookup function that is returned
320       can be called as [lookup offset] to look up the
321       owners of byte offset [offset].
322
323       Returns a list of [(owner, owner_offset)] where [owner]
324       is the filesystem, etc., and [owner_offset] is the byte
325       offset relative to the owner.
326
327       It is common for there to be multiple owners: for example
328       in the case where a filesystem is created on a partition,
329       both the filesystem ([`Filesystem fs]) and
330       partition scheme ([`Partitions parts]) will be returned.
331
332       The specialized function is efficient.  {!create_ownership}
333       creates a tree structure which allows ownership to be determined
334       in just a few steps. *)
335
336 (** {2 Debugging} *)
337
338 val debug : bool ref
339   (** If set to true, functions emit debugging information to stderr. *)