forked from xapi-project/xen-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
bootloader.ml
115 lines (100 loc) · 4.13 KB
/
bootloader.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
(*
* Copyright (C) 2006-2009 Citrix Systems Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* 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 Lesser General Public License for more details.
*)
(* TODO:
1. Modify pygrub to extract all possible boot options
2. Parse the results into some kind of option list
3. Ensure all our guests have complete grub menu.lst (no hacks please!)
4. Add support to control a slave screen process, to make a 'bios'
*)
open Stringext
open Pervasiveext
open Forkhelpers
open Xenops_task
module D=Debug.Debugger(struct let name="bootloader" end)
open D
let pygrub_path = "/usr/bin/pygrub"
let eliloader_path = "/usr/bin/eliloader"
let supported_bootloader_paths = [
"pygrub", pygrub_path;
"eliloader", eliloader_path
]
let supported_bootloaders = List.map fst supported_bootloader_paths
exception Bad_sexpr of string
exception Bad_error of string
exception Unknown_bootloader of string
exception Error_from_bootloader of string
type t = {
kernel_path: string;
initrd_path: string option;
kernel_args: string;
}
(** Helper function to generate a bootloader commandline *)
let bootloader_args q extra_args legacy_args pv_bootloader_args image vm_uuid =
(* Let's not do anything fancy while parsing the pv_bootloader_args string:
no escaping of spaces or quotes for now *)
let pv_bootloader_args = if pv_bootloader_args = "" then [] else String.split ' ' pv_bootloader_args in
let rules = [ '"', "\\\""; '\\', "\\\\" ] in
[ if q then "-q" else "";
Printf.sprintf "--default_args=%s" (String.escaped ~rules legacy_args);
Printf.sprintf "--extra_args=%s" (String.escaped ~rules extra_args);
Printf.sprintf "--vm=%s" vm_uuid;
] @ pv_bootloader_args @ [
image ]
let parse_output x =
let sexpr = "(" ^ x ^ ")" in
let sexpr' = SExpr_TS.of_string sexpr in
match sexpr' with
(* linux (kernel /var/lib/xen/vmlinuz.y1Wmrp)(args 'root=/dev/sda1 ro') *)
(* linux (kernel /var/lib/xen/vmlinuz.SFO5fb)(ramdisk /var/lib/xen/initrd.MUitgP)(args 'root=/dev/sda1 ro') *)
| SExpr.Node (SExpr.Symbol "linux" :: list) ->
let l = List.map (function
| SExpr.Node [ SExpr.Symbol x; SExpr.Symbol y | SExpr.String y ] -> (x,y)
| _ -> raise (Bad_sexpr sexpr)) list in
{
kernel_path = List.assoc "kernel" l;
initrd_path = (try Some (List.assoc "ramdisk" l) with _ -> None);
kernel_args = (try List.assoc "args" l with _ -> "") }
| _ ->
debug "Failed to parse: %s" sexpr;
raise (Bad_sexpr sexpr)
let parse_exception x =
debug "Bootloader failed: %s" x;
let msg =
try
(* Look through the error for the prefix "RuntimeError: " - raise an exception with a message
* containing the error from the end of this prefix onwards. *)
let msg_prefix = "RuntimeError: " in
let msg_start = (List.hd (String.find_all msg_prefix x)) + (String.length msg_prefix) in
String.sub_to_end x msg_start
with _ ->
raise (Bad_error x)
in
raise (Error_from_bootloader msg)
(** Extract the default kernel using the -q option *)
let extract (task: Xenops_task.t) ~bootloader ~disk ?(legacy_args="") ?(extra_args="") ?(pv_bootloader_args="") ~vm:vm_uuid () =
if not(List.mem_assoc bootloader supported_bootloader_paths)
then raise (Unknown_bootloader bootloader);
let bootloader_path = List.assoc bootloader supported_bootloader_paths in
let cmdline = bootloader_args true extra_args legacy_args pv_bootloader_args disk vm_uuid in
debug "Bootloader commandline: %s %s\n" bootloader_path (String.concat " " cmdline);
try
let output, _ = Cancel_utils.cancellable_subprocess task bootloader_path cmdline in
parse_output output
with Forkhelpers.Spawn_internal_error(stderr, stdout, _) ->
parse_exception stderr
let delete x =
Unix.unlink x.kernel_path;
match x.initrd_path with
| None -> ()
| Some x -> Unix.unlink x