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. *)
37 method virtual size : int64
38 (** Return the size of the device in bytes.
40 Note: For some types of devices, the device may have
41 "holes", alignment requirements, etc. so this method doesn't
42 imply that every byte from [0..size-1] is readable. *)
43 method read : int64 -> int -> string
44 (** [read offset len] reads len bytes starting at offset.
46 Note: A default implementation is provided for [read],
47 but it is fairly inefficient because it uses {!mapblock} to
48 map each block in the request. *)
49 method read_bitstring : int64 -> int -> Bitmatch.bitstring
50 (** [read_bitstring] is the same as [read] but returns
51 a pa_bitmatch-style bitstring. *)
52 method virtual blocksize : int
53 (** [blocksize] returns the natural block size of the device. *)
54 method virtual mapblock : int64 -> (device * int64) list
55 (** [mapblock] describes how a block in this device is
56 mapped down to any underlying device(s).
58 Returns [[]] (empty list) if there is no underlying
59 device for this block. Otherwise returns a list of
60 [(device, byte-offset)] locations where this block is mapped.
62 Normally the returned list has length 1, but in cases
63 such as mirroring you can have the same block mapped
64 to several underlying devices. *)
67 A virtual (or physical!) device, encapsulating any translation
68 that has to be done to access the device. eg. For partitions
69 there is a simple offset, but for LVM you may need complicated
72 Note this very rare use of OOP in OCaml!
75 class block_device : string -> int ->
79 method read : int64 -> int -> string
80 method read_bitstring : int64 -> int -> Bitmatch.bitstring
81 method blocksize : int
82 method mapblock : int64 -> (device * int64) list
83 method close : unit -> unit
84 (** Close the device, freeing up the file descriptor. *)
86 (** A concrete device which just direct-maps a file or /dev device.
88 Create the device with [new block_device filename blocksize]
89 where [filename] is the path to the file or device and
90 [blocksize] is the blocksize of the device. *)
92 class offset_device : string -> int64 -> int64 -> int -> device ->
96 method read : int64 -> int -> string
97 method read_bitstring : int64 -> int -> Bitmatch.bitstring
98 method blocksize : int
99 method mapblock : int64 -> (device * int64) list
101 (** A concrete device which maps a linear part of an underlying device.
103 [new offset_device name start size blocksize dev] creates a new
104 device which maps bytes from [start] to [start+size-1]
105 of the underlying device [dev] (ie. in this device they
106 appear as bytes [0] to [size-1]).
108 Useful for things like partitions.
111 class blocksize_overlay : int -> device ->
115 method read : int64 -> int -> string
116 method read_bitstring : int64 -> int -> Bitmatch.bitstring
117 method blocksize : int
118 method mapblock : int64 -> (device * int64) list
120 (** Change the blocksize of an existing device. *)
122 val null_device : device
123 (** The null device. Any attempt to read generates an error. *)
126 {2 Structures used to describe machines, disks, partitions and filesystems}
128 {3 Machine/device model}
130 The "machine/device model" that we currently understand looks
136 \--- host partitions / disk image files
140 +--> guest partitions (eg. using MBR)
142 \-(1)->+--- filesystems (eg. ext3)
149 (1) Filesystems and PVs may also appear directly on guest
152 Partition schemes (eg. MBR) and filesystems register themselves
153 with this main module and they are queried first to get an idea
154 of the physical devices, partitions and filesystems potentially
155 available to the guest.
157 Volume management schemes (eg. LVM2) register themselves here
158 and are called later with "spare" physical devices and partitions
159 to see if they contain LVM data. If this results in additional
160 logical volumes then these are checked for filesystems.
162 Swap space is considered to be a dumb filesystem for the purposes
167 m_name : string; (** Machine name. *)
168 m_disks : disk list; (** Machine disks. *)
170 (lv * filesystem) list; (** Machine LV filesystems. *)
172 (** A 'machine' is just a convenient holder for collections of disks. *)
175 d_name : string; (** Device name (eg "hda") *)
176 d_dev : block_device; (** Disk device. *)
177 d_content : disk_content; (** What's on it. *)
179 (** A single physical disk image. *)
182 [ `Filesystem of filesystem (** Contains a direct filesystem. *)
183 | `Partitions of partitions (** Contains partitions. *)
184 | `PhysicalVolume of pv (** Contains an LVM PV. *)
185 | `Unknown (** Not probed or unknown. *)
189 parts_plugin_id : parts_plugin_id; (** Partitioning scheme. *)
190 parts : partition list; (** Partitions. *)
193 part_status : partition_status; (** Bootable, etc. *)
194 part_type : int; (** Partition filesystem type. *)
195 part_dev : device; (** Partition device. *)
196 part_content : partition_content; (** What's on it. *)
198 (** Partitions as found on a disk image. *)
200 and partition_status = Bootable | Nonbootable | Malformed | NullEntry
201 and partition_content =
202 [ `Filesystem of filesystem (** Filesystem. *)
203 | `PhysicalVolume of pv (** Contains an LVM PV. *)
204 | `Unknown (** Not probed or unknown. *)
208 fs_plugin_id : fs_plugin_id; (** Filesystem type. *)
209 fs_dev : device; (** Device containing the filesystem. *)
210 fs_blocksize : int; (** Block size (bytes). *)
211 fs_blocks_total : int64; (** Total blocks. *)
212 fs_is_swap : bool; (** If swap, following not valid. *)
213 fs_blocks_reserved : int64; (** Blocks reserved for super-user. *)
214 fs_blocks_avail : int64; (** Blocks free (available). *)
215 fs_blocks_used : int64; (** Blocks in use. *)
216 fs_inodes_total : int64; (** Total inodes. *)
217 fs_inodes_reserved : int64; (** Inodes reserved for super-user. *)
218 fs_inodes_avail : int64; (** Inodes free (available). *)
219 fs_inodes_used : int64; (** Inodes in use. *)
221 (** A filesystem, with superblock contents. *)
224 lvm_plugin_id : lvm_plugin_id; (** The LVM plug-in which detected
226 pv_uuid : string; (** UUID. *)
229 lv_dev : device; (** Logical volume device. *)
231 (** Physical and logical volumes as used by LVM plug-ins. *)
236 (** Opaque IDs used to refer to the plug-ins. *)
238 val name_of_parts : parts_plugin_id -> string
239 val name_of_filesystem : fs_plugin_id -> string
240 val name_of_lvm : lvm_plugin_id -> string
241 (** Convert plug-in IDs to printable strings. *)
243 (** {2 Scanning functions} *)
245 val open_machine : string -> (string * string) list -> machine
246 (** [open_machine m_name devs]
247 creates a {!machine} containing the devices listed.
249 [devs] is a list of pairs of [(name, path)] elements
250 where [name] is something like ["hda"] and [path]
251 is a path to a disk image or [/dev] device.
253 This function does not do any scanning, so all disk
254 contents are just set to [`Unknown] and there are no
255 LV filesystems in the returned structure.
258 val close_machine : machine -> unit
259 (** This is a convenience function which calls the [dev#close]
260 method on any open {!block_device}s owned by the machine. This just
261 has the effect of closing any file descriptors which are
262 opened by these devices.
265 val scan_machine : machine -> machine
266 (** This does a complete scan of all devices owned by a machine,
267 identifying all partitions, filesystems, physical and logical
268 volumes that are known to this library.
270 This scans down to the level of the filesystem superblocks.
272 Returns an updated {!machine} structure with the scan results.
278 (** If set to true, functions emit debugging information to stderr. *)