Internationalize virt-df program.
[virt-top.git] / virt-df / virt_df.ml
index f583025..4fbc706 100644 (file)
@@ -1,11 +1,28 @@
 (* 'df' command for virtual domains.
+   (C) Copyright 2007-2008 Richard W.M. Jones, Red Hat Inc.
+   http://libvirt.org/
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *)
 
 open Printf
 open ExtList
-
 open Unix
 
+open Virt_df_gettext.Gettext
+
 module C = Libvirt.Connect
 module D = Libvirt.Domain
 module N = Libvirt.Network
@@ -21,6 +38,7 @@ let (/^) = Int64.div
 let uri = ref None
 let inodes = ref false
 let human = ref false
+let all = ref false
 
 (* Maximum number of extended partitions possible. *)
 let max_extended_partitions = 100
@@ -88,7 +106,7 @@ let rec probe_device dom_name target source =
   let size = (LargeFile.fstat fd).LargeFile.st_size in
   let size = size /^ sector_size in    (* Size in sectors. *)
 
-  print_device dom_name target source size;
+  (*print_device dom_name target source size;*)
 
   let partitions = probe_mbr fd in
 
@@ -108,9 +126,9 @@ let rec probe_device dom_name target source =
            None
       ) partitions in
     let stats = List.filter_map (fun x -> x) stats in
-    print_stats stats
+    print_stats dom_name stats
   ) else            (* Not an MBR, assume it's a single partition. *)
-    print_stats [target, probe_partition target None fd 0L size];
+    print_stats dom_name [target, probe_partition target None fd 0L size];
 
   close fd
 
@@ -128,7 +146,7 @@ and probe_mbr fd =
     lseek fd 446 SEEK_SET;
     let str = String.create 64 in
     if read fd str 0 64 <> 64 then
-      failwith "error reading partition table"
+      failwith (s_ "error reading partition table")
     else (
       (* Extract partitions from the data. *)
       let primaries = List.map (get_partition str) [ 0; 16; 32; 48 ] in
@@ -161,13 +179,13 @@ and probe_extended_partition max fd epart sect =
       LargeFile.lseek fd (ebr_offs +^ 446L) SEEK_SET;
       let str = String.create 32 in
       if read fd str 0 32 <> 32 then
-       failwith "error reading extended partition"
+       failwith (s_ "error reading extended partition")
       else (
        (* Extract partitions from the data. *)
        let part1, part2 =
          match List.map (get_partition str) [ 0; 16 ] with
          | [p1;p2] -> p1,p2
-         | _ -> failwith "probe_extended_partition: internal error" in
+         | _ -> failwith (s_ "probe_extended_partition: internal error") in
        (* First partition entry has offset to the start of this partition. *)
        let part1 = { part1 with
                        part_lba_start = sect +^ part1.part_lba_start } in
@@ -215,7 +233,7 @@ and get_partition str offs =
 and probe_partition target part_type fd start size =
   match part_type with
   | None ->
-      ProbeFailed "detection of unpartitioned devices not yet supported"
+      ProbeFailed (s_ "detection of unpartitioned devices not yet supported")
   | Some 0x05 ->
       ProbeIgnore (* Extended partition - ignore it. *)
   | Some part_type ->
@@ -225,59 +243,61 @@ and probe_partition target part_type fd start size =
       with
        Not_found ->
          ProbeFailed
-           (sprintf "unsupported partition type %02x" part_type)
+           (sprintf (f_ "unsupported partition type %02x") part_type)
 
-and print_stats statss =
+and print_stats dom_name statss =
   List.iter (
-    function
-    (* Swap partition. *)
-    | (target, Swap { swap_name = swap_name;
-                     swap_block_size = block_size;
-                     swap_blocks_total = blocks_total }) ->
-       if not !human then
-         printf "\t%s %Ld %s\n"
-           target (block_size *^ blocks_total /^ 1024L) swap_name
-       else
-         printf "\t%s %s %s\n"
-           target (printable_size (block_size *^ blocks_total)) swap_name
-
-    (* Ordinary filesystem. *)
-    | (target, Filesystem stats) ->
-       printf "\t%s " target;
-
-       if not !inodes then (           (* Block display. *)
-         (* 'df' doesn't count the restricted blocks. *)
-         let blocks_total =
-           stats.fs_blocks_total -^ stats.fs_blocks_reserved in
-         let blocks_avail =
-           stats.fs_blocks_avail -^ stats.fs_blocks_reserved in
-         let blocks_avail =
-           if blocks_avail < 0L then 0L else blocks_avail in
-
-         if not !human then (          (* Display 1K blocks. *)
-           printf "%Ld %Ld %Ld %s\n"
-             (blocks_total *^ stats.fs_block_size /^ 1024L)
-             (stats.fs_blocks_used *^ stats.fs_block_size /^ 1024L)
-             (blocks_avail *^ stats.fs_block_size /^ 1024L)
-             stats.fs_name
-         ) else (                      (* Human-readable blocks. *)
-           printf "%s %s %s %s\n"
-             (printable_size (blocks_total *^ stats.fs_block_size))
-             (printable_size (stats.fs_blocks_used *^ stats.fs_block_size))
-             (printable_size (blocks_avail *^ stats.fs_block_size))
+    fun (target, fs_probe_t) ->
+      let dom_target = dom_name ^ ":" ^ target in
+      printf "%-20s " dom_target;
+
+      match fs_probe_t with
+      (* Swap partition. *)
+      | Swap { swap_name = swap_name;
+              swap_block_size = block_size;
+              swap_blocks_total = blocks_total } ->
+         if not !human then
+           printf "%10Ld                       %s\n"
+             (block_size *^ blocks_total /^ 1024L) swap_name
+         else
+           printf "%10s                       %s\n"
+             (printable_size (block_size *^ blocks_total)) swap_name
+
+      (* Ordinary filesystem. *)
+      | Filesystem stats ->
+         if not !inodes then (         (* Block display. *)
+           (* 'df' doesn't count the restricted blocks. *)
+           let blocks_total =
+             stats.fs_blocks_total -^ stats.fs_blocks_reserved in
+           let blocks_avail =
+             stats.fs_blocks_avail -^ stats.fs_blocks_reserved in
+           let blocks_avail =
+             if blocks_avail < 0L then 0L else blocks_avail in
+
+           if not !human then (        (* Display 1K blocks. *)
+             printf "%10Ld %10Ld %10Ld %s\n"
+               (blocks_total *^ stats.fs_block_size /^ 1024L)
+               (stats.fs_blocks_used *^ stats.fs_block_size /^ 1024L)
+               (blocks_avail *^ stats.fs_block_size /^ 1024L)
+               stats.fs_name
+           ) else (                    (* Human-readable blocks. *)
+             printf "%10s %10s %10s %s\n"
+               (printable_size (blocks_total *^ stats.fs_block_size))
+               (printable_size (stats.fs_blocks_used *^ stats.fs_block_size))
+               (printable_size (blocks_avail *^ stats.fs_block_size))
+               stats.fs_name
+           )
+         ) else (                      (* Inodes display. *)
+           printf "%10Ld %10Ld %10Ld %s\n"
+             stats.fs_inodes_total stats.fs_inodes_used stats.fs_inodes_avail
              stats.fs_name
          )
-       ) else (                        (* Inodes display. *)
-         printf "%Ld %Ld %Ld %s\n"
-           stats.fs_inodes_total stats.fs_inodes_used stats.fs_inodes_avail
-           stats.fs_name
-       )
 
-    (* Unsupported filesystem or other failure. *)
-    | (target, ProbeFailed reason) ->
-       printf "\t%s %s\n" target reason
+      (* Unsupported filesystem or other failure. *)
+      | ProbeFailed reason ->
+         printf "                                 %s\n" reason
 
-    | (_, ProbeIgnore) -> ()
+      | ProbeIgnore -> ()
   ) statss
 
 (* Target is something like "hda" and size is the size in sectors. *)
@@ -307,17 +327,40 @@ let main () =
   (* Command line argument parsing. *)
   let set_uri = function "" -> uri := None | u -> uri := Some u in
 
+  let version () =
+    printf "virt-df %s\n" (Libvirt_version.version);
+
+    let major, minor, release =
+      let v, _ = Libvirt.get_version () in
+      v / 1_000_000, (v / 1_000) mod 1_000, v mod 1_000 in
+    printf "libvirt %d.%d.%d\n" major minor release;
+    exit 0
+  in
+
   let argspec = Arg.align [
-    "-c", Arg.String set_uri, "uri Connect to URI (default: Xen)";
-    "--connect", Arg.String set_uri, "uri Connect to URI (default: Xen)";
-    "-h", Arg.Set human, " Print sizes in human-readable format";
-    "--human-readable", Arg.Set human, " Print sizes in human-readable format";
-    "-i", Arg.Set inodes, " Show inodes instead of blocks";
-    "--inodes", Arg.Set inodes, " Show inodes instead of blocks";
+    "-a", Arg.Set all,
+      " " ^ s_ "Show all domains (default: only active domains)";
+    "--all", Arg.Set all,
+      " " ^ s_ "Show all domains (default: only active domains)";
+    "-c", Arg.String set_uri,
+      "uri " ^ s_ "Connect to URI (default: Xen)";
+    "--connect", Arg.String set_uri,
+      "uri " ^ s_ "Connect to URI (default: Xen)";
+    "-h", Arg.Set human,
+      " " ^ s_ "Print sizes in human-readable format";
+    "--human-readable", Arg.Set human,
+      " " ^ s_ "Print sizes in human-readable format";
+    "-i", Arg.Set inodes,
+      " " ^ s_ "Show inodes instead of blocks";
+    "--inodes", Arg.Set inodes,
+      " " ^ s_ "Show inodes instead of blocks";
+    "--version", Arg.Unit version,
+      " " ^ s_ "Display version and exit";
   ] in
 
-  let anon_fun str = raise (Arg.Bad (str ^ ": unknown parameter")) in
-  let usage_msg = "virt-df : like 'df', shows disk space used in guests
+  let anon_fun str =
+    raise (Arg.Bad (sprintf (f_ "%s: unknown parameter") str)) in
+  let usage_msg = s_ "virt-df : like 'df', shows disk space used in guests
 
 SUMMARY
   virt-df [-options]
@@ -336,7 +379,7 @@ OPTIONS" in
          prerr_endline (Libvirt.Virterror.to_string err);
          (* If non-root and no explicit connection URI, print a warning. *)
          if geteuid () <> 0 && name = None then (
-           print_endline "NB: If you want to monitor a local Xen hypervisor, you usually need to be root";
+           print_endline (s_ "NB: If you want to monitor a local Xen hypervisor, you usually need to be root");
          );
          exit 1 in
 
@@ -345,11 +388,15 @@ OPTIONS" in
       let nr_active_doms = C.num_of_domains conn in
       let active_doms = Array.to_list (C.list_domains conn nr_active_doms) in
       let active_doms = List.map (D.lookup_by_id conn) active_doms in
-      let nr_inactive_doms = C.num_of_defined_domains conn in
-      let inactive_doms =
-       Array.to_list (C.list_defined_domains conn nr_inactive_doms) in
-      let inactive_doms = List.map (D.lookup_by_name conn) inactive_doms in
-      active_doms @ inactive_doms in
+      if not !all then
+       active_doms
+      else (
+       let nr_inactive_doms = C.num_of_defined_domains conn in
+       let inactive_doms =
+         Array.to_list (C.list_defined_domains conn nr_inactive_doms) in
+       let inactive_doms = List.map (D.lookup_by_name conn) inactive_doms in
+       active_doms @ inactive_doms
+      ) in
 
     (* Get their XML. *)
     let xmls = List.map D.get_xml_desc doms in
@@ -369,7 +416,7 @@ OPTIONS" in
        let nodes, domain_attrs =
          match xml with
          | Xml.Element ("domain", attrs, children) -> children, attrs
-         | _ -> failwith "get_xml_desc didn't return <domain/>" in
+         | _ -> failwith (s_ "get_xml_desc didn't return <domain/>") in
 
        let domid =
          try Some (int_of_string (List.assoc "id" domain_attrs))
@@ -377,10 +424,10 @@ OPTIONS" in
 
        let rec loop = function
          | [] ->
-             failwith "get_xml_desc returned no <name> node in XML"
+             failwith (s_ "get_xml_desc returned no <name> node in XML")
          | Xml.Element ("name", _, [Xml.PCData name]) :: _ -> name
          | Xml.Element ("name", _, _) :: _ ->
-             failwith "get_xml_desc returned strange <name> node"
+             failwith (s_ "get_xml_desc returned strange <name> node")
          | _ :: rest -> loop rest
        in
        let name = loop nodes in
@@ -444,6 +491,16 @@ OPTIONS" in
        { dom_name = name; dom_id = domid; dom_disks = disks }
     ) xmls in
 
+  (* 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 "%-20s %10s %10s %10s %s\n%!"
+      (s_ "Filesystem") total used avail (s_ "Type") in
+
   (* Probe the devices. *)
   List.iter (
     fun { dom_name = dom_name; dom_disks = dom_disks } ->
@@ -454,6 +511,6 @@ OPTIONS" in
        | { d_device = Some "cdrom" } ->
            () (* Ignore physical CD-ROM devices. *)
        | _ ->
-           printf "(device omitted)\n";
+           print_endline (s_ "(device omitted)");
       ) dom_disks
   ) doms