123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344moduleDune=Functoria.DunemoduleInfo=Functoria.InfomoduleInstall=Functoria.InstallopenFunctoria.DSLopenFunctoria.ActionopenMiscopenKvopenPclockopenCmdlinertypeblock=BLOCKletblock=typBLOCKtypeblock_t={filename:string;number:int}letall_blocks=Hashtbl.create7letmake_block_t=(* NB: reserve number 0 for the boot disk *)letnext_number=ref1infunfilename->letb=ifHashtbl.memall_blocksfilenamethenHashtbl.findall_blocksfilenameelseletnumber=!next_numberinincrnext_number;letb={filename;number}inHashtbl.addall_blocksfilenameb;binbletxen_block_packages=[package~min:"2.1.0"~max:"3.0.0"~sublibs:["front"]"mirage-block-xen"](* this function takes a string rather than an int as `id` to allow
the user to pass stuff like "/dev/xvdi1", which mirage-block-xen
also understands *)letxenstore_confid=letconfigurei=matchget_targetiwith|`Qubes|`Xen->ok()|_->error"XenStore IDs are only valid ways of specifying block devices when \
the target is Xen or Qubes."inletconnect_impl_name_=code~pos:__POS__"%s.connect %S"impl_nameidinimpl~configure~connect~packages:xen_block_packages"Block"blockletblock_of_xenstore_idid=xenstore_confid(* calculate the XenStore ID for the nth available block device.
Taken from https://github.com/mirage/mirage-block-xen/blob/
a64d152586c7ebc1d23c5adaa4ddd440b45a3a83/lib/device_number.ml#L64 . *)letxenstore_id_of_indexnumber=ifnumber<16then(202lsl8)lor(numberlsl4)else(1lsl28)lor(numberlsl8)letblock_conffile=letconnect_nametarget=matchtargetwith|#Key.mode_unix->file(* open the file directly *)|#Key.mode_xen->letb=make_block_tfileinxenstore_id_of_indexb.number|>string_of_int|#Key.mode_solo5->(* XXX For now, on Solo5, just pass the "file" name through directly as
* the Solo5 block device name *)fileinletpackages_v=Key.match_Key.(valuetarget)@@function|#Key.mode_xen->xen_block_packages|#Key.mode_solo5->[package~min:"0.8.0"~max:"0.9.0""mirage-block-solo5"]|#Key.mode_unix->[package~min:"2.12.0"~max:"3.0.0""mirage-block-unix"]inletconfigure_=let(_:block_t)=make_block_tfileinok()inletconnectis_=matchget_targetiwith|`Muen->failwith"Block devices not supported on Muen target."|_->code~pos:__POS__"%s.connect %S"s(connect_name(get_targeti))inFunctoria.Device.v~configure~packages_v~connect"Block"blockletblock_of_filefile=of_device(block_conffile)letramdiskrname=letpackages=[package"mirage-block-ramdisk"]inletconnect_m_=code~pos:__POS__"%s.connect ~name:%S"mrnameinimpl~connect~packages"Ramdisk"blockletgeneric_block?group?(key=Key.(value@@block?group()))name=match_implkey[(`XenstoreId,block_of_xenstore_idname);(`BlockFile,block_of_filename);(`Ramdisk,ramdiskname);]~default:(ramdiskname)lettar_kv_ro_conf=letpackages=[package~min:"1.0.0"~max:"4.0.0""tar-mirage"]inletconnect_modname=function|[block]->code~pos:__POS__"%s.connect %s"modnameblock|_->connect_err"tar_kv_ro"1inimpl~packages~connect"Tar_mirage.Make_KV_RO"(block@->Kv.ro)lettar_kv_rw_conf=letpackages=[package~min:"2.2.0"~max:"4.0.0""tar-mirage"]inletconnect_modname=function|[_pclock;block]->code~pos:__POS__"%s.connect %s"modnameblock|_->connect_err"tar_kv_rw"2inimpl~packages~connect"Tar_mirage.Make_KV_RW"(pclock@->block@->Kv.rw)lettar_kv_roblock=tar_kv_ro_conf$blocklettar_kv_rwpclockblock=tar_kv_rw_conf$pclock$blockletfat_conf=letpackages=[package~min:"0.15.0"~max:"0.16.0""fat-filesystem"]inletconnect_modname=function|[block]->code~pos:__POS__"%s.connect %s"modnameblock|_->connect_err"fat"1inimpl~packages~connect"Fat.KV_RO"(block@->Kv.ro)letfat_roblock=fat_conf$blocktypemode=[`Fast|`Light]letpp_modeppf=function|`Fast->Fmt.stringppf"Fast"|`Light->Fmt.stringppf"Light"letpp_branchppf=function|None->()|Somebranch->Fmt.pfppf" -b %s"branchletdocteur_unix(mode:mode)extra_deps~name:_~outputbranchanalyzeremote=letduneinfo=letctx=Info.contextinfoinletoutput=Key.getctxoutputinletsource_tree=leturi=Uri.of_stringremoteinmatchUri.schemeuriwith|Some"file"->letpath=Uri.host_with_default~default:""uri^Uri.pathuriinFmt.str" (source_tree /%s)"path|Some"relativize"->letpath=Uri.host_with_default~default:""uri^Uri.pathuriinFmt.str" (source_tree %s)"path|_->""inletdune=Dune.stanzaf{dune|
(rule
(targets %s)
(enabled_if (= %%{context_name} "default"))
(deps (:make %%{bin:docteur.make})%a%s)
(action (run %%{make} %s%a %s)))
|dune}outputFmt.(list~sep:nop(conststring" "++string))extra_depssource_treeremotepp_branchbranchoutputin[dune]inletinstallinfo=letctx=Info.contextinfoinletoutput=Fpath.v(Key.getctxoutput)inInstall.v~etc:[output]()inletconfigureinfo=letctx=Info.contextinfoinletname=Key.getctxoutputinlet(_:block_t)=make_block_tnameinok()inletconnectinfomodname=function|[analyze]->letctx=Info.contextinfoinletname=Key.getctxoutputincode~pos:__POS__{ocaml|let ( <.> ) f g = fun x -> f (g x) in
let f = Rresult.R.(failwith_error_msg <.> reword_error (msgf "%%a" %s.pp_error)) in
Lwt.map f (%s.connect ~analyze:%s %S)|ocaml}modnamemodnameanalyzename|_->connect_err"docteur_unix"1inletkeys=[Key.voutput]inletruntime_args=Runtime_arg.[vanalyze]inletpackages=[package"docteur-unix"~min:"0.0.6"]inimpl~runtime_args~keys~packages~dune~install~configure~connect(Fmt.str"Docteur_unix.%a"pp_modemode)roletdocteur_solo5(mode:mode)extra_deps~name~outputbranchanalyzeremote=letduneinfo=letctx=Info.contextinfoinletoutput=Key.getctxoutputinletsource_tree=leturi=Uri.of_stringremoteinmatchUri.schemeuriwith|Some"file"->letpath=Uri.host_with_default~default:""uri^Uri.pathuriinFmt.str" (source_tree /%s)"path|Some"relativize"->letpath=Uri.host_with_default~default:""uri^Uri.pathuriinFmt.str" (source_tree %s)"path|_->""inletdune=Dune.stanzaf{dune|
(rule
(targets %s)
(enabled_if (= %%{context_name} "default"))
(deps (:make %%{bin:docteur.make})%a%s)
(action (run %%{make} %s%a %s)))
|dune}outputFmt.(list~sep:nop(conststring" "++string))extra_depssource_treeremotepp_branchbranchoutputin[dune]inletinstallinfo=letctx=Info.contextinfoinletoutput=Fpath.v(Key.getctxoutput)inInstall.v~etc:[output]()inletconfigureinfo=letctx=Info.contextinfoinletname=Key.getctxnameinlet(_:block_t)=make_block_tnameinok()inletconnectinfomodname=function|[analyze]->letctx=Info.contextinfoinletname=Key.getctxnameincode~pos:__POS__{ocaml|let ( <.> ) f g = fun x -> f (g x) in
let f = Rresult.R.(failwith_error_msg <.> reword_error (msgf "%%a" %s.pp_error)) in
Lwt.map f (%s.connect ~analyze:%s %S)|ocaml}modnamemodnameanalyzename|_->connect_err"docteur_solo5"1inletkeys=[Key.voutput;Key.vname]inletruntime_args=Runtime_arg.[vanalyze]inletpackages=[package"docteur-solo5"~min:"0.0.6"]inimpl~keys~runtime_args~packages~dune~install~configure~connect(Fmt.str"Docteur_solo5.%a"pp_modemode)roletdisk_name=letdoc=Arg.info~doc:"Name of the docteur disk (for Solo5 targets, the name must contains \
only alpanumeric characters)."["disk-name"]inletkey=Key.Arg.optArg.string"docteur"docinKey.create"disk-name"keyletdisk_output=letdoc=Arg.info~doc:"The output of the generated docteur image."["disk-output"]inletkey=Key.Arg.optArg.string"disk.img"docinKey.create"disk-output"keyletdocteur_solo5(mode:mode)extra_deps?(name=disk_name)?(output=disk_output)branchanalyzeremote=docteur_solo5modeextra_deps~name~outputbranchanalyzeremoteletdocteur_unix(mode:mode)extra_deps?(name=disk_name)?(output=disk_output)branchanalyzeremote=docteur_unixmodeextra_deps~name~outputbranchanalyzeremoteletanalyze=Runtime_arg.create~pos:__POS__"Mirage_runtime.analyze"letdocteur?(mode=`Fast)?name?output?(analyze=analyze)?branch?(extra_deps=[])remote=match_implKey.(valuetarget)[(`Xen,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);(`Qubes,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);(`Virtio,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);(`Hvt,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);(`Spt,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);(`Muen,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);(`Genode,docteur_solo5modeextra_deps?name?outputbranchanalyzeremote);]~default:(docteur_unixmodeextra_deps?name?outputbranchanalyzeremote)letchamelon~program_block_size=letruntime_args=Runtime_arg.[vprogram_block_size]inletpackages=[package"chamelon"~sublibs:["kv"]~min:"0.0.8"]inletconnect_modname=function|[block;_;program_block_size]->code~pos:__POS__{ocaml|%s.connect ~program_block_size:%s %s
>|= Result.map_error (Fmt.str "%%a" %s.pp_error)
>|= Result.fold ~ok:Fun.id ~error:failwith|ocaml}modnameprogram_block_sizeblockmodname|_->connect_err"chameleon"3inimpl~packages~runtime_args~connect"Kv.Make"(block@->pclock@->Kv.rw)letccm_block?nonce_lenkey=letruntime_args=Runtime_arg.[vkey]inletpackages=[package"mirage-block-ccm"~min:"2.0.0"~max:"3.0.0"]inletconnect_modname=function|[block;key]->code~pos:__POS__{ocaml|let key = %s in
let key =
if String.length key >= 2 && String.(equal "0x" (sub key 0 2)) then
String.sub key 2 (String.length key - 2)
else
key
in
%s.connect ?nonce_len:%a ~key:(Cstruct.of_hex key) %s|ocaml}keymodnameFmt.(parens(Dump.optionint))nonce_lenblock|_->connect_err"ccm_block"2inimpl~packages~runtime_args~connect"Block_ccm.Make"(block@->block)