method name = filename
end
+(* A linear offset/size from an underlying device. *)
+class offset_device name start size (dev : device) =
+object
+ inherit device
+ method name = name
+ method size = size
+ method read offset len =
+ if offset < 0L || len < 0 || offset +^ Int64.of_int len > size then
+ invalid_arg (
+ sprintf "%s: tried to read outside device boundaries (%Ld/%d/%Ld)"
+ name offset len size
+ );
+ dev#read (start+^offset) len
+end
+
(* The null device. Any attempt to read generates an error. *)
let null_device : device =
object
dom_name : string; (* Domain name. *)
dom_id : int option; (* Domain ID (if running). *)
dom_disks : disk list; (* Domain disks. *)
- dom_lv_filesystems : filesystem list; (* Domain LV filesystems. *)
+ dom_lv_filesystems :
+ (lv * filesystem) list; (* Domain LV filesystems. *)
}
and disk = {
(* From the XML ... *)
if not swap then name
else name ^ " [swap]"
+(* Convert a UUID (containing '-' chars) to canonical form. *)
+let canonical_uuid uuid =
+ let uuid' = String.make 32 ' ' in
+ let j = ref 0 in
+ for i = 0 to String.length uuid - 1 do
+ if !j >= 32 then
+ invalid_arg (sprintf (f_ "canonical_uuid: UUID is too long: %s") uuid);
+ let c = uuid.[i] in
+ if c <> '-' then ( uuid'.[!j] <- c; incr j )
+ done;
+ if !j <> 32 then
+ invalid_arg (sprintf (f_ "canonical_uuid: invalid UUID: %s") uuid);
+ uuid'
+
(* Register a partition scheme. *)
let partition_types = ref []
let partition_type_register (parts_name : string) probe_fn =
Note the very rare use of OOP in OCaml!
*)
-class block_device :
- string ->
+class block_device : string ->
object
method name : string
method read : int64 -> int -> string
end
(** A concrete device which just direct-maps a file or /dev device. *)
+class offset_device : string -> int64 -> int64 -> device ->
+ object
+ method name : string
+ method read : int64 -> int -> string
+ method read_bitstring : int64 -> int -> string * int * int
+ method size : int64
+ end
+ (** A concrete device which maps a linear part of an underlying device.
+
+ [new offset_device name start size dev] creates a new
+ device which maps bytes from [start] to [start+size-1]
+ of the underlying device [dev] (ie. in this device they
+ appear as bytes [0] to [size-1]).
+
+ Useful for things like partitions.
+ *)
+
val null_device : device
(** The null device. Any attempt to read generates an error. *)
dom_name : string; (** Domain name. *)
dom_id : int option; (** Domain ID (if running). *)
dom_disks : disk list; (** Domain disks. *)
- dom_lv_filesystems : filesystem list; (** Domain LV filesystems. *)
+ dom_lv_filesystems :
+ (lv * filesystem) list; (** Domain LV filesystems. *)
}
and disk = {
d_type : string option; (** The <disk type=...> *)
val string_of_filesystem : filesystem -> string
(** Convert a partition or filesystem struct to a string (for debugging). *)
+val canonical_uuid : string -> string
+(** Convert a UUID which may contain '-' characters to canonical form. *)
+
(** {2 Plug-in registration functions} *)
val partition_type_register : string -> (device -> partitions) -> unit
let lvs = group_by lvs in
let lvs =
- List.map (fun (pv, devs) -> list_lvs pv.lvm_plugin_id devs)
- lvs in
+ List.map (fun (pv, devs) -> list_lvs pv.lvm_plugin_id devs) lvs in
let lvs = List.concat lvs in
(* lvs is a list of potential LV devices. Now run them through the
*)
let filesystems =
List.filter_map (
- fun { lv_dev = dev } -> probe_for_filesystem dev
+ fun ({ lv_dev = dev } as lv) ->
+ match probe_for_filesystem dev with
+ | Some fs -> Some (lv, fs)
+ | None -> None
) lvs in
{ dom with dom_lv_filesystems = filesystems }
(* HOF to iterate over filesystems. *)
let iter_over_filesystems doms
- (f : domain -> ?disk:disk -> ?part:(partition * int) -> filesystem ->
+ (f : domain -> ?disk:disk -> ?partno:int -> device -> filesystem ->
unit) =
List.iter (
fun ({ dom_disks = disks; dom_lv_filesystems = filesystems } as dom) ->
(* Ordinary filesystems found on disks & partitions. *)
List.iter (
function
- | ({ d_content = `Filesystem fs } as disk) ->
- f dom ~disk fs
+ | ({ d_content = `Filesystem fs; d_dev = dev } as disk) ->
+ f dom ~disk dev fs
| ({ d_content = `Partitions partitions } as disk) ->
List.iteri (
fun i ->
function
- | ({ part_content = `Filesystem fs } as part) ->
- f dom ~disk ~part:(part, i) fs
+ | { part_content = `Filesystem fs; part_dev = dev } ->
+ f dom ~disk ~partno:(i+1) dev fs
| _ -> ()
) partitions.parts
| _ -> ()
) disks;
(* LV filesystems. *)
- List.iter (fun fs -> f dom fs) filesystems
+ List.iter (fun ({lv_dev = dev}, fs) -> f dom dev fs) filesystems
) doms
in
(* Print stats for each recognized filesystem. *)
- let print_stats dom ?disk ?part fs =
+ let print_stats dom ?disk ?partno dev fs =
(* Printable name is like "domain:hda" or "domain:hda1". *)
let name =
let dom_name = dom.dom_name in
+ (* Get the disk name (eg. "hda") from the domain XML, if
+ * we have it, otherwise use the device name (eg. for LVM).
+ *)
let disk_name =
match disk with
- | None -> "???" (* XXX keep LV dev around *)
+ | None -> dev#name
| Some disk -> disk.d_target
in
- match part with
+ match partno with
| None ->
dom_name ^ ":" ^ disk_name
- | Some (_, pnum) ->
- dom_name ^ ":" ^ disk_name ^ string_of_int pnum in
+ | Some partno ->
+ dom_name ^ ":" ^ disk_name ^ string_of_int partno in
printf "%-20s " name;
if fs.fs_is_swap then (