sparsify: Add auto-detection of .vdi files.
[libguestfs.git] / sparsify / utils.ml
1 (* virt-sparsify
2  * Copyright (C) 2010-2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  *)
18
19 (* XXX This was copied from virt-resize, and probably some of the
20    functions here are not used in virt-sparsify and could be
21    deleted. *)
22
23 open Printf
24
25 module G = Guestfs
26
27 let (//) = Filename.concat
28
29 let ( +^ ) = Int64.add
30 let ( -^ ) = Int64.sub
31 let ( *^ ) = Int64.mul
32 let ( /^ ) = Int64.div
33 let ( &^ ) = Int64.logand
34 let ( ~^ ) = Int64.lognot
35
36 let output_spaces chan n = for i = 0 to n-1 do output_char chan ' ' done
37
38 let wrap ?(chan = stdout) ?(hanging = 0) str =
39   let rec _wrap col str =
40     let n = String.length str in
41     let i = try String.index str ' ' with Not_found -> n in
42     let col =
43       if col+i >= 72 then (
44         output_char chan '\n';
45         output_spaces chan hanging;
46         i+hanging+1
47       ) else col+i+1 in
48     output_string chan (String.sub str 0 i);
49     if i < n then (
50       output_char chan ' ';
51       _wrap col (String.sub str (i+1) (n-(i+1)))
52     )
53   in
54   _wrap 0 str
55
56 let string_prefix str prefix =
57   let n = String.length prefix in
58   String.length str >= n && String.sub str 0 n = prefix
59
60 let rec string_find s sub =
61   let len = String.length s in
62   let sublen = String.length sub in
63   let rec loop i =
64     if i <= len-sublen then (
65       let rec loop2 j =
66         if j < sublen then (
67           if s.[i+j] = sub.[j] then loop2 (j+1)
68           else -1
69         ) else
70           i (* found *)
71       in
72       let r = loop2 0 in
73       if r = -1 then loop (i+1) else r
74     ) else
75       -1 (* not found *)
76   in
77   loop 0
78
79 let string_random8 =
80   let chars = "abcdefghijklmnopqrstuvwxyz0123456789" in
81   fun () ->
82     String.concat "" (
83       List.map (
84         fun _ ->
85           let c = Random.int 36 in
86           let c = chars.[c] in
87           String.make 1 c
88       ) [1;2;3;4;5;6;7;8]
89     )
90
91 let error fs =
92   let display str =
93     wrap ~chan:stderr ("virt-sparsify: error: " ^ str);
94     prerr_newline ();
95     prerr_newline ();
96     wrap ~chan:stderr
97       "If reporting bugs, run virt-sparsify with the '-v' and '-x' options and include the complete output.";
98     prerr_newline ();
99     exit 1
100   in
101   ksprintf display fs
102
103 (* The reverse of device name translation, see
104  * BLOCK DEVICE NAMING in guestfs(3).
105  *)
106 let canonicalize dev =
107   if String.length dev >= 8 &&
108     dev.[0] = '/' && dev.[1] = 'd' && dev.[2] = 'e' && dev.[3] = 'v' &&
109     dev.[4] = '/' && (dev.[5] = 'h' || dev.[5] = 'v') && dev.[6] = 'd' then (
110       let dev = String.copy dev in
111       dev.[5] <- 's';
112       dev
113     )
114   else
115     dev
116
117 let feature_available (g : Guestfs.guestfs) names =
118   try g#available names; true
119   with G.Error _ -> false
120
121 let human_size i =
122   let sign, i = if i < 0L then "-", Int64.neg i else "", i in
123
124   if i < 1024L then
125     sprintf "%s%Ld" sign i
126   else (
127     let f = Int64.to_float i /. 1024. in
128     let i = i /^ 1024L in
129     if i < 1024L then
130       sprintf "%s%.1fK" sign f
131     else (
132       let f = Int64.to_float i /. 1024. in
133       let i = i /^ 1024L in
134       if i < 1024L then
135         sprintf "%s%.1fM" sign f
136       else (
137         let f = Int64.to_float i /. 1024. in
138         (*let i = i /^ 1024L in*)
139         sprintf "%s%.1fG" sign f
140       )
141     )
142   )