X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=virt-df%2Fvirt_df_lvm2.ml;h=fcf1fd2b1ffe020eee42464aa5c76f785ad653b1;hb=81294675f6a5058a3381871f1dc99c806922d77c;hp=93555972d9c5d047b7558dfa5dcf1e985a07019c;hpb=bb0788a39d9b8675db60a61ecd2baebfdfb5ca10;p=virt-top.git diff --git a/virt-df/virt_df_lvm2.ml b/virt-df/virt_df_lvm2.ml index 9355597..fcf1fd2 100644 --- a/virt-df/virt_df_lvm2.ml +++ b/virt-df/virt_df_lvm2.ml @@ -24,41 +24,120 @@ open Printf open Virt_df_gettext.Gettext open Virt_df +open Virt_df_lvm2_metadata + +let plugin_name = "LVM2" + let sector_size = 512 let sector_size64 = 512L -let pv_label_offset = sector_size64 - -(* Probe to see if it's an LVM2 PV. Look for the "LABELONE" label. *) -let rec probe_pv dev = - try ignore (read_pv_label dev); true - with _ -> false +(* Probe to see if it's an LVM2 PV. *) +let rec probe_pv lvm_plugin_id dev = + try + let uuid, _ = read_pv_label dev in + if debug then + eprintf "LVM2 detected PV UUID %s\n%!" uuid; + { lvm_plugin_id = lvm_plugin_id; pv_uuid = uuid } + with exn -> + if debug then prerr_endline (Printexc.to_string exn); + raise Not_found and read_pv_label dev = - (* Load the second sector. *) - let bits = dev#read_bitstring pv_label_offset sector_size in + (* Load the first 8 sectors. I found by experimentation that + * the second sector contains the header ("LABELONE" etc) and + * the nineth sector contains some additional information about + * the location of the current metadata. + *) + let bits = dev#read_bitstring 0L (9 * sector_size) in - Bitmatch.hexdump_bitstring stdout bits; + (*Bitmatch.hexdump_bitstring stdout bits;*) bitmatch bits with - | labelone : 8*8 : bitstring; (* "LABELONE" *) - padding : 16*8 : bitstring; + | sector0 : sector_size*8 : bitstring; (* sector 0 *) + labelone : 8*8 : bitstring; (* "LABELONE" *) + padding : 16*8 : bitstring; (* Seems to contain something. *) lvm2_ver : 8*8 : bitstring; (* "LVM2 001" *) - uuid : 32*8 : bitstring (* UUID *) + uuid : 32*8 : bitstring; (* UUID *) + padding2 : (sector_size-64)*8 : bitstring; (* to end of second sector *) + sector234567 : sector_size*8 * 6 : bitstring; (* sectors 2-6 *) + padding3 : 0x28*8 : bitstring; (* start of sector 8 *) + metadata_offset : 32 : littleendian;(* metadata offset *) + padding4 : 4*8 : bitstring; + metadata_length : 32 : littleendian (* length of metadata (bytes) *) when Bitmatch.string_of_bitstring labelone = "LABELONE" && - Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> - uuid + Bitmatch.string_of_bitstring lvm2_ver = "LVM2 001" -> + + (* Metadata offset is relative to end of PV label. *) + let metadata_offset = metadata_offset +* 0x1000_l in + (* Metadata length appears to include the trailing \000 which + * we don't want. + *) + let metadata_length = metadata_length -* 1_l in + + let metadata = read_metadata dev metadata_offset metadata_length in + + let uuid = Bitmatch.string_of_bitstring uuid in + + uuid, metadata + | _ -> - invalid_arg (sprintf "read_pv_label: %s: not an LVM2 physical volume" - dev#name) + invalid_arg + (sprintf "LVM2: read_pv_label: %s: not an LVM2 physical volume" dev#name) + +and read_metadata dev offset32 len32 = + if debug then + eprintf "metadata: offset 0x%lx len %ld bytes\n%!" offset32 len32; + + (* Check the offset and length are sensible. *) + let offset64 = + if offset32 <= Int32.max_int then Int64.of_int32 offset32 + else invalid_arg "LVM2: read_metadata: metadata offset too large" in + let len64 = + if len32 <= 2_147_483_647_l then Int64.of_int32 len32 + else invalid_arg "LVM2: read_metadata: metadata length too large" in + + if offset64 <= 0x1200L || offset64 >= dev#size + || len64 <= 0L || offset64 +^ len64 >= dev#size then + invalid_arg "LVM2: read_metadata: bad metadata offset or length"; + + (* If it is outside the disk boundaries, this will throw an exception, + * otherwise it will read and return the metadata string. + *) + dev#read offset64 (Int64.to_int len64) (* We are passed a list of devices which we previously identified * as PVs belonging to us. From these produce a list of all LVs * (as devices) and return them. Note that we don't try to detect * what is on these LVs - that will be done in the main code. *) -let list_lvs devs = [] +let rec list_lvs devs = + (* Read the UUID and metadata (again) from each device to end up with + * an assoc list of PVs, keyed on the UUID. + *) + let pvs = List.map read_pv_label devs in + + (* Parse the metadata using the external lexer/parser. *) + let pvs = List.map ( + fun (uuid, metadata) -> + eprintf "parsing: %s\n<<<<\n" metadata; + uuid, Virt_df_lvm2_lexer.parse_lvm2_metadata_from_string metadata + ) pvs in + + (* Print the parsed metadata. *) + List.iter ( + fun (uuid, metadata) -> + eprintf "metadata for UUID %s:\n" uuid; + output_metadata stderr metadata + ) pvs; + + [] + + + + + + (* Register with main code. *) let () = - lvm_type_register "LVM2" probe_pv list_lvs + lvm_type_register plugin_name probe_pv list_lvs