1 (** Diskimage library for reading disk images. *)
2 (* (C) Copyright 2007-2008 Richard W.M. Jones, Red Hat Inc.
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.
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.
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.
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 ... *)
31 (** {2 Device class and specialized subclasses} *)
33 class virtual device :
35 method virtual name : string
36 (** Return some printable name for the device. *)
38 method virtual size : Int63.t
39 (** Return the size of the device in bytes.
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.
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. *)
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).
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.
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. *)
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.
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). *)
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
85 Note this very rare use of OOP in OCaml!
88 class block_device : string -> 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. *)
100 (** A concrete device which just direct-maps a file or /dev device.
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. *)
106 class offset_device : string -> Int63.t -> Int63.t -> Int63.t -> device ->
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
116 (** A concrete device which maps a linear part of an underlying device.
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]).
123 Useful for things like partitions.
126 class blocksize_overlay : Int63.t -> device ->
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
136 (** Change the blocksize of an existing device. *)
138 val null_device : device
139 (** The null device. Any attempt to read generates an error. *)
142 {2 Structures used to describe machines, disks, partitions and filesystems}
144 {3 Machine/device model}
146 The "machine/device model" that we currently understand looks
152 \--- host partitions / disk image files
156 +--> guest partitions (eg. using MBR)
158 \-(1)->+--- filesystems (eg. ext3)
165 (1) Filesystems and PVs may also appear directly on guest
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.
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.
178 Swap space is considered to be a dumb filesystem for the purposes
183 m_name : string; (** Machine name. *)
184 m_disks : disk list; (** Machine disks. *)
186 (lv * filesystem) list; (** Machine LV filesystems. *)
188 (** A 'machine' is just a convenient holder for collections of disks. *)
191 d_name : string; (** Device name (eg "hda") *)
192 d_dev : block_device; (** Disk device. *)
193 d_content : disk_content; (** What's on it. *)
195 (** A single physical disk image. *)
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. *)
205 parts_cb : partitioner_callbacks; (** Partitioning scheme. *)
206 parts_dev : device; (** Partitions (whole) device. *)
207 parts : partition list; (** Partitions. *)
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. *)
215 (** Partitions as found on a disk image. *)
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. *)
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. *)
238 (** A filesystem, with superblock contents. *)
241 pv_cb : lvm_callbacks; (** The LVM plug-in which detected
243 pv_dev : device; (** Device covering whole PV. *)
244 pv_uuid : string; (** UUID. *)
247 lv_dev : device; (** Logical volume device. *)
249 (** Physical and logical volumes as used by LVM plug-ins. *)
251 and partitioner_callbacks
252 and filesystem_callbacks
257 val name_of_filesystem : filesystem -> string
258 (** [name_of_filesystem fs] returns a printable name for
262 (** {3 Create 'machine'} *)
264 val open_machine : string -> (string * string) list -> machine
265 (** [open_machine m_name devs]
266 creates a {!machine} containing the devices listed.
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.
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.
277 val open_machine_from_devices : string -> (string * block_device) list ->
279 (** This is the same as {!open_machine} except that instead
280 of passing a path you should pass a {!block_device} object. *)
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.
289 (** {3 Scanning for filesystems} *)
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.
296 This scans down to the level of the filesystem superblocks.
298 Returns an updated {!machine} structure with the scan results.
301 (** {3 Create ownership tables} *)
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).
311 [ `Filesystem of filesystem
312 | `Partitions of partitions
313 | `PhysicalVolume of pv ]
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].
321 [disk] must be a block device of the machine.
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].
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.
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.
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. *)
340 val offset_is_free : (owner * Int63.t) list -> bool
341 (** [offset_is_free owners] tests if the offset is free (unused).
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. *)
352 (** If set to true, functions emit debugging information to stderr. *)