mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			2504 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
			
		
		
	
	
			2504 lines
		
	
	
		
			66 KiB
		
	
	
	
		
			OCaml
		
	
	
	
	
	
(*
 | 
						|
 * Copyright (c) 2013 Thomas Gazagnaire <thomas@gazagnaire.org>
 | 
						|
 * Copyright (c) 2013 Anil Madhavapeddy <anil@recoil.org>
 | 
						|
 *
 | 
						|
 * Permission to use, copy, modify, and distribute this software for any
 | 
						|
 * purpose with or without fee is hereby granted, provided that the above
 | 
						|
 * copyright notice and this permission notice appear in all copies.
 | 
						|
 *
 | 
						|
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 | 
						|
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 | 
						|
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 | 
						|
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 | 
						|
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 | 
						|
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 | 
						|
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 | 
						|
 *)
 | 
						|
 | 
						|
open Mirage_misc
 | 
						|
 | 
						|
module StringSet = struct
 | 
						|
 | 
						|
  include Set.Make(String)
 | 
						|
 | 
						|
  let of_list l =
 | 
						|
    let s = ref empty in
 | 
						|
    List.iter (fun e -> s := add e !s) l;
 | 
						|
    !s
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
let main_ml = ref None
 | 
						|
 | 
						|
let append_main fmt =
 | 
						|
  match !main_ml with
 | 
						|
  | None    -> failwith "main_ml"
 | 
						|
  | Some oc -> append oc fmt
 | 
						|
 | 
						|
let newline_main () =
 | 
						|
  match !main_ml with
 | 
						|
  | None    -> failwith "main_ml"
 | 
						|
  | Some oc -> newline oc
 | 
						|
 | 
						|
let set_main_ml file =
 | 
						|
  let oc = open_out file in
 | 
						|
  main_ml := Some oc
 | 
						|
 | 
						|
type mode = [
 | 
						|
  | `Unix
 | 
						|
  | `Xen
 | 
						|
  | `MacOSX
 | 
						|
]
 | 
						|
 | 
						|
let string_of_mode =
 | 
						|
  function
 | 
						|
  | `Unix -> "Unix"
 | 
						|
  | `Xen -> "Xen"
 | 
						|
  | `MacOSX -> "MacOS X"
 | 
						|
 | 
						|
let mode : mode ref = ref `Unix
 | 
						|
 | 
						|
let set_mode m =
 | 
						|
  mode := m
 | 
						|
 | 
						|
let get_mode () =
 | 
						|
  !mode
 | 
						|
 | 
						|
type _ typ =
 | 
						|
  | Type: 'a -> 'a typ
 | 
						|
  | Function: 'a typ * 'b typ -> ('a -> 'b) typ
 | 
						|
 | 
						|
let (@->) f t =
 | 
						|
  Function (f, t)
 | 
						|
 | 
						|
module type CONFIGURABLE = sig
 | 
						|
  type t
 | 
						|
  val name: t -> string
 | 
						|
  val module_name: t -> string
 | 
						|
  val packages: t -> string list
 | 
						|
  val libraries: t -> string list
 | 
						|
  val configure: t -> unit
 | 
						|
  val clean: t -> unit
 | 
						|
  val update_path: t -> string -> t
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
module TODO (N: sig val name: string end) = struct
 | 
						|
 | 
						|
  let todo str =
 | 
						|
    failwith (Printf.sprintf "TODO: %s.%s" N.name str)
 | 
						|
 | 
						|
  let name _ =
 | 
						|
    todo "name"
 | 
						|
 | 
						|
  let module_name _ =
 | 
						|
    todo "module_name"
 | 
						|
 | 
						|
  let packages _ =
 | 
						|
    todo "packages"
 | 
						|
 | 
						|
  let libraries _ =
 | 
						|
    todo "libraries"
 | 
						|
 | 
						|
  let configure _ =
 | 
						|
    todo "configure"
 | 
						|
 | 
						|
  let clean _ =
 | 
						|
    todo "clean"
 | 
						|
 | 
						|
  let update_path _ =
 | 
						|
    todo "update_path"
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type ('a, 'b) base = {
 | 
						|
  typ: 'a typ;
 | 
						|
  t: 'b;
 | 
						|
  m: (module CONFIGURABLE with type t = 'b);
 | 
						|
}
 | 
						|
 | 
						|
type 'a foreign = {
 | 
						|
  name: string;
 | 
						|
  ty: 'a typ;
 | 
						|
  libraries: string list;
 | 
						|
  packages: string list;
 | 
						|
}
 | 
						|
 | 
						|
type _ impl =
 | 
						|
  | Impl: ('a, 'b) base -> 'a impl (* base implementation *)
 | 
						|
  | App: ('a, 'b) app -> 'b impl   (* functor application *)
 | 
						|
  | Foreign: 'a foreign -> 'a impl (* foreign functor implementation *)
 | 
						|
 | 
						|
and ('a, 'b) app = {
 | 
						|
  f: ('a -> 'b) impl;  (* functor *)
 | 
						|
  x: 'a impl;          (* parameter *)
 | 
						|
}
 | 
						|
 | 
						|
let rec string_of_impl: type a. a impl -> string = function
 | 
						|
  | Impl { t; m = (module M) } -> Printf.sprintf "Impl (%s)" (M.module_name t)
 | 
						|
  | Foreign { name } -> Printf.sprintf "Foreign (%s)" name
 | 
						|
  | App { f; x } -> Printf.sprintf "App (%s, %s)" (string_of_impl f) (string_of_impl x)
 | 
						|
 | 
						|
type 'a folder = {
 | 
						|
  fn: 'b. 'a -> 'b impl -> 'a
 | 
						|
}
 | 
						|
 | 
						|
let rec fold: type a. 'b folder -> a impl -> 'b -> 'b =
 | 
						|
  fun fn t acc ->
 | 
						|
    match t with
 | 
						|
    | Impl _
 | 
						|
    | Foreign _  -> fn.fn acc t
 | 
						|
    | App {f; x} -> fold fn f (fn.fn acc x)
 | 
						|
 | 
						|
type iterator = {
 | 
						|
  i: 'b. 'b impl -> unit
 | 
						|
}
 | 
						|
 | 
						|
let rec iter: type a. iterator -> a impl -> unit =
 | 
						|
  fun fn t ->
 | 
						|
    match t with
 | 
						|
    | Impl _
 | 
						|
    | Foreign _  -> fn.i t
 | 
						|
    | App {f; x} -> iter fn f; iter fn x; fn.i x
 | 
						|
 | 
						|
let driver_initialisation_error name =
 | 
						|
  Printf.sprintf "fail (Failure %S)" name
 | 
						|
 | 
						|
module Name = struct
 | 
						|
 | 
						|
  let ids = Hashtbl.create 1024
 | 
						|
 | 
						|
  let names = Hashtbl.create 1024
 | 
						|
 | 
						|
  let create name =
 | 
						|
    let n =
 | 
						|
      try 1 + Hashtbl.find ids name
 | 
						|
      with Not_found -> 1 in
 | 
						|
    Hashtbl.replace ids name n;
 | 
						|
    Printf.sprintf "%s%d" name n
 | 
						|
 | 
						|
  let of_key key ~base =
 | 
						|
    find_or_create names key (fun () -> create base)
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module Impl = struct
 | 
						|
 | 
						|
  (* get the left-most module name (ie. the name of the functor). *)
 | 
						|
  let rec functor_name: type a. a impl -> string = function
 | 
						|
    | Impl { t; m = (module M) } -> M.module_name t
 | 
						|
    | Foreign { name }           -> name
 | 
						|
    | App { f }                  -> functor_name f
 | 
						|
 | 
						|
  (* return a unique variable name holding the state of the given
 | 
						|
     module construction. *)
 | 
						|
  let rec name: type a. a impl -> string = function
 | 
						|
    | Impl { t; m = (module M) } -> M.name t
 | 
						|
    | Foreign { name }           -> Name.of_key ("f" ^ name) ~base:"f"
 | 
						|
    | App _ as t                 -> Name.of_key (module_name t) ~base:"t"
 | 
						|
 | 
						|
  (* return a unique module name holding the implementation of the
 | 
						|
     given module construction. *)
 | 
						|
  and module_name: type a. a impl -> string = function
 | 
						|
    | Impl { t; m = (module M) } -> M.module_name t
 | 
						|
    | Foreign { name }           -> name
 | 
						|
    | App { f; x }   ->
 | 
						|
      let name = match module_names f @ [module_name x] with
 | 
						|
        | []   -> assert false
 | 
						|
        | [m]  -> m
 | 
						|
        | h::t -> h ^ String.concat "" (List.map (Printf.sprintf "(%s)") t)
 | 
						|
      in
 | 
						|
      Name.of_key name ~base:"M"
 | 
						|
 | 
						|
  and module_names: type a. a impl -> string list =
 | 
						|
    function t ->
 | 
						|
      let fn = {
 | 
						|
        fn = fun acc t -> module_name t :: acc
 | 
						|
      } in
 | 
						|
      fold fn t []
 | 
						|
 | 
						|
  let rec names: type a. a impl -> string list = function
 | 
						|
    | Foreign _            -> []
 | 
						|
    | Impl _ as t          -> [name t]
 | 
						|
    | App {f=Foreign f; x} -> names x
 | 
						|
    | App {f; x}           -> (names f) @ [name x]
 | 
						|
 | 
						|
  let configured = Hashtbl.create 31
 | 
						|
 | 
						|
  let rec configure: type a. a impl -> unit =
 | 
						|
    fun t ->
 | 
						|
      let name = name t in
 | 
						|
      if not (Hashtbl.mem configured name) then (
 | 
						|
        Hashtbl.add configured name true;
 | 
						|
        match t with
 | 
						|
        | Impl { t; m = (module M) } -> M.configure t
 | 
						|
        | Foreign _                  -> ()
 | 
						|
        | App {f; x} as  app         ->
 | 
						|
          configure_app f;
 | 
						|
          configure_app x;
 | 
						|
          iter { i=configure } app;
 | 
						|
          let name = module_name app in
 | 
						|
          let body = cofind Name.names name in
 | 
						|
          append_main "module %s = %s" name body;
 | 
						|
          newline_main ();
 | 
						|
      )
 | 
						|
 | 
						|
  and configure_app: type a. a impl -> unit = function
 | 
						|
    | Impl _
 | 
						|
    | Foreign _  -> ()
 | 
						|
    | App _ as t ->
 | 
						|
      let name = name t in
 | 
						|
      configure t;
 | 
						|
      begin match names t with
 | 
						|
        | [n]   -> append_main "let %s = %s" name n
 | 
						|
        | names ->
 | 
						|
          append_main "let %s () =" name;
 | 
						|
          List.iter (fun n ->
 | 
						|
              append_main "  %s () >>= function" n;
 | 
						|
              append_main "  | `Error e -> %s" (driver_initialisation_error n);
 | 
						|
              append_main "  | `Ok %s ->" n;
 | 
						|
            ) names;
 | 
						|
          append_main "  return (`Ok (%s))" (String.concat ", " names)
 | 
						|
      end;
 | 
						|
      newline_main ()
 | 
						|
 | 
						|
  let rec packages: type a. a impl -> string list = function
 | 
						|
    | Impl { t; m = (module M) } -> M.packages t
 | 
						|
    | Foreign { packages }       -> packages
 | 
						|
    | App {f; x}                 -> packages f @ packages x
 | 
						|
 | 
						|
  let rec libraries: type a. a impl -> string list = function
 | 
						|
    | Impl { t; m = (module M) } -> M.libraries t
 | 
						|
    | Foreign { libraries }      -> libraries
 | 
						|
    | App {f; x}                 -> libraries f @ libraries x
 | 
						|
 | 
						|
  let rec clean: type a. a impl -> unit = function
 | 
						|
    | Impl { t; m = (module M) } -> M.clean t
 | 
						|
    | Foreign _                  -> ()
 | 
						|
    | App {f; x}                 -> clean f; clean x
 | 
						|
 | 
						|
  let rec update_path: type a. a impl -> string -> a impl =
 | 
						|
    fun t root -> match t with
 | 
						|
      | Impl b     ->
 | 
						|
        let module M = (val b.m) in Impl { b with t = M.update_path b.t root }
 | 
						|
      | Foreign _  -> t
 | 
						|
      | App {f; x} -> App { f = update_path f root; x = update_path x root }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
let impl typ t m =
 | 
						|
  Impl { typ; t; m }
 | 
						|
 | 
						|
let implementation typ t m =
 | 
						|
  let typ = Type typ in
 | 
						|
  Impl { typ; t; m }
 | 
						|
 | 
						|
let ($) f x =
 | 
						|
  App { f; x }
 | 
						|
 | 
						|
let foreign name ?(libraries=[]) ?(packages=[]) ty =
 | 
						|
  Foreign { name; ty; libraries; packages }
 | 
						|
 | 
						|
let rec typ: type a. a impl -> a typ = function
 | 
						|
  | Impl { typ } -> typ
 | 
						|
  | Foreign { ty } -> ty
 | 
						|
  | App { f }       -> match typ f with Function (_, b) -> b | _ -> assert false
 | 
						|
 | 
						|
 | 
						|
module Io_page = struct
 | 
						|
 | 
						|
  (** Memory allocation interface. *)
 | 
						|
 | 
						|
  type t = unit
 | 
						|
 | 
						|
  let name () =
 | 
						|
    "io_page"
 | 
						|
 | 
						|
  let module_name () =
 | 
						|
    "Io_page"
 | 
						|
 | 
						|
  let packages () = [
 | 
						|
    "io-page"
 | 
						|
  ]
 | 
						|
 | 
						|
  let libraries () =
 | 
						|
    match !mode with
 | 
						|
    | `Xen  -> ["io-page"]
 | 
						|
    | `Unix | `MacOSX -> ["io-page"; "io-page.unix"]
 | 
						|
 | 
						|
  let configure () = ()
 | 
						|
 | 
						|
  let clean () = ()
 | 
						|
 | 
						|
  let update_path () _ = ()
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type io_page = IO_PAGE
 | 
						|
 | 
						|
let io_page = Type IO_PAGE
 | 
						|
 | 
						|
let default_io_page: io_page impl =
 | 
						|
  impl io_page () (module Io_page)
 | 
						|
 | 
						|
module Time = struct
 | 
						|
 | 
						|
  (** OS Timer. *)
 | 
						|
 | 
						|
  type t = unit
 | 
						|
 | 
						|
  let name () =
 | 
						|
    "time"
 | 
						|
 | 
						|
  let module_name () =
 | 
						|
    "OS.Time"
 | 
						|
 | 
						|
  let packages () = []
 | 
						|
 | 
						|
  let libraries () = []
 | 
						|
 | 
						|
  let configure () = ()
 | 
						|
 | 
						|
  let clean () = ()
 | 
						|
 | 
						|
  let update_path () _ = ()
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type time = TIME
 | 
						|
 | 
						|
let time = Type TIME
 | 
						|
 | 
						|
let default_time: time impl =
 | 
						|
  impl time () (module Time)
 | 
						|
 | 
						|
module Clock = struct
 | 
						|
 | 
						|
  (** Clock operations. *)
 | 
						|
 | 
						|
  type t = unit
 | 
						|
 | 
						|
  let name () =
 | 
						|
    "clock"
 | 
						|
 | 
						|
  let module_name () =
 | 
						|
    "Clock"
 | 
						|
 | 
						|
  let packages () = [
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> "mirage-clock-unix"
 | 
						|
    | `Xen  -> "mirage-clock-xen"
 | 
						|
  ]
 | 
						|
 | 
						|
  let libraries () = packages ()
 | 
						|
 | 
						|
  let configure () =
 | 
						|
    append_main "let clock () = return (`Ok ())";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean () = ()
 | 
						|
 | 
						|
  let update_path () _ = ()
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type clock = CLOCK
 | 
						|
 | 
						|
let clock = Type CLOCK
 | 
						|
 | 
						|
let default_clock: clock impl =
 | 
						|
  impl clock () (module Clock)
 | 
						|
 | 
						|
module Random = struct
 | 
						|
 | 
						|
  type t = unit
 | 
						|
 | 
						|
  let name () =
 | 
						|
    "random"
 | 
						|
 | 
						|
  let module_name () =
 | 
						|
    "Random"
 | 
						|
 | 
						|
  let packages () = []
 | 
						|
 | 
						|
  let libraries () = []
 | 
						|
 | 
						|
  let configure () =
 | 
						|
    append_main "let random () = return (`Ok ())";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean () = ()
 | 
						|
 | 
						|
  let update_path () _ = ()
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type random = RANDOM
 | 
						|
 | 
						|
let random = Type RANDOM
 | 
						|
 | 
						|
let default_random: random impl =
 | 
						|
  impl random () (module Random)
 | 
						|
 | 
						|
module Entropy = struct
 | 
						|
 | 
						|
  type t = unit
 | 
						|
 | 
						|
  let name _ =
 | 
						|
    "entropy"
 | 
						|
 | 
						|
  let module_name () = "Entropy"
 | 
						|
 | 
						|
  let construction () =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> "Entropy_unix.Make (OS.Time)"
 | 
						|
    | `Xen  -> "Entropy_xen"
 | 
						|
 | 
						|
  let packages () =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> [ "mirage-entropy-unix" ]
 | 
						|
    | `Xen  -> [ "mirage-entropy-xen" ]
 | 
						|
 | 
						|
  let libraries = packages
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "module %s = %s" (module_name t) (construction t) ;
 | 
						|
    newline_main () ;
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s.connect ()" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean () = ()
 | 
						|
 | 
						|
  let update_path t _ = t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type entropy = ENTROPY
 | 
						|
 | 
						|
let entropy = Type ENTROPY
 | 
						|
 | 
						|
let default_entropy: entropy impl =
 | 
						|
  impl entropy () (module Entropy)
 | 
						|
 | 
						|
module Console = struct
 | 
						|
 | 
						|
  type t = string
 | 
						|
 | 
						|
  let name t =
 | 
						|
    Name.of_key ("console" ^ t) ~base:"console"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    "Console"
 | 
						|
 | 
						|
  let construction () =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> "Console_unix"
 | 
						|
    | `Xen  -> "Console_xen"
 | 
						|
 | 
						|
  let packages _ =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> ["mirage-console"; "mirage-unix"]
 | 
						|
    | `Xen  -> ["mirage-console"; "xenstore"; "mirage-xen"; "xen-gnt"; "xen-evtchn"]
 | 
						|
 | 
						|
  let libraries _ =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> ["mirage-console.unix"]
 | 
						|
    | `Xen -> ["mirage-console.xen"]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "module %s = %s" (module_name t) (construction ());
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s.connect %S" (module_name t) t;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean _ =
 | 
						|
    ()
 | 
						|
 | 
						|
  let update_path t _ =
 | 
						|
    t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type console = CONSOLE
 | 
						|
 | 
						|
let console = Type CONSOLE
 | 
						|
 | 
						|
let default_console: console impl =
 | 
						|
  impl console "0" (module Console)
 | 
						|
 | 
						|
let custom_console: string -> console impl =
 | 
						|
  fun str ->
 | 
						|
    impl console str (module Console)
 | 
						|
 | 
						|
module Crunch = struct
 | 
						|
 | 
						|
  type t = string
 | 
						|
 | 
						|
  let name t =
 | 
						|
    Name.of_key ("static" ^ t) ~base:"static"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages _ = [
 | 
						|
    "mirage-types";
 | 
						|
    "lwt";
 | 
						|
    "cstruct";
 | 
						|
    "crunch";
 | 
						|
  ] @ Io_page.packages ()
 | 
						|
 | 
						|
  let libraries _ = [
 | 
						|
    "mirage-types";
 | 
						|
    "lwt";
 | 
						|
    "cstruct";
 | 
						|
  ] @ Io_page.libraries ()
 | 
						|
 | 
						|
  let ml t =
 | 
						|
    Printf.sprintf "%s.ml" (name t)
 | 
						|
 | 
						|
  let mli t =
 | 
						|
    Printf.sprintf "%s.mli" (name t)
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    if not (command_exists "ocaml-crunch") then
 | 
						|
      error "ocaml-crunch not found, stopping.";
 | 
						|
    let file = ml t in
 | 
						|
    if Sys.file_exists t then (
 | 
						|
      info "%s %s" (blue_s "Generating:") (Sys.getcwd () / file);
 | 
						|
      command "ocaml-crunch -o %s %s" file t
 | 
						|
    ) else
 | 
						|
      error "The directory %s does not exist." t;
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s.connect ()" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    remove (ml t);
 | 
						|
    remove (mli t)
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    if Sys.file_exists (root / t) then
 | 
						|
      root / t
 | 
						|
    else
 | 
						|
      t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type kv_ro = KV_RO
 | 
						|
 | 
						|
let kv_ro = Type KV_RO
 | 
						|
 | 
						|
let crunch dirname =
 | 
						|
  impl kv_ro dirname (module Crunch)
 | 
						|
 | 
						|
module Direct_kv_ro = struct
 | 
						|
 | 
						|
  include Crunch
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    match !mode with
 | 
						|
    | `Xen  -> Crunch.module_name t
 | 
						|
    | `Unix | `MacOSX -> "Kvro_fs_unix"
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    match !mode with
 | 
						|
    | `Xen  -> Crunch.packages t
 | 
						|
    | `Unix | `MacOSX -> "mirage-fs-unix" :: Crunch.packages t
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    match !mode with
 | 
						|
    | `Xen  -> Crunch.libraries t
 | 
						|
    | `Unix | `MacOSX -> "mirage-fs-unix" :: Crunch.libraries t
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    match !mode with
 | 
						|
    | `Xen  -> Crunch.configure t
 | 
						|
    | `Unix | `MacOSX ->
 | 
						|
      append_main "let %s () =" (name t);
 | 
						|
      append_main "  Kvro_fs_unix.connect %S" t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
let direct_kv_ro dirname =
 | 
						|
  impl kv_ro dirname (module Direct_kv_ro)
 | 
						|
 | 
						|
module Block = struct
 | 
						|
 | 
						|
  type t = string
 | 
						|
 | 
						|
  let name t =
 | 
						|
    Name.of_key ("block" ^ t) ~base:"block"
 | 
						|
 | 
						|
  let module_name _ =
 | 
						|
    "Block"
 | 
						|
 | 
						|
  let packages _ = [
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> "mirage-block-unix"
 | 
						|
    | `Xen  -> "mirage-block-xen"
 | 
						|
  ]
 | 
						|
 | 
						|
  let libraries _ = [
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> "mirage-block-unix"
 | 
						|
    | `Xen  -> "mirage-block-xen.front"
 | 
						|
  ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s.connect %S" (module_name t) t;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    ()
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    if Sys.file_exists (root / t) then
 | 
						|
      root / t
 | 
						|
    else
 | 
						|
      t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type block = BLOCK
 | 
						|
 | 
						|
let block = Type BLOCK
 | 
						|
 | 
						|
let block_of_file filename =
 | 
						|
  impl block filename (module Block)
 | 
						|
 | 
						|
module Fat = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    io_page: io_page impl;
 | 
						|
    block  : block impl;
 | 
						|
  }
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "fat" ^ Impl.name t.io_page ^ Impl.name t.block in
 | 
						|
    Name.of_key key ~base:"fat"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    "fat-filesystem"
 | 
						|
    :: Impl.packages t.io_page
 | 
						|
    @  Impl.packages t.block
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    "fat-filesystem"
 | 
						|
    :: Impl.libraries t.io_page
 | 
						|
    @  Impl.libraries t.block
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    Impl.configure t.io_page;
 | 
						|
    Impl.configure t.block;
 | 
						|
    append_main "module %s = Fat.Fs.Make(%s)(%s)"
 | 
						|
      (module_name t)
 | 
						|
      (Impl.module_name t.block)
 | 
						|
      (Impl.module_name t.io_page);
 | 
						|
    newline_main ();
 | 
						|
    let name = name t in
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "  %s () >>= function" (Impl.name t.block);
 | 
						|
    append_main "  | `Error _ -> %s" (driver_initialisation_error name);
 | 
						|
    append_main "  | `Ok dev  -> %s.connect dev" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.block;
 | 
						|
    Impl.clean t.io_page
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { io_page = Impl.update_path t.io_page root;
 | 
						|
      block  = Impl.update_path t.block root;
 | 
						|
    }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type fs = FS
 | 
						|
 | 
						|
let fs = Type FS
 | 
						|
 | 
						|
let fat ?(io_page=default_io_page) block: fs impl =
 | 
						|
  let t = { Fat.block; io_page } in
 | 
						|
  impl fs t (module Fat)
 | 
						|
 | 
						|
(* This would deserve to be in its own lib. *)
 | 
						|
let kv_ro_of_fs x: kv_ro impl =
 | 
						|
  let dummy_fat = fat (block_of_file "xx") in
 | 
						|
  let libraries = Impl.libraries dummy_fat in
 | 
						|
  let packages = Impl.packages dummy_fat in
 | 
						|
  let fn = foreign "Fat.KV_RO.Make" ~libraries ~packages (fs @-> kv_ro) in
 | 
						|
  fn $ x
 | 
						|
 | 
						|
module Fat_of_files = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    dir   : string option;
 | 
						|
    regexp: string;
 | 
						|
  }
 | 
						|
 | 
						|
  let name t =
 | 
						|
    Name.of_key
 | 
						|
      ("fat" ^ (match t.dir with None -> "." | Some d -> d) ^ ":" ^ t.regexp)
 | 
						|
      ~base:"fat"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let block_file t =
 | 
						|
    name t ^ ".img"
 | 
						|
 | 
						|
  let block t =
 | 
						|
    block_of_file (block_file t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    Impl.packages (fat (block t))
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    Impl.libraries (fat (block t))
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let fat = fat (block t) in
 | 
						|
    Impl.configure fat;
 | 
						|
    append_main "module %s = %s" (module_name t) (Impl.module_name fat);
 | 
						|
    append_main "let %s = %s" (name t) (Impl.name fat);
 | 
						|
    newline_main ();
 | 
						|
    let file = Printf.sprintf "make-%s-image.sh" (name t) in
 | 
						|
    let oc = open_out file in
 | 
						|
    append oc "#!/bin/sh";
 | 
						|
    append oc "";
 | 
						|
    append oc "echo This uses the 'fat' command-line tool to build a simple FAT";
 | 
						|
    append oc "echo filesystem image.";
 | 
						|
    append oc "";
 | 
						|
    append oc "FAT=$(which fat)";
 | 
						|
    append oc "if [ ! -x \"${FAT}\" ]; then";
 | 
						|
    append oc "  echo I couldn\\'t find the 'fat' command-line tool.";
 | 
						|
    append oc "  echo Try running 'opam install fat-filesystem'";
 | 
						|
    append oc "  exit 1";
 | 
						|
    append oc "fi";
 | 
						|
    append oc "";
 | 
						|
    append oc "IMG=$(pwd)/%s" (block_file t);
 | 
						|
    append oc "rm -f ${IMG}";
 | 
						|
    (match t.dir with None -> () | Some d -> append oc "cd %s/" d);
 | 
						|
    append oc "SIZE=$(du -s . | cut -f 1)";
 | 
						|
    append oc "${FAT} create ${IMG} ${SIZE}KiB";
 | 
						|
    append oc "${FAT} add ${IMG} %s" t.regexp;
 | 
						|
    append oc "echo Created '%s'" (block_file t);
 | 
						|
 | 
						|
    close_out oc;
 | 
						|
    Unix.chmod file 0o755;
 | 
						|
    command "./make-%s-image.sh" (name t)
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    command "rm -f make-%s-image.sh %s" (name t) (block_file t);
 | 
						|
    Impl.clean (block t)
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    match t.dir with
 | 
						|
    | None   -> t
 | 
						|
    | Some d -> { t with dir = Some (root / d) }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
let fat_of_files: ?dir:string -> ?regexp:string -> unit -> fs impl =
 | 
						|
  fun ?dir ?regexp () ->
 | 
						|
    let regexp = match regexp with
 | 
						|
      | None   -> "*"
 | 
						|
      | Some r -> r in
 | 
						|
    impl fs { Fat_of_files.dir; regexp } (module Fat_of_files)
 | 
						|
 | 
						|
type network_config = Tap0 | Custom of string
 | 
						|
 | 
						|
module Network = struct
 | 
						|
 | 
						|
  type t = network_config
 | 
						|
 | 
						|
  let name t =
 | 
						|
    "net_" ^ match t with
 | 
						|
    | Tap0     -> "tap0"
 | 
						|
    | Custom s -> s
 | 
						|
 | 
						|
  let module_name _ =
 | 
						|
    "Netif"
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    match !mode with
 | 
						|
    | `Unix -> ["mirage-net-unix"]
 | 
						|
    | `MacOSX -> ["mirage-net-macosx"]
 | 
						|
    | `Xen  -> ["mirage-net-xen"]
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    packages t
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s.connect %S"
 | 
						|
      (module_name t)
 | 
						|
      (match t with Tap0 -> "tap0" | Custom s -> s);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean _ =
 | 
						|
    ()
 | 
						|
 | 
						|
  let update_path t _ =
 | 
						|
    t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type network = NETWORK
 | 
						|
 | 
						|
let network = Type NETWORK
 | 
						|
 | 
						|
let tap0 =
 | 
						|
  impl network Tap0 (module Network)
 | 
						|
 | 
						|
let netif dev =
 | 
						|
  impl network (Custom dev) (module Network)
 | 
						|
 | 
						|
module Ethif = struct
 | 
						|
 | 
						|
  type t = network impl
 | 
						|
 | 
						|
  let name t =
 | 
						|
    Name.of_key ("ethif" ^ Impl.name t) ~base:"ethif"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    Impl.packages t @ ["tcpip"]
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    Impl.libraries t @
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> [ "tcpip.ethif-unix" ]
 | 
						|
    | `Xen  -> [ "tcpip.ethif" ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    Impl.configure t;
 | 
						|
    append_main "module %s = Ethif.Make(%s)" (module_name t) (Impl.module_name t);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "   %s () >>= function" (Impl.name t);
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error name);
 | 
						|
    append_main "   | `Ok eth  -> %s.connect eth" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    Impl.update_path t root
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type ethernet = ETHERNET
 | 
						|
 | 
						|
let ethernet = Type ETHERNET
 | 
						|
 | 
						|
let etif network =
 | 
						|
  impl ethernet network (module Ethif)
 | 
						|
 | 
						|
type ('ipaddr, 'prefix) ip_config = {
 | 
						|
  address: 'ipaddr;
 | 
						|
  netmask: 'prefix;
 | 
						|
  gateways: 'ipaddr list;
 | 
						|
}
 | 
						|
 | 
						|
type ipv4_config = (Ipaddr.V4.t, Ipaddr.V4.t) ip_config
 | 
						|
 | 
						|
let meta_ipv4_config t =
 | 
						|
  Printf.sprintf "(Ipaddr.V4.of_string_exn %S, Ipaddr.V4.of_string_exn %S, [%s])"
 | 
						|
    (Ipaddr.V4.to_string t.address)
 | 
						|
    (Ipaddr.V4.to_string t.netmask)
 | 
						|
    (String.concat "; "
 | 
						|
       (List.map (Printf.sprintf "Ipaddr.V4.of_string_exn %S")
 | 
						|
          (List.map Ipaddr.V4.to_string t.gateways)))
 | 
						|
 | 
						|
module IPV4 = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    ethernet: ethernet impl;
 | 
						|
    config  : ipv4_config;
 | 
						|
  }
 | 
						|
  (* XXX: should the type if ipv4.id be ipv4.t ?
 | 
						|
     N.connect ethif |> N.set_ip up *)
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "ipv4" ^ Impl.name t.ethernet ^ meta_ipv4_config t.config in
 | 
						|
    Name.of_key key ~base:"ipv4"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    "tcpip" :: Impl.packages t.ethernet
 | 
						|
 | 
						|
  let libraries t  =
 | 
						|
    (match !mode with
 | 
						|
     | `Unix | `MacOSX -> [ "tcpip.ipv4-unix" ]
 | 
						|
     | `Xen  -> [ "tcpip.ipv4" ])
 | 
						|
    @ Impl.libraries t.ethernet
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    let mname = module_name t in
 | 
						|
    Impl.configure t.ethernet;
 | 
						|
    append_main "module %s = Ipv4.Make(%s)"
 | 
						|
      (module_name t) (Impl.module_name t.ethernet);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "   %s () >>= function" (Impl.name t.ethernet);
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error name);
 | 
						|
    append_main "   | `Ok eth  ->";
 | 
						|
    append_main "   %s.connect eth >>= function" mname;
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error "IPV4");
 | 
						|
    append_main "   | `Ok ip   ->";
 | 
						|
    append_main "   let i = Ipaddr.V4.of_string_exn in";
 | 
						|
    append_main "   %s.set_ip ip (i %S) >>= fun () ->"
 | 
						|
      mname (Ipaddr.V4.to_string t.config.address);
 | 
						|
    append_main "   %s.set_ip_netmask ip (i %S) >>= fun () ->"
 | 
						|
      mname (Ipaddr.V4.to_string t.config.netmask);
 | 
						|
    append_main "   %s.set_ip_gateways ip [%s] >>= fun () ->"
 | 
						|
      mname
 | 
						|
      (String.concat "; "
 | 
						|
         (List.map
 | 
						|
            (fun n -> Printf.sprintf "(i %S)" (Ipaddr.V4.to_string n))
 | 
						|
            t.config.gateways));
 | 
						|
    append_main "   return (`Ok ip)";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.ethernet
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { t with ethernet = Impl.update_path t.ethernet root }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type ipv6_config = (Ipaddr.V6.t, Ipaddr.V6.Prefix.t list) ip_config
 | 
						|
 | 
						|
let meta_ipv6_config t =
 | 
						|
  Printf.sprintf "(Ipaddr.V6.of_string_exn %S, [%s], [%s])"
 | 
						|
    (Ipaddr.V6.to_string t.address)
 | 
						|
    (String.concat "; "
 | 
						|
       (List.map (Printf.sprintf "Ipaddr.V6.Prefix.of_string_exn %S")
 | 
						|
          (List.map Ipaddr.V6.Prefix.to_string t.netmask)))
 | 
						|
    (String.concat "; "
 | 
						|
       (List.map (Printf.sprintf "Ipaddr.V6.of_string_exn %S")
 | 
						|
          (List.map Ipaddr.V6.to_string t.gateways)))
 | 
						|
 | 
						|
module IPV6 = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    time    : time impl;
 | 
						|
    clock   : clock impl;
 | 
						|
    ethernet: ethernet impl;
 | 
						|
    config  : ipv6_config;
 | 
						|
  }
 | 
						|
  (* XXX: should the type if ipv4.id be ipv4.t ?
 | 
						|
     N.connect ethif |> N.set_ip up *)
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "ipv6" ^ Impl.name t.time ^ Impl.name t.clock ^ Impl.name t.ethernet ^ meta_ipv6_config t.config in
 | 
						|
    Name.of_key key ~base:"ipv6"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    "tcpip" :: Impl.packages t.time @ Impl.packages t.clock @ Impl.packages t.ethernet
 | 
						|
 | 
						|
  let libraries t  =
 | 
						|
    (match !mode with
 | 
						|
     | `Unix | `MacOSX -> [ "tcpip.ipv6-unix" ]
 | 
						|
     | `Xen  -> [ "tcpip.ipv6" ])
 | 
						|
    @ Impl.libraries t.time @ Impl.libraries t.clock @ Impl.libraries t.ethernet
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    let mname = module_name t in
 | 
						|
    Impl.configure t.ethernet;
 | 
						|
    append_main "module %s = Ipv6.Make(%s)(%s)(%s)"
 | 
						|
      (module_name t) (Impl.module_name t.ethernet) (Impl.module_name t.time) (Impl.module_name t.clock);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "   %s () >>= function" (Impl.name t.ethernet);
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error name);
 | 
						|
    append_main "   | `Ok eth  ->";
 | 
						|
    append_main "   %s.connect eth >>= function" mname;
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error name);
 | 
						|
    append_main "   | `Ok ip   ->";
 | 
						|
    append_main "   let i = Ipaddr.V6.of_string_exn in";
 | 
						|
    append_main "   %s.set_ip ip (i %S) >>= fun () ->"
 | 
						|
      mname (Ipaddr.V6.to_string t.config.address);
 | 
						|
    List.iter begin fun netmask ->
 | 
						|
      append_main "   %s.set_ip_netmask ip (i %S) >>= fun () ->"
 | 
						|
        mname (Ipaddr.V6.Prefix.to_string netmask)
 | 
						|
    end t.config.netmask;
 | 
						|
    append_main "   %s.set_ip_gateways ip [%s] >>= fun () ->"
 | 
						|
      mname
 | 
						|
      (String.concat "; "
 | 
						|
         (List.map
 | 
						|
            (fun n -> Printf.sprintf "(i %S)" (Ipaddr.V6.to_string n))
 | 
						|
            t.config.gateways));
 | 
						|
    append_main "   return (`Ok ip)";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.time;
 | 
						|
    Impl.clean t.clock;
 | 
						|
    Impl.clean t.ethernet
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { t with
 | 
						|
      time = Impl.update_path t.time root;
 | 
						|
      clock = Impl.update_path t.clock root;
 | 
						|
      ethernet = Impl.update_path t.ethernet root }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type v4
 | 
						|
type v6
 | 
						|
 | 
						|
type 'a ip = IP
 | 
						|
 | 
						|
let ip = Type IP
 | 
						|
 | 
						|
type ipv4 = v4 ip
 | 
						|
type ipv6 = v6 ip
 | 
						|
 | 
						|
let ipv4 : ipv4 typ = ip
 | 
						|
let ipv6 : ipv6 typ = ip
 | 
						|
 | 
						|
let create_ipv4 net config =
 | 
						|
  let etif = etif net in
 | 
						|
  let t = {
 | 
						|
    IPV4.ethernet = etif;
 | 
						|
    config } in
 | 
						|
  impl ipv4 t (module IPV4)
 | 
						|
 | 
						|
let default_ipv4_conf =
 | 
						|
  let i = Ipaddr.V4.of_string_exn in
 | 
						|
  {
 | 
						|
    address  = i "10.0.0.2";
 | 
						|
    netmask  = i "255.255.255.0";
 | 
						|
    gateways = [i "10.0.0.1"];
 | 
						|
  }
 | 
						|
 | 
						|
let default_ipv4 net =
 | 
						|
  create_ipv4 net default_ipv4_conf
 | 
						|
 | 
						|
let create_ipv6
 | 
						|
    ?(time = default_time)
 | 
						|
    ?(clock = default_clock)
 | 
						|
    net config =
 | 
						|
  let etif = etif net in
 | 
						|
  let t = {
 | 
						|
    IPV6.ethernet = etif;
 | 
						|
    time; clock;
 | 
						|
    config
 | 
						|
  } in
 | 
						|
  impl ipv6 t (module IPV6)
 | 
						|
 | 
						|
module UDP_direct (V : sig type t end) = struct
 | 
						|
 | 
						|
  type t = V.t ip impl
 | 
						|
 | 
						|
  let name t =
 | 
						|
    Name.of_key ("udp" ^ Impl.name t) ~base:"udp"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    Impl.packages t @ [ "tcpip" ]
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    Impl.libraries t @ [ "tcpip.udp" ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    Impl.configure t;
 | 
						|
    append_main "module %s = Udp.Make(%s)" (module_name t) (Impl.module_name t);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "   %s () >>= function" (Impl.name t);
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error name);
 | 
						|
    append_main "   | `Ok ip   -> %s.connect ip" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    Impl.update_path t root
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module UDPV4_socket = struct
 | 
						|
 | 
						|
  type t = Ipaddr.V4.t option
 | 
						|
 | 
						|
  let name _ = "udpv4_socket"
 | 
						|
 | 
						|
  let module_name _ = "Udpv4_socket"
 | 
						|
 | 
						|
  let packages t = [ "tcpip" ]
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> [ "tcpip.udpv4-socket" ]
 | 
						|
    | `Xen  -> failwith "No socket implementation available for Xen"
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    let ip = match t with
 | 
						|
      | None    -> "None"
 | 
						|
      | Some ip ->
 | 
						|
        Printf.sprintf "Some (Ipaddr.V4.of_string_exn %s)" (Ipaddr.V4.to_string ip)
 | 
						|
    in
 | 
						|
    append_main " %s.connect %S" (module_name t) ip;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    ()
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type 'a udp = UDP
 | 
						|
 | 
						|
type udpv4 = v4 udp
 | 
						|
type udpv6 = v6 udp
 | 
						|
 | 
						|
let udp = Type UDP
 | 
						|
let udpv4 : udpv4 typ = udp
 | 
						|
let udpv6 : udpv6 typ = udp
 | 
						|
 | 
						|
let direct_udp (type v) (ip : v ip impl) =
 | 
						|
  impl udp ip (module UDP_direct (struct type t = v end))
 | 
						|
 | 
						|
let socket_udpv4 ip =
 | 
						|
  impl udpv4 ip (module UDPV4_socket)
 | 
						|
 | 
						|
module TCP_direct (V : sig type t end) = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    clock : clock impl;
 | 
						|
    time  : time impl;
 | 
						|
    ip    : V.t ip impl;
 | 
						|
    random: random impl;
 | 
						|
  }
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "tcp"
 | 
						|
              ^ Impl.name t.clock
 | 
						|
              ^ Impl.name t.time
 | 
						|
              ^ Impl.name t.ip in
 | 
						|
    Name.of_key key ~base:"tcp"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    "tcpip"
 | 
						|
    :: Impl.packages t.clock
 | 
						|
    @  Impl.packages t.time
 | 
						|
    @  Impl.packages t.ip
 | 
						|
    @  Impl.packages t.random
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    "tcpip.tcp"
 | 
						|
    :: Impl.libraries t.clock
 | 
						|
    @  Impl.libraries t.time
 | 
						|
    @  Impl.libraries t.ip
 | 
						|
    @  Impl.libraries t.random
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    Impl.configure t.clock;
 | 
						|
    Impl.configure t.time;
 | 
						|
    Impl.configure t.ip;
 | 
						|
    Impl.configure t.random;
 | 
						|
    append_main "module %s = Tcp.Flow.Make(%s)(%s)(%s)(%s)"
 | 
						|
      (module_name t)
 | 
						|
      (Impl.module_name t.ip)
 | 
						|
      (Impl.module_name t.time)
 | 
						|
      (Impl.module_name t.clock)
 | 
						|
      (Impl.module_name t.random);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "   %s () >>= function" (Impl.name t.ip);
 | 
						|
    append_main "   | `Error _ -> %s" (driver_initialisation_error (Impl.name t.ip));
 | 
						|
    append_main "   | `Ok ip   -> %s.connect ip" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.clock;
 | 
						|
    Impl.clean t.time;
 | 
						|
    Impl.clean t.ip;
 | 
						|
    Impl.clean t.random
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { clock  = Impl.update_path t.clock root;
 | 
						|
      ip     = Impl.update_path t.ip root;
 | 
						|
      time   = Impl.update_path t.time root;
 | 
						|
      random = Impl.update_path t.random root;
 | 
						|
    }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module TCPV4_socket = struct
 | 
						|
 | 
						|
  type t = Ipaddr.V4.t option
 | 
						|
 | 
						|
  let name _ = "tcpv4_socket"
 | 
						|
 | 
						|
  let module_name _ = "Tcpv4_socket"
 | 
						|
 | 
						|
  let packages t = [ "tcpip" ]
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> [ "tcpip.tcpv4-socket" ]
 | 
						|
    | `Xen  -> failwith "No socket implementation available for Xen"
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    let ip = match t with
 | 
						|
      | None    -> "None"
 | 
						|
      | Some ip ->
 | 
						|
        Printf.sprintf "Some (Ipaddr.V4.of_string_exn %s)" (Ipaddr.V4.to_string ip)
 | 
						|
    in
 | 
						|
    append_main "  %s.connect %S" (module_name t) ip;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    ()
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type 'a tcp = TCP
 | 
						|
 | 
						|
type tcpv4 = v4 tcp
 | 
						|
type tcpv6 = v6 tcp
 | 
						|
 | 
						|
let tcp = Type TCP
 | 
						|
let tcpv4 : tcpv4 typ = tcp
 | 
						|
let tcpv6 : tcpv6 typ = tcp
 | 
						|
 | 
						|
let direct_tcp (type v)
 | 
						|
    ?(clock=default_clock) ?(random=default_random) ?(time=default_time) (ip : v ip impl) =
 | 
						|
  let module TCP_direct = TCP_direct (struct type t = v end) in
 | 
						|
  let t = { TCP_direct.clock; random; time; ip } in
 | 
						|
  impl tcp t (module TCP_direct)
 | 
						|
 | 
						|
let socket_tcpv4 ip =
 | 
						|
  impl tcpv4 ip (module TCPV4_socket)
 | 
						|
 | 
						|
module STACKV4_direct = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    clock  : clock impl;
 | 
						|
    time   : time impl;
 | 
						|
    console: console impl;
 | 
						|
    network: network impl;
 | 
						|
    random : random impl;
 | 
						|
    config : [`DHCP | `IPV4 of ipv4_config];
 | 
						|
  }
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "stackv4"
 | 
						|
              ^ Impl.name t.clock
 | 
						|
              ^ Impl.name t.time
 | 
						|
              ^ Impl.name t.console
 | 
						|
              ^ Impl.name t.network
 | 
						|
              ^ Impl.name t.random
 | 
						|
              ^ match t.config with
 | 
						|
              | `DHCP   -> "dhcp"
 | 
						|
              | `IPV4 i -> meta_ipv4_config i in
 | 
						|
    Name.of_key key ~base:"stackv4"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    "tcpip"
 | 
						|
    :: Impl.packages t.clock
 | 
						|
    @  Impl.packages t.time
 | 
						|
    @  Impl.packages t.console
 | 
						|
    @  Impl.packages t.network
 | 
						|
    @  Impl.packages t.random
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    "tcpip.stack-direct"
 | 
						|
    :: "mirage.runtime"
 | 
						|
    :: Impl.libraries t.clock
 | 
						|
    @  Impl.libraries t.time
 | 
						|
    @  Impl.libraries t.console
 | 
						|
    @  Impl.libraries t.network
 | 
						|
    @  Impl.libraries t.random
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    Impl.configure t.clock;
 | 
						|
    Impl.configure t.time;
 | 
						|
    Impl.configure t.console;
 | 
						|
    Impl.configure t.network;
 | 
						|
    Impl.configure t.random;
 | 
						|
    append_main "module %s = struct" (module_name t);
 | 
						|
    append_main "  module E = Ethif.Make(%s)" (Impl.module_name t.network);
 | 
						|
    append_main "  module I = Ipv4.Make(E)";
 | 
						|
    append_main "  module U = Udp.Make(I)";
 | 
						|
    append_main "  module T = Tcp.Flow.Make(I)(%s)(%s)(%s)"
 | 
						|
      (Impl.module_name t.time)
 | 
						|
      (Impl.module_name t.clock)
 | 
						|
      (Impl.module_name t.random);
 | 
						|
    append_main "  module S = Tcpip_stack_direct.Make(%s)(%s)(%s)(%s)(E)(I)(U)(T)"
 | 
						|
      (Impl.module_name t.console)
 | 
						|
      (Impl.module_name t.time)
 | 
						|
      (Impl.module_name t.random)
 | 
						|
      (Impl.module_name t.network);
 | 
						|
    append_main "  include S";
 | 
						|
    append_main "end";
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "  %s () >>= function" (Impl.name t.console);
 | 
						|
    append_main "  | `Error _    -> %s"
 | 
						|
      (driver_initialisation_error (Impl.name t.console));
 | 
						|
    append_main "  | `Ok console ->";
 | 
						|
    append_main "  %s () >>= function" (Impl.name t.network);
 | 
						|
    append_main "  | `Error e      ->";
 | 
						|
    let net_init_error_msg_fn = "Mirage_runtime.string_of_network_init_error" in
 | 
						|
    append_main "    fail (Failure (%s %S e))"
 | 
						|
      net_init_error_msg_fn (Impl.name t.network);
 | 
						|
    append_main "  | `Ok interface ->";
 | 
						|
    append_main "  let config = {";
 | 
						|
    append_main "    V1_LWT.name = %S;" name;
 | 
						|
    append_main "    console; interface;";
 | 
						|
    begin match t.config with
 | 
						|
      | `DHCP   -> append_main "    mode = `DHCP;"
 | 
						|
      | `IPV4 i -> append_main "    mode = `IPv4 %s;" (meta_ipv4_config i);
 | 
						|
    end;
 | 
						|
    append_main "  } in";
 | 
						|
    append_main "  %s.connect config" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.clock;
 | 
						|
    Impl.clean t.time;
 | 
						|
    Impl.clean t.console;
 | 
						|
    Impl.clean t.network;
 | 
						|
    Impl.clean t.random
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { t with
 | 
						|
      clock   = Impl.update_path t.clock root;
 | 
						|
      time    = Impl.update_path t.time root;
 | 
						|
      console = Impl.update_path t.console root;
 | 
						|
      network = Impl.update_path t.network root;
 | 
						|
      random  = Impl.update_path t.random root;
 | 
						|
    }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module STACKV4_socket = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    console: console impl;
 | 
						|
    ipv4s  : Ipaddr.V4.t list;
 | 
						|
  }
 | 
						|
 | 
						|
  let meta_ips ips =
 | 
						|
    String.concat "; "
 | 
						|
      (List.map (fun x ->
 | 
						|
           Printf.sprintf "Ipaddr.V4.of_string_exn %S" (Ipaddr.V4.to_string x)
 | 
						|
         ) ips)
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "stackv4" ^ Impl.name t.console ^ meta_ips t.ipv4s in
 | 
						|
    Name.of_key key ~base:"stackv4"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    "tcpip" :: Impl.packages t.console
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    "tcpip.stack-socket" :: Impl.libraries t.console
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let name = name t in
 | 
						|
    Impl.configure t.console;
 | 
						|
    append_main "module %s = Tcpip_stack_socket.Make(%s)"
 | 
						|
      (module_name t) (Impl.module_name t.console);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" name;
 | 
						|
    append_main "  %s () >>= function" (Impl.name t.console);
 | 
						|
    append_main "  | `Error _    -> %s"
 | 
						|
      (driver_initialisation_error (Impl.name t.console));
 | 
						|
    append_main "  | `Ok console ->";
 | 
						|
    append_main "  let config = {";
 | 
						|
    append_main "    V1_LWT.name = %S;" name;
 | 
						|
    append_main "    console; interface = [%s];" (meta_ips t.ipv4s);
 | 
						|
    append_main "    mode = ();";
 | 
						|
    append_main "  } in";
 | 
						|
    append_main "  %s.connect config" (module_name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.console
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { t with console = Impl.update_path t.console root }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type stackv4 = STACKV4
 | 
						|
 | 
						|
let stackv4 = Type STACKV4
 | 
						|
 | 
						|
let direct_stackv4_with_dhcp
 | 
						|
    ?(clock=default_clock)
 | 
						|
    ?(random=default_random)
 | 
						|
    ?(time=default_time)
 | 
						|
    console network =
 | 
						|
  let t = {
 | 
						|
    STACKV4_direct.console; network; time; clock; random;
 | 
						|
    config = `DHCP } in
 | 
						|
  impl stackv4 t (module STACKV4_direct)
 | 
						|
 | 
						|
let direct_stackv4_with_default_ipv4
 | 
						|
    ?(clock=default_clock)
 | 
						|
    ?(random=default_random)
 | 
						|
    ?(time=default_time)
 | 
						|
    console network =
 | 
						|
  let t = {
 | 
						|
    STACKV4_direct.console; network; clock; time; random;
 | 
						|
    config = `IPV4 default_ipv4_conf;
 | 
						|
  } in
 | 
						|
  impl stackv4 t (module STACKV4_direct)
 | 
						|
 | 
						|
let direct_stackv4_with_static_ipv4
 | 
						|
    ?(clock=default_clock)
 | 
						|
    ?(random=default_random)
 | 
						|
    ?(time=default_time)
 | 
						|
    console network ipv4 =
 | 
						|
  let t = {
 | 
						|
    STACKV4_direct.console; network; clock; time; random;
 | 
						|
    config = `IPV4 ipv4;
 | 
						|
  } in
 | 
						|
  impl stackv4 t (module STACKV4_direct)
 | 
						|
 | 
						|
let socket_stackv4 console ipv4s =
 | 
						|
  impl stackv4 { STACKV4_socket.console; ipv4s } (module STACKV4_socket)
 | 
						|
 | 
						|
module Channel_over_TCP (V : sig type t end) = struct
 | 
						|
 | 
						|
  type t = V.t tcp impl
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "channel" ^ Impl.name t in
 | 
						|
    Name.of_key key ~base:"channel"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages _ =
 | 
						|
    [ "mirage-tcpip" ]
 | 
						|
 | 
						|
  let libraries _ =
 | 
						|
    [ "tcpip.channel" ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    Impl.configure t;
 | 
						|
    append_main "module %s = Channel.Make(%s)" (module_name t) (Impl.module_name t);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s () >>= function" (Impl.name t);
 | 
						|
    append_main "  | `Error _    -> %s" (driver_initialisation_error (Impl.name t));
 | 
						|
    append_main "  | `Ok console ->";
 | 
						|
    append_main "  let flow = %s.create config in" (module_name t);
 | 
						|
    append_main "  return (`Ok flow)";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    Impl.update_path t root
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type channel = CHANNEL
 | 
						|
 | 
						|
let channel = Type CHANNEL
 | 
						|
 | 
						|
let channel_over_tcp (type v) (flow : v tcp impl) =
 | 
						|
  impl channel flow (module Channel_over_TCP (struct type t = v end))
 | 
						|
 | 
						|
module VCHAN_localhost = struct
 | 
						|
 | 
						|
  type uuid = string
 | 
						|
  type t = uuid
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "in_memory" in
 | 
						|
    Name.of_key key ~base:"vchan"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    [ "mirage-conduit" ]
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    [ "conduit.mirage" ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "module %s = Conduit_localhost" (module_name t);
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s = %s.register %S" (name t) (module_name t) t;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t = ()
 | 
						|
 | 
						|
  let update_path t root = t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module VCHAN_xenstore = struct
 | 
						|
 | 
						|
  type uuid = string
 | 
						|
  type t = string
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "xen" in
 | 
						|
    Name.of_key key ~base:"vchan"
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    match !mode with
 | 
						|
    |`Xen -> [ "vchan"; "mirage-xen"; "xen-evtchn"; "xen-gnt" ]
 | 
						|
    |`Unix | `MacOSX -> [ "vchan"; "xen-evtchn"; "xen-gnt"]
 | 
						|
    (* TODO: emit a failure on MacOSX? *)
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    match !mode with
 | 
						|
    |`Xen -> [ "conduit.mirage-xen" ]
 | 
						|
    |`Unix | `MacOSX-> [ "vchan" ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    let m =
 | 
						|
      match !mode with
 | 
						|
      |`Xen -> "Conduit_xenstore"
 | 
						|
      |`Unix | `MacOSX -> "Vchan_lwt_unix.M"
 | 
						|
    in
 | 
						|
    append_main "module %s = %s" (module_name t) m;
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s = %s.register %S" (name t) (module_name t) t;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t = ()
 | 
						|
 | 
						|
  let update_path t root = t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type vchan = STACK4
 | 
						|
 | 
						|
let vchan = Type STACK4
 | 
						|
 | 
						|
let vchan_localhost ?(uuid="localhost") () =
 | 
						|
  impl vchan uuid (module VCHAN_localhost)
 | 
						|
 | 
						|
let vchan_xen ?(uuid="localhost") () =
 | 
						|
  impl vchan uuid (module VCHAN_xenstore)
 | 
						|
 | 
						|
let vchan_default ?uuid () =
 | 
						|
  match !mode with
 | 
						|
  | `Xen -> vchan_xen ?uuid ()
 | 
						|
  | `Unix | `MacOSX -> vchan_localhost ?uuid ()
 | 
						|
 | 
						|
module Conduit = struct
 | 
						|
  type t =
 | 
						|
    [ `Stack of stackv4 impl * vchan impl ]
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "conduit" ^ match t with
 | 
						|
     | `Stack (s,v) ->
 | 
						|
          Printf.sprintf "%s_%s" (Impl.name s) (Impl.name v) in
 | 
						|
    Name.of_key key ~base:"conduit"
 | 
						|
 | 
						|
  let module_name_core t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    module_name_core t
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    [ "conduit"; "mirage-types"; "vchan" ] @
 | 
						|
    match t with
 | 
						|
    | `Stack (s,v) -> Impl.packages s @ (Impl.packages v)
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    [ "conduit.mirage" ] @
 | 
						|
    match t with
 | 
						|
    | `Stack (s,v) -> Impl.libraries s @ (Impl.libraries v)
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    begin match t with
 | 
						|
      | `Stack (s,v) ->
 | 
						|
        Impl.configure s;
 | 
						|
        Impl.configure v;
 | 
						|
        append_main "module %s = Conduit_mirage.Make(%s)(%s)"
 | 
						|
          (module_name_core t) (Impl.module_name s) (Impl.module_name v);
 | 
						|
    end;
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    let (stack_subname, vchan_subname) = match t with
 | 
						|
      | `Stack (s,v) -> Impl.name s, Impl.name v in
 | 
						|
 | 
						|
    append_main "  %s () >>= function" stack_subname;
 | 
						|
    append_main "  | `Error _  -> %s" (driver_initialisation_error stack_subname);
 | 
						|
    append_main "  | `Ok %s ->" stack_subname;
 | 
						|
    append_main "  %s >>= fun %s ->" vchan_subname vchan_subname;
 | 
						|
    append_main "  %s.init ~peer:%s ~stack:%s () >>= fun %s ->"
 | 
						|
      (module_name_core t) vchan_subname stack_subname (name t);
 | 
						|
    append_main "  return (`Ok %s)" (name t);
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean = function
 | 
						|
    | `Stack (s,v) -> Impl.clean s; Impl.clean v
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    match t with
 | 
						|
    | `Stack (s,v) ->
 | 
						|
        `Stack ((Impl.update_path s root), (Impl.update_path v root))
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type conduit = Conduit
 | 
						|
 | 
						|
let conduit = Type Conduit
 | 
						|
 | 
						|
let conduit_direct ?(vchan=vchan_localhost ()) stack =
 | 
						|
  impl conduit (`Stack (stack,vchan)) (module Conduit)
 | 
						|
 | 
						|
type conduit_client = [
 | 
						|
  | `TCP of Ipaddr.t * int
 | 
						|
  | `Vchan of string list
 | 
						|
]
 | 
						|
 | 
						|
type conduit_server = [
 | 
						|
  | `TCP of [ `Port of int ]
 | 
						|
  | `Vchan of string list
 | 
						|
]
 | 
						|
 | 
						|
module Resolver_unix = struct
 | 
						|
  type t = unit
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "resolver_unix" in
 | 
						|
    Name.of_key key ~base:"resolver"
 | 
						|
 | 
						|
  let module_name_core t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
      module_name_core t
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    match !mode with
 | 
						|
    |`Unix | `MacOSX -> [ "mirage-conduit" ]
 | 
						|
    |`Xen -> failwith "Resolver_unix not supported on Xen"
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    [ "conduit.mirage"; "conduit.lwt-unix" ]
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    append_main "module %s = Resolver_lwt" (module_name t);
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  return (`Ok Resolver_lwt_unix.system)";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t = ()
 | 
						|
 | 
						|
  let update_path t root = t
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module Resolver_direct = struct
 | 
						|
  type t =
 | 
						|
    [ `DNS of stackv4 impl * Ipaddr.V4.t option * int option ]
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "resolver" ^ match t with
 | 
						|
     | `DNS (s,_,_) -> Impl.name s in
 | 
						|
    Name.of_key key ~base:"resolver"
 | 
						|
 | 
						|
  let module_name_core t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    (module_name_core t) ^ "_res"
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    [ "dns"; "tcpip" ] @
 | 
						|
    match t with
 | 
						|
    | `DNS (s,_,_) -> Impl.packages s
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    [ "dns.mirage" ] @
 | 
						|
    match t with
 | 
						|
    | `DNS (s,_,_) -> Impl.libraries s
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    begin match t with
 | 
						|
      | `DNS (s,_,_) ->
 | 
						|
        Impl.configure s;
 | 
						|
        append_main "module %s = Resolver_lwt" (module_name t);
 | 
						|
        append_main "module %s_dns = Dns_resolver_mirage.Make(OS.Time)(%s)"
 | 
						|
          (module_name_core t) (Impl.module_name s);
 | 
						|
        append_main "module %s = Resolver_mirage.Make(%s_dns)"
 | 
						|
          (module_name_core t) (module_name_core t);
 | 
						|
    end;
 | 
						|
    newline_main ();
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    let subname = match t with
 | 
						|
      | `DNS (s,_,_) -> Impl.name s in
 | 
						|
    append_main "  %s () >>= function" subname;
 | 
						|
    append_main "  | `Error _  -> %s" (driver_initialisation_error subname);
 | 
						|
    append_main "  | `Ok %s ->" subname;
 | 
						|
    let res_ns = match t with
 | 
						|
     | `DNS (_,None,_) -> "None"
 | 
						|
     | `DNS (_,Some ns,_) ->
 | 
						|
         Printf.sprintf "Ipaddr.V4.of_string %S" (Ipaddr.V4.to_string ns) in
 | 
						|
    append_main "  let ns = %s in" res_ns;
 | 
						|
    let res_ns_port = match t with
 | 
						|
     | `DNS (_,_,None) -> "None"
 | 
						|
     | `DNS (_,_,Some ns_port) -> Printf.sprintf "Some %d" ns_port in
 | 
						|
    append_main "  let ns_port = %s in" res_ns_port;
 | 
						|
    append_main "  let res = %s.init ?ns ?ns_port ~stack:%s () in" (module_name_core t) subname;
 | 
						|
    append_main "  return (`Ok res)";
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean = function
 | 
						|
    | `DNS (s,_,_) -> Impl.clean s
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    match t with
 | 
						|
    | `DNS (s,a,b) -> `DNS (Impl.update_path s root, a, b)
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type resolver = Resolver
 | 
						|
 | 
						|
let resolver = Type Resolver
 | 
						|
 | 
						|
let resolver_dns ?ns ?ns_port stack =
 | 
						|
  impl resolver (`DNS (stack, ns, ns_port)) (module Resolver_direct)
 | 
						|
 | 
						|
let resolver_unix_system =
 | 
						|
  impl resolver () (module Resolver_unix)
 | 
						|
 | 
						|
module HTTP = struct
 | 
						|
 | 
						|
  type t =
 | 
						|
    [ `Channel of channel impl
 | 
						|
    | `Stack of conduit_server * conduit impl ]
 | 
						|
 | 
						|
  let name t =
 | 
						|
    let key = "http" ^ match t with
 | 
						|
      | `Channel c    -> Impl.name c
 | 
						|
      | `Stack (_, c) -> Impl.name c in
 | 
						|
    Name.of_key key ~base:"http"
 | 
						|
 | 
						|
  let module_name_core t =
 | 
						|
    String.capitalize (name t)
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    module_name_core t ^ ".Server"
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    [ "mirage-http" ] @
 | 
						|
    match t with
 | 
						|
    | `Channel c    -> Impl.packages c
 | 
						|
    | `Stack (_, c) -> Impl.packages c
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    [ "mirage-http" ] @
 | 
						|
    match t with
 | 
						|
    | `Channel c    -> Impl.libraries c
 | 
						|
    | `Stack (_, c) -> Impl.libraries c
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    begin match t with
 | 
						|
      | `Channel c ->
 | 
						|
        Impl.configure c;
 | 
						|
        append_main "module %s = HTTP.Make(%s)" (module_name_core t) (Impl.module_name c)
 | 
						|
      | `Stack (_, c) ->
 | 
						|
        Impl.configure c;
 | 
						|
        append_main "module %s = HTTP.Make(%s)" (module_name_core t) (Impl.module_name c)
 | 
						|
    end;
 | 
						|
    newline_main ();
 | 
						|
    let subname = match t with
 | 
						|
      | `Channel c   -> Impl.name c
 | 
						|
      | `Stack (_,c) -> Impl.name c in
 | 
						|
    append_main "let %s () =" (name t);
 | 
						|
    append_main "  %s () >>= function" subname;
 | 
						|
    append_main "  | `Error _  -> %s" (driver_initialisation_error subname);
 | 
						|
    append_main "  | `Ok %s ->" subname;
 | 
						|
    begin match t with
 | 
						|
      | `Channel c   -> failwith "TODO"
 | 
						|
      | `Stack (m,c) ->
 | 
						|
        append_main "  let listen spec =";
 | 
						|
        append_main "    let ctx = %s in" (Impl.name c);
 | 
						|
        append_main "    let mode = %s in"
 | 
						|
          (match m with
 | 
						|
           |`TCP (`Port port) -> Printf.sprintf "`TCP (`Port %d)" port
 | 
						|
           |`Vchan l -> failwith "Vchan not supported yet in server"
 | 
						|
          );
 | 
						|
        append_main "    %s.serve ~ctx ~mode (%s.Server.listen spec)" (Impl.module_name c) (module_name_core t);
 | 
						|
        append_main "  in";
 | 
						|
        append_main "  return (`Ok listen)";
 | 
						|
    end;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean = function
 | 
						|
    | `Channel c    -> Impl.clean c
 | 
						|
    | `Stack (_,c) -> Impl.clean c
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    match t with
 | 
						|
    | `Channel c    -> `Channel (Impl.update_path c root)
 | 
						|
    | `Stack (m, c) -> `Stack (m, Impl.update_path c root)
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
type http = HTTP
 | 
						|
 | 
						|
let http = Type HTTP
 | 
						|
 | 
						|
let http_server_of_channel chan =
 | 
						|
  impl http (`Channel chan) (module HTTP)
 | 
						|
 | 
						|
let http_server mode conduit =
 | 
						|
  impl http (`Stack (mode, conduit)) (module HTTP)
 | 
						|
 | 
						|
type job = JOB
 | 
						|
 | 
						|
let job = Type JOB
 | 
						|
 | 
						|
module Job = struct
 | 
						|
 | 
						|
  type t = {
 | 
						|
    name: string;
 | 
						|
    impl: job impl;
 | 
						|
  }
 | 
						|
 | 
						|
  let create impl =
 | 
						|
    let name = Name.create "job" in
 | 
						|
    { name; impl }
 | 
						|
 | 
						|
  let name t =
 | 
						|
    t.name
 | 
						|
 | 
						|
  let module_name t =
 | 
						|
    "Job_" ^ t.name
 | 
						|
 | 
						|
  let packages t =
 | 
						|
    Impl.packages t.impl
 | 
						|
 | 
						|
  let libraries t =
 | 
						|
    Impl.libraries t.impl
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    Impl.configure t.impl;
 | 
						|
    newline_main ()
 | 
						|
 | 
						|
  let clean t =
 | 
						|
    Impl.clean t.impl
 | 
						|
 | 
						|
  let update_path t root =
 | 
						|
    { t with impl = Impl.update_path t.impl root }
 | 
						|
 | 
						|
end
 | 
						|
 | 
						|
module Tracing = struct
 | 
						|
  type t = {
 | 
						|
    size : int;
 | 
						|
  }
 | 
						|
 | 
						|
  let unix_trace_file = "trace.ctf"
 | 
						|
 | 
						|
  let packages _ = StringSet.singleton "mirage-profile"
 | 
						|
 | 
						|
  let libraries _ =
 | 
						|
    match !mode with
 | 
						|
    | `Unix | `MacOSX -> StringSet.singleton "mirage-profile.unix"
 | 
						|
    | `Xen  -> StringSet.singleton "mirage-profile.xen"
 | 
						|
 | 
						|
  let configure t =
 | 
						|
    if Sys.command "ocamlfind query lwt.tracing 2>/dev/null" <> 0 then (
 | 
						|
      flush stdout;
 | 
						|
      error "lwt.tracing module not found. Hint:\n\
 | 
						|
             opam pin add lwt 'https://github.com/mirage/lwt.git#tracing'"
 | 
						|
    );
 | 
						|
 | 
						|
    append_main "let () = ";
 | 
						|
    begin match !mode with
 | 
						|
    | `Unix | `MacOSX ->
 | 
						|
        append_main "  let buffer = MProf_unix.mmap_buffer ~size:%d %S in" t.size unix_trace_file;
 | 
						|
        append_main "  let trace_config = MProf.Trace.Control.make buffer MProf_unix.timestamper in";
 | 
						|
        append_main "  MProf.Trace.Control.start trace_config";
 | 
						|
    | `Xen  ->
 | 
						|
        append_main "  let trace_pages = MProf_xen.make_shared_buffer ~size:%d in" t.size;
 | 
						|
        append_main "  let buffer = trace_pages |> Io_page.to_cstruct |> Cstruct.to_bigarray in";
 | 
						|
        append_main "  let trace_config = MProf.Trace.Control.make buffer MProf_xen.timestamper in";
 | 
						|
        append_main "  MProf.Trace.Control.start trace_config;";
 | 
						|
        append_main "  MProf_xen.share_with (module Gnt.Gntshr) (module OS.Xs) ~domid:0 trace_pages";
 | 
						|
        append_main "  |> OS.Main.run";
 | 
						|
    end;
 | 
						|
    newline_main ()
 | 
						|
end
 | 
						|
 | 
						|
type tracing = Tracing.t
 | 
						|
 | 
						|
let mprof_trace ~size () =
 | 
						|
  { Tracing.size }
 | 
						|
 | 
						|
type t = {
 | 
						|
  name: string;
 | 
						|
  root: string;
 | 
						|
  jobs: job impl list;
 | 
						|
  tracing: tracing option;
 | 
						|
}
 | 
						|
 | 
						|
let t = ref None
 | 
						|
 | 
						|
let config_file = ref None
 | 
						|
 | 
						|
let reset () =
 | 
						|
  config_file := None;
 | 
						|
  t := None
 | 
						|
 | 
						|
let set_config_file f =
 | 
						|
  config_file := Some f
 | 
						|
 | 
						|
let get_config_file () =
 | 
						|
  match !config_file with
 | 
						|
  | None -> Sys.getcwd () / "config.ml"
 | 
						|
  | Some f -> f
 | 
						|
 | 
						|
let update_path t root =
 | 
						|
  { t with jobs = List.map (fun j -> Impl.update_path j root) t.jobs }
 | 
						|
 | 
						|
let register ?tracing name jobs =
 | 
						|
  let root = match !config_file with
 | 
						|
    | None   -> failwith "no config file"
 | 
						|
    | Some f -> Filename.dirname f in
 | 
						|
  t := Some { name; jobs; root; tracing }
 | 
						|
 | 
						|
let registered () =
 | 
						|
  match !t with
 | 
						|
  | None   -> { name = "empty"; jobs = []; root = Sys.getcwd (); tracing = None }
 | 
						|
  | Some t -> t
 | 
						|
 | 
						|
let ps = ref StringSet.empty
 | 
						|
 | 
						|
let add_to_opam_packages p =
 | 
						|
  ps := StringSet.union (StringSet.of_list p) !ps
 | 
						|
 | 
						|
let packages t =
 | 
						|
  let m = match !mode with
 | 
						|
    | `Unix | `MacOSX -> "mirage-unix"
 | 
						|
    | `Xen  -> "mirage-xen" in
 | 
						|
  let ps = StringSet.add m !ps in
 | 
						|
  let ps = match t.tracing with
 | 
						|
    | None -> ps
 | 
						|
    | Some tracing -> StringSet.union (Tracing.packages tracing) ps in
 | 
						|
  let ps = List.fold_left (fun set j ->
 | 
						|
      let ps = StringSet.of_list (Impl.packages j) in
 | 
						|
      StringSet.union ps set
 | 
						|
    ) ps t.jobs in
 | 
						|
  StringSet.elements ps
 | 
						|
 | 
						|
let ls = ref StringSet.empty
 | 
						|
 | 
						|
let add_to_ocamlfind_libraries l =
 | 
						|
  ls := StringSet.union !ls (StringSet.of_list l)
 | 
						|
 | 
						|
let libraries t =
 | 
						|
  let m = match !mode with
 | 
						|
    | `Unix | `MacOSX -> "mirage-types.lwt"
 | 
						|
    | `Xen  -> "mirage-types.lwt" in
 | 
						|
  let ls = StringSet.add m !ls in
 | 
						|
  let ls = match t.tracing with
 | 
						|
    | None -> ls
 | 
						|
    | Some tracing -> StringSet.union (Tracing.libraries tracing) ls in
 | 
						|
  let ls = List.fold_left (fun set j ->
 | 
						|
      let ls = StringSet.of_list (Impl.libraries j) in
 | 
						|
      StringSet.union ls set
 | 
						|
    ) ls t.jobs in
 | 
						|
  StringSet.elements ls
 | 
						|
 | 
						|
let configure_myocamlbuild_ml t =
 | 
						|
  let minor, major = ocaml_version () in
 | 
						|
  if minor < 4 || major < 1 then (
 | 
						|
    (* Previous ocamlbuild versions weren't able to understand the
 | 
						|
       --output-obj rules *)
 | 
						|
    let file = t.root / "myocamlbuild.ml" in
 | 
						|
    let oc = open_out file in
 | 
						|
    append oc "(* %s *)" generated_by_mirage;
 | 
						|
    newline oc;
 | 
						|
    append oc
 | 
						|
      "open Ocamlbuild_pack;;\n\
 | 
						|
       open Ocamlbuild_plugin;;\n\
 | 
						|
       open Ocaml_compiler;;\n\
 | 
						|
       \n\
 | 
						|
       let native_link_gen linker =\n\
 | 
						|
      \  link_gen \"cmx\" \"cmxa\" !Options.ext_lib [!Options.ext_obj; \"cmi\"] linker;;\n\
 | 
						|
       \n\
 | 
						|
       let native_output_obj x = native_link_gen ocamlopt_link_prog\n\
 | 
						|
      \  (fun tags -> tags++\"ocaml\"++\"link\"++\"native\"++\"output_obj\") x;;\n\
 | 
						|
       \n\
 | 
						|
       rule \"ocaml: cmx* & o* -> native.o\"\n\
 | 
						|
      \  ~tags:[\"ocaml\"; \"native\"; \"output_obj\" ]\n\
 | 
						|
      \  ~prod:\"%%.native.o\" ~deps:[\"%%.cmx\"; \"%%.o\"]\n\
 | 
						|
      \  (native_output_obj \"%%.cmx\" \"%%.native.o\");;\n\
 | 
						|
       \n\
 | 
						|
       \n\
 | 
						|
       let byte_link_gen = link_gen \"cmo\" \"cma\" \"cma\" [\"cmo\"; \"cmi\"];;\n\
 | 
						|
       let byte_output_obj = byte_link_gen ocamlc_link_prog\n\
 | 
						|
      \  (fun tags -> tags++\"ocaml\"++\"link\"++\"byte\"++\"output_obj\");;\n\
 | 
						|
       \n\
 | 
						|
       rule \"ocaml: cmo* -> byte.o\"\n\
 | 
						|
      \  ~tags:[\"ocaml\"; \"byte\"; \"link\"; \"output_obj\" ]\n\
 | 
						|
       ~prod:\"%%.byte.o\" ~dep:\"%%.cmo\"\n\
 | 
						|
      \  (byte_output_obj \"%%.cmo\" \"%%.byte.o\");;";
 | 
						|
    close_out oc
 | 
						|
  )
 | 
						|
 | 
						|
let clean_myocamlbuild_ml t =
 | 
						|
  remove (t.root / "myocamlbuild.ml")
 | 
						|
 | 
						|
let configure_main_libvirt_xml t =
 | 
						|
  let file = t.root / t.name ^ "_libvirt.xml" in
 | 
						|
  let oc = open_out file in
 | 
						|
  append oc "<!-- %s -->" generated_by_mirage;
 | 
						|
  append oc "<domain type='xen'>";
 | 
						|
  append oc "    <name>%s</name>" t.name;
 | 
						|
  append oc "    <memory unit='KiB'>262144</memory>";
 | 
						|
  append oc "    <currentMemory unit='KiB'>262144</currentMemory>";
 | 
						|
  append oc "    <vcpu placement='static'>1</vcpu>";
 | 
						|
  append oc "    <os>";
 | 
						|
  append oc "        <type arch='armv7l' machine='xenpv'>linux</type>";
 | 
						|
  append oc "        <kernel>%s/mir-%s.xen</kernel>" t.root t.name;
 | 
						|
  append oc "        <cmdline> </cmdline>"; (* the libxl driver currently needs an empty cmdline to be able to start the domain on arm - due to this? http://lists.xen.org/archives/html/xen-devel/2014-02/msg02375.html *)
 | 
						|
  append oc "    </os>";
 | 
						|
  append oc "    <clock offset='utc' adjustment='reset'/>";
 | 
						|
  append oc "    <on_crash>preserve</on_crash>";
 | 
						|
  append oc "    <!-- ";
 | 
						|
  append oc "    You must define network and block interfaces manually.";
 | 
						|
  append oc "    See http://libvirt.org/drvxen.html for information about converting .xl-files to libvirt xml automatically.";
 | 
						|
  append oc "    -->";
 | 
						|
  append oc "    <devices>";
 | 
						|
  append oc "        <!--";
 | 
						|
  append oc "        The disk configuration is defined here:";
 | 
						|
  append oc "        http://libvirt.org/formatstorage.html.";
 | 
						|
  append oc "        An example would look like:";
 | 
						|
  append oc"         <disk type='block' device='disk'>";
 | 
						|
  append oc "            <driver name='phy'/>";
 | 
						|
  append oc "            <source dev='/dev/loop0'/>";
 | 
						|
  append oc "            <target dev='' bus='xen'/>";
 | 
						|
  append oc "        </disk>";
 | 
						|
  append oc "        -->";
 | 
						|
  append oc "        <!-- ";
 | 
						|
  append oc "        The network configuration is defined here:";
 | 
						|
  append oc "        http://libvirt.org/formatnetwork.html";
 | 
						|
  append oc "        An example would look like:";
 | 
						|
  append oc "        <interface type='bridge'>";
 | 
						|
  append oc "            <mac address='c0:ff:ee:c0:ff:ee'/>";
 | 
						|
  append oc "            <source bridge='br0'/>";
 | 
						|
  append oc "        </interface>";
 | 
						|
  append oc "        -->";
 | 
						|
  append oc "        <console type='pty'>";
 | 
						|
  append oc "            <target type='xen' port='0'/>";
 | 
						|
  append oc "        </console>";
 | 
						|
  append oc "    </devices>";
 | 
						|
  append oc "</domain>";
 | 
						|
  close_out oc
 | 
						|
 | 
						|
let clean_main_libvirt_xml t =
 | 
						|
  remove (t.root / t.name ^ "_libvirt.xml")
 | 
						|
 | 
						|
let configure_main_xl t =
 | 
						|
  let file = t.root / t.name ^ ".xl" in
 | 
						|
  let oc = open_out file in
 | 
						|
  append oc "# %s" generated_by_mirage;
 | 
						|
  newline oc;
 | 
						|
  append oc "name = '%s'" t.name;
 | 
						|
  append oc "kernel = '%s/mir-%s.xen'" t.root t.name;
 | 
						|
  append oc "builder = 'linux'";
 | 
						|
  append oc "memory = 256";
 | 
						|
  append oc "on_crash = 'preserve'";
 | 
						|
  newline oc;
 | 
						|
  append oc "# You must define the network and block interfaces manually.";
 | 
						|
  newline oc;
 | 
						|
  append oc "# The disk configuration is defined here:";
 | 
						|
  append oc "# http://xenbits.xen.org/docs/4.3-testing/misc/xl-disk-configuration.txt";
 | 
						|
  append oc "# An example would look like:";
 | 
						|
  append oc "# disk = [ '/dev/loop0,,xvda' ]";
 | 
						|
  newline oc;
 | 
						|
  append oc "# The network configuration is defined here:";
 | 
						|
  append oc "# http://xenbits.xen.org/docs/4.3-testing/misc/xl-network-configuration.html";
 | 
						|
  append oc "# An example would look like:";
 | 
						|
  append oc "# vif = [ 'mac=c0:ff:ee:c0:ff:ee,bridge=br0' ]";
 | 
						|
  close_out oc
 | 
						|
 | 
						|
let clean_main_xl t =
 | 
						|
  remove (t.root / t.name ^ ".xl")
 | 
						|
 | 
						|
let configure_main_xe t =
 | 
						|
  let file = t.root / t.name ^ ".xe" in
 | 
						|
  let oc = open_out file in
 | 
						|
  append oc "#!/bin/sh";
 | 
						|
  append oc "# %s" generated_by_mirage;
 | 
						|
  newline oc;
 | 
						|
  append oc "set -e";
 | 
						|
  newline oc;
 | 
						|
  append oc "# Dependency: xe";
 | 
						|
  append oc "command -v xe >/dev/null 2>&1 || { echo >&2 \"I require xe but it's not installed.  Aborting.\"; exit 1; }";
 | 
						|
  append oc "# Dependency: xe-unikernel-upload";
 | 
						|
  append oc "command -v xe-unikernel-upload >/dev/null 2>&1 || { echo >&2 \"I require xe-unikernel-upload but it's not installed.  Aborting.\"; exit 1; }";
 | 
						|
  append oc "# Dependency: a $HOME/.xe";
 | 
						|
  append oc "if [ ! -e $HOME/.xe ]; then";
 | 
						|
  append oc "  echo Please create a config file for xe in $HOME/.xe which contains:";
 | 
						|
  append oc "  echo server='<IP or DNS name of the host running xapi>'";
 | 
						|
  append oc "  echo username=root";
 | 
						|
  append oc "  echo password=password";
 | 
						|
  append oc "  exit 1";
 | 
						|
  append oc "fi";
 | 
						|
  newline oc;
 | 
						|
  append oc "echo Uploading VDI containing unikernel";
 | 
						|
  append oc "VDI=$(xe-unikernel-upload --path %s/mir-%s.xen)" t.root t.name;
 | 
						|
  append oc "echo VDI=$VDI";
 | 
						|
  append oc "echo Creating VM metadata";
 | 
						|
  append oc "VM=$(xe vm-create name-label=%s)" t.name;
 | 
						|
  append oc "echo VM=$VM";
 | 
						|
  append oc "xe vm-param-set uuid=$VM PV-bootloader=pygrub";
 | 
						|
  append oc "echo Adding network interface connected to xenbr0";
 | 
						|
  append oc "ETH0=$(xe network-list bridge=xenbr0 params=uuid --minimal)";
 | 
						|
  append oc "VIF=$(xe vif-create vm-uuid=$VM network-uuid=$ETH0 device=0)";
 | 
						|
  append oc "echo Atting block device and making it bootable";
 | 
						|
  append oc "VBD=$(xe vbd-create vm-uuid=$VM vdi-uuid=$VDI device=0)";
 | 
						|
  append oc "xe vbd-param-set uuid=$VBD bootable=true";
 | 
						|
  append oc "xe vbd-param-set uuid=$VBD other-config:owner=true";
 | 
						|
  append oc "echo Starting VM";
 | 
						|
  append oc "xe vm-start vm=%s" t.name;
 | 
						|
  close_out oc;
 | 
						|
  Unix.chmod file 0o755
 | 
						|
 | 
						|
let clean_main_xe t =
 | 
						|
  remove (t.root / t.name ^ ".xe")
 | 
						|
 | 
						|
(* Get the linker flags for any extra C objects we depend on.
 | 
						|
 * This is needed when building a Xen image as we do the link manually. *)
 | 
						|
let get_extra_ld_flags ~filter pkgs =
 | 
						|
  let output = read_command
 | 
						|
    "ocamlfind query -r -format '%%d\t%%(xen_linkopts)' -predicates native %s"
 | 
						|
    (String.concat " " pkgs) in
 | 
						|
  split output '\n'
 | 
						|
  |> List.fold_left (fun acc line ->
 | 
						|
    match cut_at line '\t' with
 | 
						|
    | None -> acc
 | 
						|
    | Some (dir, ldflags) -> Printf.sprintf "-L%s %s" dir ldflags :: acc
 | 
						|
  ) []
 | 
						|
 | 
						|
let configure_makefile t =
 | 
						|
  let file = t.root / "Makefile" in
 | 
						|
  let pkgs = "lwt.syntax" :: libraries t in
 | 
						|
  let libraries_str =
 | 
						|
    match pkgs with
 | 
						|
    | [] -> ""
 | 
						|
    | ls -> "-pkgs " ^ String.concat "," ls in
 | 
						|
  let packages = String.concat " " (packages t) in
 | 
						|
  let oc = open_out file in
 | 
						|
  append oc "# %s" generated_by_mirage;
 | 
						|
  newline oc;
 | 
						|
  append oc "LIBS   = %s" libraries_str;
 | 
						|
  append oc "PKGS   = %s" packages;
 | 
						|
  begin match !mode with
 | 
						|
    | `Xen  ->
 | 
						|
      append oc "SYNTAX = -tags \"syntax(camlp4o),annot,bin_annot,strict_sequence,principal\"\n";
 | 
						|
      append oc "SYNTAX += -tag-line \"<static*.*>: -syntax(camlp4o)\"\n";
 | 
						|
      append oc "FLAGS  = -cflag -g -lflags -g,-linkpkg,-dontlink,unix\n";
 | 
						|
      append oc "XENLIB = $(shell ocamlfind query mirage-xen)\n"
 | 
						|
    | `Unix ->
 | 
						|
      append oc "SYNTAX = -tags \"syntax(camlp4o),annot,bin_annot,strict_sequence,principal\"\n";
 | 
						|
      append oc "SYNTAX += -tag-line \"<static*.*>: -syntax(camlp4o)\"\n";
 | 
						|
      append oc "FLAGS  = -cflag -g -lflags -g,-linkpkg\n"
 | 
						|
    | `MacOSX ->
 | 
						|
      append oc "SYNTAX = -tags \"syntax(camlp4o),annot,bin_annot,strict_sequence,principal,thread\"\n";
 | 
						|
      append oc "SYNTAX += -tag-line \"<static*.*>: -syntax(camlp4o)\"\n";
 | 
						|
      append oc "FLAGS  = -cflag -g -lflags -g,-linkpkg\n"
 | 
						|
  end;
 | 
						|
  append oc "BUILD  = ocamlbuild -use-ocamlfind $(LIBS) $(SYNTAX) $(FLAGS)\n\
 | 
						|
             OPAM   = opam\n\n\
 | 
						|
             export PKG_CONFIG_PATH=$(shell opam config var prefix)/lib/pkgconfig\n\n\
 | 
						|
             export OPAMVERBOSE=1\n\
 | 
						|
             export OPAMYES=1";
 | 
						|
  newline oc;
 | 
						|
  append oc ".PHONY: all depend clean build main.native\n\
 | 
						|
             all: build\n\
 | 
						|
             \n\
 | 
						|
             depend:\n\
 | 
						|
             \t$(OPAM) install $(PKGS) --verbose\n\
 | 
						|
             \n\
 | 
						|
             main.native:\n\
 | 
						|
             \t$(BUILD) main.native\n\
 | 
						|
             \n\
 | 
						|
             main.native.o:\n\
 | 
						|
             \t$(BUILD) main.native.o";
 | 
						|
  newline oc;
 | 
						|
 | 
						|
  (* On ARM, we must convert the ELF image to an ARM boot executable zImage,
 | 
						|
   * while on x86 we leave it as it is. *)
 | 
						|
  let generate_image =
 | 
						|
    let need_zImage =
 | 
						|
      match uname_m () with
 | 
						|
      | Some machine -> String.length machine > 2 && String.sub machine 0 3 = "arm"
 | 
						|
      | None -> failwith "uname -m failed; can't determine target machine type!" in
 | 
						|
    if need_zImage then (
 | 
						|
      Printf.sprintf "\t  -o mir-%s.elf\n\
 | 
						|
                      \tobjcopy -O binary mir-%s.elf mir-%s.xen"
 | 
						|
                      t.name t.name t.name
 | 
						|
    ) else (
 | 
						|
      Printf.sprintf "\t  -o mir-%s.xen" t.name
 | 
						|
    ) in
 | 
						|
 | 
						|
  begin match !mode with
 | 
						|
    | `Xen ->
 | 
						|
      let filter = function
 | 
						|
        | "unix" | "bigarray" |"shared_memory_ring_stubs" -> false    (* Provided by mirage-xen instead. *)
 | 
						|
        | _ -> true in
 | 
						|
      let extra_c_archives =
 | 
						|
        get_extra_ld_flags ~filter pkgs
 | 
						|
        |> String.concat " \\\n\t  " in
 | 
						|
 | 
						|
      append oc "build: main.native.o";
 | 
						|
      let pkg_config_deps = "mirage-xen" in
 | 
						|
      append oc "\tpkg-config --print-errors --exists %s" pkg_config_deps;
 | 
						|
      append oc "\tld -d -static -nostdlib \\\n\
 | 
						|
                 \t  _build/main.native.o \\\n\
 | 
						|
                 \t  %s \\\n\
 | 
						|
                 \t  $$(pkg-config --static --libs %s) \\\n\
 | 
						|
                 \t  $(shell gcc -print-libgcc-file-name) \\\n\
 | 
						|
                 %s"
 | 
						|
        extra_c_archives pkg_config_deps generate_image;
 | 
						|
    | `Unix | `MacOSX ->
 | 
						|
      append oc "build: main.native";
 | 
						|
      append oc "\tln -nfs _build/main.native mir-%s" t.name;
 | 
						|
  end;
 | 
						|
  newline oc;
 | 
						|
  append oc "run: build";
 | 
						|
  begin match !mode with
 | 
						|
    | `Xen ->
 | 
						|
      append oc "\t@echo %s.xl has been created. Edit it to add VIFs or VBDs" t.name;
 | 
						|
      append oc "\t@echo Then do something similar to: xl create -c %s.xl\n" t.name
 | 
						|
    | `Unix | `MacOSX ->
 | 
						|
      append oc "\t$(SUDO) ./mir-%s\n" t.name
 | 
						|
  end;
 | 
						|
  append oc "clean:\n\
 | 
						|
             \tocamlbuild -clean";
 | 
						|
  close_out oc
 | 
						|
 | 
						|
let clean_makefile t =
 | 
						|
  remove (t.root / "Makefile")
 | 
						|
 | 
						|
let no_opam_version_check_ = ref false
 | 
						|
let no_opam_version_check b = no_opam_version_check_ := b
 | 
						|
 | 
						|
let configure_opam t =
 | 
						|
  info "Installing OPAM packages.";
 | 
						|
  match packages t with
 | 
						|
  | [] -> ()
 | 
						|
  | ps ->
 | 
						|
    if command_exists "opam" then
 | 
						|
      if !no_opam_version_check_ then ()
 | 
						|
      else (
 | 
						|
        let opam_version = read_command "opam --version" in
 | 
						|
        let version_error () =
 | 
						|
          error "Your version of opam: %s is not up-to-date. \
 | 
						|
                 Please update to (at least) 1.2." opam_version
 | 
						|
        in
 | 
						|
        match split opam_version '.' with
 | 
						|
        | major::minor::_ ->
 | 
						|
          let major = try int_of_string major with Failure _ -> 0 in
 | 
						|
          let minor = try int_of_string minor with Failure _ -> 0 in
 | 
						|
          if (major, minor) >= (1, 2) then opam "install" ps else version_error ()
 | 
						|
        | _ -> version_error ()
 | 
						|
      )
 | 
						|
    else error "OPAM is not installed."
 | 
						|
 | 
						|
let clean_opam t =
 | 
						|
  ()
 | 
						|
(* This is a bit too agressive, disabling for now on.
 | 
						|
   let (++) = StringSet.union in
 | 
						|
   let set mode = StringSet.of_list (packages t mode) in
 | 
						|
   let packages =
 | 
						|
    set (`Unix `Socket) ++ set (`Unix `Direct) ++ set `Xen in
 | 
						|
   match StringSet.elements packages with
 | 
						|
   | [] -> ()
 | 
						|
   | ps ->
 | 
						|
    if cmd_exists "opam" then opam "remove" ps
 | 
						|
    else error "OPAM is not installed."
 | 
						|
*)
 | 
						|
 | 
						|
let manage_opam_packages_ = ref true
 | 
						|
let manage_opam_packages b = manage_opam_packages_ := b
 | 
						|
 | 
						|
let configure_job j =
 | 
						|
  let name = Impl.name j in
 | 
						|
  let module_name = Impl.module_name j in
 | 
						|
  let param_names = Impl.names j in
 | 
						|
  append_main "let %s () =" name;
 | 
						|
  List.iter (fun p ->
 | 
						|
      append_main "  %s () >>= function" p;
 | 
						|
      append_main "  | `Error e -> %s" (driver_initialisation_error p);
 | 
						|
      append_main "  | `Ok %s ->" p;
 | 
						|
    ) (dedup param_names);
 | 
						|
  append_main "  %s.start %s" module_name (String.concat " " param_names);
 | 
						|
  newline_main ()
 | 
						|
 | 
						|
let configure_main t =
 | 
						|
  info "%s main.ml" (blue_s "Generating:");
 | 
						|
  set_main_ml (t.root / "main.ml");
 | 
						|
  append_main "(* %s *)" generated_by_mirage;
 | 
						|
  newline_main ();
 | 
						|
  append_main "open Lwt";
 | 
						|
  newline_main ();
 | 
						|
  append_main "let _ = Printexc.record_backtrace true";
 | 
						|
  newline_main ();
 | 
						|
  begin match t.tracing with
 | 
						|
  | None -> ()
 | 
						|
  | Some tracing -> Tracing.configure tracing end;
 | 
						|
  List.iter (fun j -> Impl.configure j) t.jobs;
 | 
						|
  List.iter configure_job t.jobs;
 | 
						|
  let names = List.map (fun j -> Printf.sprintf "%s ()" (Impl.name j)) t.jobs in
 | 
						|
  append_main "let () =";
 | 
						|
  append_main "  OS.Main.run (join [%s])" (String.concat "; " names)
 | 
						|
 | 
						|
let clean_main t =
 | 
						|
  List.iter Impl.clean t.jobs;
 | 
						|
  remove (t.root / "main.ml")
 | 
						|
 | 
						|
let configure t =
 | 
						|
  info "%s %s" (blue_s "Using configuration:") (get_config_file ());
 | 
						|
  info "%d job%s [%s]"
 | 
						|
    (List.length t.jobs)
 | 
						|
    (if List.length t.jobs = 1 then "" else "s")
 | 
						|
    (String.concat ", " (List.map Impl.functor_name t.jobs));
 | 
						|
  in_dir t.root (fun () ->
 | 
						|
      if !manage_opam_packages_ then configure_opam t;
 | 
						|
      configure_myocamlbuild_ml t;
 | 
						|
      configure_makefile t;
 | 
						|
      configure_main_xl t;
 | 
						|
      configure_main_xe t;
 | 
						|
      configure_main_libvirt_xml t;
 | 
						|
      configure_main t
 | 
						|
    )
 | 
						|
 | 
						|
let make () =
 | 
						|
  match uname_s () with
 | 
						|
  | Some ("FreeBSD" | "OpenBSD" | "NetBSD" | "DragonFly") -> "gmake"
 | 
						|
  | _ -> "make"
 | 
						|
 | 
						|
let build t =
 | 
						|
  info "Build: %s" (blue_s (get_config_file ()));
 | 
						|
  in_dir t.root (fun () ->
 | 
						|
      command "%s build" (make ())
 | 
						|
    )
 | 
						|
 | 
						|
let run t =
 | 
						|
  info "Run: %s" (blue_s (get_config_file ()));
 | 
						|
  in_dir t.root (fun () ->
 | 
						|
      command "%s run" (make ())
 | 
						|
    )
 | 
						|
 | 
						|
let clean t =
 | 
						|
  info "Clean: %s" (blue_s (get_config_file ()));
 | 
						|
  in_dir t.root (fun () ->
 | 
						|
      if !manage_opam_packages_ then clean_opam t;
 | 
						|
      clean_myocamlbuild_ml t;
 | 
						|
      clean_makefile t;
 | 
						|
      clean_main_xl t;
 | 
						|
      clean_main_xe t;
 | 
						|
      clean_main_libvirt_xml t;
 | 
						|
      clean_main t;
 | 
						|
      command "rm -rf %s/_build" t.root;
 | 
						|
      command "rm -rf log %s/main.native.o %s/main.native %s/mir-%s %s/*~"
 | 
						|
        t.root t.root t.root t.name t.root;
 | 
						|
    )
 | 
						|
 | 
						|
(* Compile the configuration file and attempt to dynlink it.
 | 
						|
 * It is responsible for registering an application via
 | 
						|
 * [Mirage_config.register] in order to have an observable
 | 
						|
 * side effect to this command. *)
 | 
						|
let compile_and_dynlink file =
 | 
						|
  info "%s %s" (blue_s "Processing:") file;
 | 
						|
  let root = Filename.dirname file in
 | 
						|
  let file = Filename.basename file in
 | 
						|
  let file = Dynlink.adapt_filename file in
 | 
						|
  command "rm -rf %s/_build/%s.*" root (Filename.chop_extension file);
 | 
						|
  command "cd %s && ocamlbuild -use-ocamlfind -tags annot,bin_annot -pkg mirage %s" root file;
 | 
						|
  try Dynlink.loadfile (String.concat "/" [root; "_build"; file])
 | 
						|
  with Dynlink.Error err -> error "Error loading config: %s" (Dynlink.error_message err)
 | 
						|
 | 
						|
(* If a configuration file is specified, then use that.
 | 
						|
 * If not, then scan the curdir for a `config.ml` file.
 | 
						|
 * If there is more than one, then error out. *)
 | 
						|
let scan_conf = function
 | 
						|
  | Some f ->
 | 
						|
    info "%s %s" (blue_s "Using specified config file:") f;
 | 
						|
    if not (Sys.file_exists f) then error "%s does not exist, stopping." f;
 | 
						|
    realpath f
 | 
						|
  | None   ->
 | 
						|
    let files = Array.to_list (Sys.readdir ".") in
 | 
						|
    match List.filter ((=) "config.ml") files with
 | 
						|
    | [] -> error "No configuration file config.ml found.\n\
 | 
						|
                   You'll need to create one to let Mirage know what to do."
 | 
						|
    | [f] ->
 | 
						|
      info "%s %s" (blue_s "Using scanned config file:") f;
 | 
						|
      realpath f
 | 
						|
    | _   -> error "There is more than one config.ml in the current working directory.\n\
 | 
						|
                    Please specify one explictly on the command-line."
 | 
						|
 | 
						|
let load file =
 | 
						|
  reset ();
 | 
						|
  let file = scan_conf file in
 | 
						|
  let root = realpath (Filename.dirname file) in
 | 
						|
  let file = root / Filename.basename file in
 | 
						|
  info "%s %s" (blue_s "Compiling for target:") (string_of_mode !mode);
 | 
						|
  set_config_file file;
 | 
						|
  compile_and_dynlink file;
 | 
						|
  let t = registered () in
 | 
						|
  set_section t.name;
 | 
						|
  update_path t root
 |