Don't require external insmod.static.
[febootstrap.git] / febootstrap_utils.ml
1 (* febootstrap 3
2  * Copyright (C) 2009-2010 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
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 open Unix
20 open Printf
21
22 let (//) = Filename.concat
23
24 let file_exists name =
25   try access name [F_OK]; true
26   with Unix_error _ -> false
27
28 let dir_exists name =
29   try (stat name).st_kind = S_DIR
30   with Unix_error _ -> false
31
32 let rec uniq ?(cmp = Pervasives.compare) = function
33   | [] -> []
34   | [x] -> [x]
35   | x :: y :: xs when cmp x y = 0 ->
36       uniq ~cmp (x :: xs)
37   | x :: y :: xs ->
38       x :: uniq ~cmp (y :: xs)
39
40 let sort_uniq ?(cmp = Pervasives.compare) xs =
41   let xs = List.sort cmp xs in
42   let xs = uniq ~cmp xs in
43   xs
44
45 let rec input_all_lines chan =
46   try let line = input_line chan in line :: input_all_lines chan
47   with End_of_file -> []
48
49 let run_command_get_lines cmd =
50   let chan = open_process_in cmd in
51   let lines = input_all_lines chan in
52   let stat = close_process_in chan in
53   (match stat with
54    | WEXITED 0 -> ()
55    | WEXITED i ->
56        eprintf "febootstrap: command '%s' failed (returned %d), see earlier error messages\n" cmd i;
57        exit i
58    | WSIGNALED i ->
59        eprintf "febootstrap: command '%s' killed by signal %d" cmd i;
60        exit 1
61    | WSTOPPED i ->
62        eprintf "febootstrap: command '%s' stopped by signal %d" cmd i;
63        exit 1
64   );
65   lines
66
67 let run_command cmd =
68   if Sys.command cmd <> 0 then (
69     eprintf "febootstrap: %s: command failed, see earlier errors\n" cmd;
70     exit 1
71   )
72
73 let run_python code args =
74   let cmd = sprintf "python -c %s %s"
75     (Filename.quote code)
76     (String.concat " " (List.map Filename.quote args)) in
77   if Sys.command cmd <> 0 then (
78     eprintf "febootstrap: external python program failed, see earlier error messages\n";
79     exit 1
80   )
81
82 let tmpdir () =
83   let chan = open_in "/dev/urandom" in
84   let data = String.create 16 in
85   really_input chan data 0 (String.length data);
86   close_in chan;
87   let data = Digest.to_hex (Digest.string data) in
88   (* Note this is secure, because if the name already exists, even as a
89    * symlink, mkdir(2) will fail.
90    *)
91   let tmpdir = Filename.temp_dir_name // sprintf "febootstrap%s.tmp" data in
92   Unix.mkdir tmpdir 0o700;
93   at_exit
94     (fun () ->
95        let cmd = sprintf "rm -rf %s" (Filename.quote tmpdir) in
96        ignore (Sys.command cmd));
97   tmpdir
98
99 let rec find s sub =
100   let len = String.length s in
101   let sublen = String.length sub in
102   let rec loop i =
103     if i <= len-sublen then (
104       let rec loop2 j =
105         if j < sublen then (
106           if s.[i+j] = sub.[j] then loop2 (j+1)
107           else -1
108         ) else
109           i (* found *)
110       in
111       let r = loop2 0 in
112       if r = -1 then loop (i+1) else r
113     ) else
114       -1 (* not found *)
115   in
116   loop 0
117
118 let rec string_split sep str =
119   let len = String.length str in
120   let seplen = String.length sep in
121   let i = find str sep in
122   if i = -1 then [str]
123   else (
124     let s' = String.sub str 0 i in
125     let s'' = String.sub str (i+seplen) (len-i-seplen) in
126     s' :: string_split sep s''
127   )
128
129 let string_prefix p str =
130   let len = String.length str in
131   let plen = String.length p in
132   len >= plen && String.sub str 0 plen = p
133
134 let path_prefix p path =
135   let len = String.length path in
136   let plen = String.length p in
137   path = p || (len > plen && String.sub path 0 (plen+1) = (p ^ "/"))
138
139 let rec filter_map f = function
140   | [] -> []
141   | x :: xs ->
142       let x = f x in
143       match x with
144       | None -> filter_map f xs
145       | Some x -> x :: filter_map f xs