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