Skip to content

Commit 9c175d9

Browse files
author
David Scott
committed
Add xenvm host-dump <VG> <host> to dump the metadata volumes
This will create 2 files in the current directory: <host>-fromLVM <host>-toLVM Signed-off-by: David Scott <[email protected]>
1 parent 5038c14 commit 9c175d9

File tree

2 files changed

+65
-32
lines changed

2 files changed

+65
-32
lines changed

xenvm/lvdump.ml

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,39 @@ open Lwt
55
open Xenvm_common
66
open Errors
77

8+
module Vg_IO = Lvm.Vg.Make(Log)(Block)(Time)(Clock)
9+
10+
let to_file (vg_name, lv_name) local_device oc =
11+
with_block local_device
12+
(fun x ->
13+
Vg_IO.connect [ x ] `RO >>|= fun vg ->
14+
match Vg_IO.find vg lv_name with
15+
| None -> failwith (Printf.sprintf "Failed to find LV %s" lv_name)
16+
| Some vol ->
17+
Vg_IO.Volume.connect vol
18+
>>= function
19+
| `Error _ -> fail (Failure (Printf.sprintf "Failed to open %s" lv_name))
20+
| `Ok disk ->
21+
Vg_IO.Volume.get_info disk
22+
>>= fun info ->
23+
let buffer = Io_page.(to_cstruct (get 1024)) in
24+
let nsectors = Cstruct.len buffer / info.Vg_IO.Volume.sector_size in
25+
let rec loop = function
26+
| n when n = info.Vg_IO.Volume.size_sectors -> return ()
27+
| n ->
28+
let remaining = Int64.sub info.Vg_IO.Volume.size_sectors n in
29+
let toread = min (Int64.to_int remaining) nsectors in
30+
let buffer' = Cstruct.sub buffer 0 (toread * info.Vg_IO.Volume.sector_size) in
31+
Vg_IO.Volume.read disk n [ buffer' ]
32+
>>= function
33+
| `Ok () ->
34+
Lwt_io.write oc (Cstruct.to_string buffer')
35+
>>= fun () ->
36+
loop (Int64.(add n (of_int toread)))
37+
| _ -> failwith (Printf.sprintf "Failed to read sector %Ld" n) in
38+
loop 0L
39+
)
40+
841
let lvdump copts (vg_name, lv_name_opt) physical_device : unit =
942
let open Xenvm_common in
1043
let lv_name = match lv_name_opt with Some l -> l | None -> failwith "Need LV name" in
@@ -15,37 +48,8 @@ let lvdump copts (vg_name, lv_name_opt) physical_device : unit =
1548
| _, Some d -> d (* cmdline overrides default for the VG *)
1649
| Some info, None -> info.local_device (* If we've got a default, use that *)
1750
| None, None -> failwith "Need to know the local device!" in
18-
let module Vg_IO = Lvm.Vg.Make(Log)(Block)(Time)(Clock) in
19-
with_block local_device
20-
(fun x ->
21-
Vg_IO.connect [ x ] `RO >>|= fun vg ->
22-
match Vg_IO.find vg lv_name with
23-
| None -> failwith (Printf.sprintf "Failed to find LV %s" lv_name)
24-
| Some vol ->
25-
Vg_IO.Volume.connect vol
26-
>>= function
27-
| `Error _ -> fail (Failure (Printf.sprintf "Failed to open %s" lv_name))
28-
| `Ok disk ->
29-
Vg_IO.Volume.get_info disk
30-
>>= fun info ->
31-
let buffer = Io_page.(to_cstruct (get 1024)) in
32-
let nsectors = Cstruct.len buffer / info.Vg_IO.Volume.sector_size in
33-
let rec loop = function
34-
| n when n = info.Vg_IO.Volume.size_sectors -> return ()
35-
| n ->
36-
let remaining = Int64.sub info.Vg_IO.Volume.size_sectors n in
37-
let toread = min (Int64.to_int remaining) nsectors in
38-
let buffer' = Cstruct.sub buffer 0 (toread * info.Vg_IO.Volume.sector_size) in
39-
Vg_IO.Volume.read disk n [ buffer' ]
40-
>>= function
41-
| `Ok () ->
42-
Lwt_io.write Lwt_io.stdout (Cstruct.to_string buffer')
43-
>>= fun () ->
44-
loop (Int64.(add n (of_int toread)))
45-
| _ -> failwith (Printf.sprintf "Failed to read sector %Ld" n) in
46-
loop 0L
47-
)
48-
)
51+
to_file (vg_name, lv_name) local_device Lwt_io.stdout
52+
)
4953

5054
let lvdump_cmd =
5155
let doc = "Dump the physical contents of a logical volume" in

xenvm/xenvm.ml

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,23 @@ let host_disconnect copts (vg_name,_) uncooperative host =
184184
set_uri copts info;
185185
Client.Host.disconnect ~cooperative:(not uncooperative) ~name:host in
186186
Lwt_main.run t
187+
let host_dump copts (vg_name,_) physical_device host =
188+
let t =
189+
get_vg_info_t copts vg_name >>= fun info ->
190+
set_uri copts info;
191+
let local_device : string = match (info,physical_device) with
192+
| _, Some d -> d (* cmdline overrides default for the VG *)
193+
| Some info, None -> info.local_device (* If we've got a default, use that *)
194+
| None, None -> failwith "Need to know the local device!" in
195+
Client.Host.all ()
196+
>>= fun all ->
197+
let open Xenvm_interface in
198+
let h = List.find (fun h -> h.name = host) all in
199+
Lwt_io.with_file Lwt_io.Output h.toLVM.lv (Lvdump.to_file (vg_name, h.toLVM.lv) local_device)
200+
>>= fun () ->
201+
Lwt_io.with_file Lwt_io.Output h.fromLVM.lv (Lvdump.to_file (vg_name, h.fromLVM.lv) local_device) in
202+
Lwt_main.run t
203+
187204
let host_destroy copts (vg_name,_) host =
188205
let t =
189206
get_vg_info_t copts vg_name >>= fun info ->
@@ -399,6 +416,15 @@ let host_disconnect_cmd =
399416
Term.(pure host_disconnect $ copts_t $ name_arg $ uncooperative_flag $ hostname),
400417
Term.info "host-disconnect" ~sdocs:copts_sect ~doc ~man
401418

419+
let host_dump_cmd =
420+
let doc = "Dump a host's metadata volumes" in
421+
let man = [
422+
`S "DESCRIPTION";
423+
`P "Copy the contents of a host's metadata volumes to local files in the current directory for forensic analysis.";
424+
] in
425+
Term.(pure host_dump $ copts_t $ name_arg $ physical_device_arg $ hostname),
426+
Term.info "host-dump" ~sdocs:copts_sect ~doc ~man
427+
402428
let host_create_cmd =
403429
let doc = "Initialise a host's metadata volumes" in
404430
let man = [
@@ -462,7 +488,10 @@ let cmds = [
462488
dump_cmd;
463489
shutdown_cmd; host_create_cmd; host_destroy_cmd;
464490
host_list_cmd;
465-
host_connect_cmd; host_disconnect_cmd; benchmark_cmd;
491+
host_connect_cmd;
492+
host_disconnect_cmd;
493+
host_dump_cmd;
494+
benchmark_cmd;
466495
Lvcreate.lvcreate_cmd;
467496
Lvchange.lvchange_cmd;
468497
Vgchange.vgchange_cmd;

0 commit comments

Comments
 (0)