X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=virt-df%2Fvirt_df_main.ml;h=2a97d5e391f3a859c4457945dae29812c661f9d3;hb=fc96d842a5276a27f528fbfb382b8a4afaeb2819;hp=1895aee985ef70f3fc81b9edc4d2624dab874c76;hpb=ba79ebe073b88ef611dea4e508d96962a65101b1;p=virt-df.git diff --git a/virt-df/virt_df_main.ml b/virt-df/virt_df_main.ml index 1895aee..2a97d5e 100644 --- a/virt-df/virt_df_main.ml +++ b/virt-df/virt_df_main.ml @@ -19,7 +19,6 @@ open Printf open ExtList -open Unix module C = Libvirt.Connect module D = Libvirt.Domain @@ -41,9 +40,7 @@ let () = exit 0 in - let test_mode filename = - test_files := filename :: !test_files - in + let test_mode filename = test_files := filename :: !test_files in let argspec = Arg.align [ "-a", Arg.Set all, @@ -54,6 +51,8 @@ let () = "uri " ^ s_ "Connect to URI (default: Xen)"; "--connect", Arg.String set_uri, "uri " ^ s_ "Connect to URI (default: Xen)"; + "--csv", Arg.Set csv_mode, + " " ^ s_ "Write results in CSV format"; "--debug", Arg.Set debug, " " ^ s_ "Debug mode (default: false)"; "-h", Arg.Set human, @@ -81,6 +80,19 @@ OPTIONS" in Arg.parse argspec anon_fun usage_msg; + (* Set up CSV support. *) + let csv_write = + if not !csv_mode then + fun _ -> assert false (* Should never happen. *) + else + match !csv_write with + | None -> + prerr_endline (s_ "CSV is not supported in this build of virt-df"); + exit 1 + | Some csv_write -> + csv_write stdout + in + let doms : domain list = if !test_files = [] then ( let xmls = @@ -92,7 +104,7 @@ OPTIONS" in Libvirt.Virterror err -> prerr_endline (Libvirt.Virterror.to_string err); (* If non-root and no explicit connection URI, print a warning. *) - if geteuid () <> 0 && name = None then ( + if Unix.geteuid () <> 0 && name = None then ( print_endline (s_ "NB: If you want to monitor a local Xen hypervisor, you usually need to be root"); ); exit 1 in @@ -215,8 +227,9 @@ OPTIONS" in d_dev = dev; d_content = `Unknown } with - Unix_error (err, func, param) -> - eprintf "%s:%s: %s" func param (error_message err); + Unix.Unix_error (err, func, param) -> + eprintf "%s:%s: %s" func param + (Unix.error_message err); None ) | _ -> None (* ignore anything else *) @@ -381,18 +394,21 @@ OPTIONS" in { dom with dom_lv_filesystems = filesystems } ) doms in - (* Now print the results. - * - * Print the title. - *) + (*----------------------------------------------------------------------*) + (* Now print the results. *) + + (* Print the title. *) let () = let total, used, avail = match !inodes, !human with | false, false -> s_ "1K-blocks", s_ "Used", s_ "Available" | false, true -> s_ "Size", s_ "Used", s_ "Available" | true, _ -> s_ "Inodes", s_ "IUse", s_ "IFree" in - printf "%-32s %10s %10s %10s %s\n%!" - (s_ "Filesystem") total used avail (s_ "Type") in + if not !csv_mode then + printf "%-32s %10s %10s %10s %s\n%!" + (s_ "Filesystem") total used avail (s_ "Type") + else + csv_write [ "Filesystem"; total; used; avail; "Type" ] in let printable_size bytes = if bytes < 1024L *^ 1024L then @@ -429,24 +445,27 @@ OPTIONS" in ) doms in + (* Printable name is like "domain:hda" or "domain:hda1". *) + let printable_name dom ?disk ?partno dev = + 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 -> dev#name + | Some disk -> disk.d_target + in + match partno with + | None -> + dom_name ^ ":" ^ disk_name + | Some partno -> + dom_name ^ ":" ^ disk_name ^ string_of_int partno + in + (* Print stats for each recognized filesystem. *) 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 -> dev#name - | Some disk -> disk.d_target - in - match partno with - | None -> - dom_name ^ ":" ^ disk_name - | Some partno -> - dom_name ^ ":" ^ disk_name ^ string_of_int partno in + let name = printable_name dom ?disk ?partno dev in printf "%-32s " name; if fs.fs_is_swap then ( @@ -485,4 +504,40 @@ OPTIONS" in ) ) in - iter_over_filesystems doms print_stats + + (* Alternate version of print_stats which writes to a CSV file. + * We ignore the human-readable option because we assume that + * the data will be post-processed by something. + *) + let print_stats_csv dom ?disk ?partno dev fs = + let name = printable_name dom ?disk ?partno dev in + + let row = + if fs.fs_is_swap then + (* Swap partition. *) + [ Int64.to_string (fs.fs_block_size *^ fs.fs_blocks_total /^ 1024L); + ""; "" ] + else ( + (* Ordinary filesystem. *) + if not !inodes then ( (* Block display. *) + (* 'df' doesn't count the restricted blocks. *) + let blocks_total = fs.fs_blocks_total -^ fs.fs_blocks_reserved in + let blocks_avail = fs.fs_blocks_avail -^ fs.fs_blocks_reserved in + let blocks_avail = if blocks_avail < 0L then 0L else blocks_avail in + + [ Int64.to_string (blocks_total *^ fs.fs_block_size /^ 1024L); + Int64.to_string (fs.fs_blocks_used *^ fs.fs_block_size /^ 1024L); + Int64.to_string (blocks_avail *^ fs.fs_block_size /^ 1024L) ] + ) else ( (* Inodes display. *) + [ Int64.to_string fs.fs_inodes_total; + Int64.to_string fs.fs_inodes_used; + Int64.to_string fs.fs_inodes_avail ] + ) + ) in + + let row = name :: row @ [fs.fs_name] in + csv_write row + in + + iter_over_filesystems doms + (if not !csv_mode then print_stats else print_stats_csv)