open Printf
open ExtList
-open Unix
module C = Libvirt.Connect
module D = Libvirt.Domain
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,
"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,
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 =
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
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 *)
{ 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
) 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 (
)
)
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)