123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268moduleSMap=Map.Make(String)moduleString=structincludeString(* To be compatible with OCaml < 4.04.0 *)letsplit_on_charseps=letr=ref[]inletj=ref(lengths)infori=lengths-1downto0doifunsafe_getsi=septhenbeginr:=subs(i+1)(!j-i-1)::!r;j:=ienddone;subs0!j::!rletrecunsafe_rev_blitsdstpossepseplen=function|[]->dst|[hd]->unsafe_blithd0dst0(String.lengthhd);dst|hd::tl->letpos=pos-String.lengthhdinunsafe_blithd0dstpos(String.lengthhd);letpos=pos-sepleninunsafe_blitsep0dstposseplen;unsafe_rev_blitsdstpossepseplentl(* Equivalent to [String.concat sep (List.rev l)].
[n] = number of elements in [l].
[sum_len] = sum of lengths of the elements in [l]. *)letrev_concatsepl~n~sum_len=letseplen=String.lengthsepinletlen=(n-1)*seplen+sum_leninBytes.unsafe_to_string(unsafe_rev_blits (Bytes.createlen)lensepseplenl)endtypeconf={args:stringlist;(* arguments, in reverse order *)n:int;(* number of elements in [args]. *)sum_len:int;(* sum of lengths in [args]. *)unshare_user:bool;unshare_user_mandatory:bool;unshare_ipc:bool;unshare_pid:bool;unshare_net:bool;unshare_uts:bool;unshare_uts_mandatory:bool;unshare_cgroup:bool;uid:int;(* < 0 if unset *)gid:int;(* < 0 if unset *)hostname:string;(* = "" if unset *)env:stringSMap.t;(* variable → content *)proc:string;(* = "" if not set *)dev:string;(* = "" if not set *)new_session:bool;die_with_parent:bool;}let[@inline]add_arg1ov1c={cwithargs=v1::o::c.args;n=2+c.n;sum_len=String.lengthv1+String.lengtho+c.sum_len}let[@inline]add_arg2ov1v2c={cwithargs=v2::v1::o::c.args;n=3+c.n;sum_len=String.lengthv2+String.lengthv1+String.lengtho+c.sum_len}letbare={args=["bwrap"];n=1;sum_len=5;unshare_user=true;unshare_user_mandatory=false;unshare_ipc=true;unshare_pid=true;unshare_net=true;unshare_uts=true;unshare_uts_mandatory=false;unshare_cgroup=true;uid=-1;gid=-1;hostname="";env=SMap.empty;proc="";dev="";new_session=true;die_with_parent=true;}(* Newer versions of bwrap have --ro-bind-try but not older ones. *)let[@inline]ro_bind_trypathargs=ifSys.file_existspaththenpath::path::"--ro-bind"::argselseargsletdefault_args=[(* Beware [args] is in reverse order. *)"/tmp";"--tmpfs";"/run";"--tmpfs";"/var";"--tmpfs";"bwrap"]|>ro_bind_try"/lib64"|>ro_bind_try"/lib32"|>ro_bind_try"/lib"|>ro_bind_try"/usr"|>ro_bind_try"/bin"letdefault_n=List.lengthdefault_argsletdefault_sum_len=List.fold_left(funlv->l+String.lengthv)0default_argsletconf?uid?gid()=letuid =match uidwithSomeu->u|None->-1inletgid=matchgidwithSomeu->u|None->-1in{args=default_args;n=default_n;sum_len=default_sum_len;unshare_user=true;unshare_user_mandatory=false;unshare_ipc=true;unshare_pid=true;unshare_net=true;unshare_uts=true;unshare_uts_mandatory=false;unshare_cgroup=true;uid;gid;hostname="OCaml";env=SMap.empty;proc="/proc";dev="/dev";new_session=true;die_with_parent=true;}letshare_userbc={cwithunshare_user=notb}letshare_ipcbc={cwithunshare_ipc =notb}letshare_pidbc={cwithunshare_pid =notb}letshare_netbc={cwithunshare_net =notb}letshare_utsbc={cwithunshare_uts =notb}letshare_cgroupbc={cwithunshare_cgroup =notb}letuiduidc=ifuid<0then {cwithuid}else{cwithuid;unshare_user_mandatory=true}letgidgidc=ifgid<0then {cwithgid}else{cwithgid;unshare_user_mandatory=true}lethostnamehc=ifh=""then{cwithhostname=""}else{cwithhostname=Filename.quoteh;unshare_uts_mandatory=true}letsetenvvarvc={cwithenv=SMap.addvarvc.env}letunsetenvvarc={cwithenv=SMap.removevarc.env}letmount?(dev=false)?src?(rw=false)destc=letdest=Filename.quotedestinletsrc=match srcwithSomes->Filename.quotes|None->destinifdevthenadd_arg2"--dev-bind"srcdestcelseifrwthenadd_arg2"--bind"srcdestcelseadd_arg2"--ro-bind"srcdestcletremount_rodestc=add_arg1"--remount-ro" (Filename.quotedest)cletprocdestc={cwithproc=Filename.quotedest}letdevdestc={cwithdev=Filename.quotedest}lettmpfsdest c=add_arg1"--tmpfs"(Filename.quotedest)cletmqueuedest c=add_arg1"--mqueue"(Filename.quotedest)cletdirdest c=add_arg1"--dir"(Filename.quotedest)cletsymlink ?srcdestc=let dest=Filename.quotedestinletsrc=match srcwithSomes->Filename.quotes|None->destinadd_arg2"--symlink"srcdestcletchdirdirc=add_arg1"--chdir"(Filename.quotedir)cletnew_session bc={cwithnew_session =b}letdie_with_parentbc={cwithdie_with_parent =b}letmake_cmdc~envcmdargs=letn=ref c.ninletsum_len=refc.sum_leninlet[@inline]add1va=incrn;sum_len:=String.lengthv+!sum_len;v::ainlet[@inline]add1_condcondva=ifcondthenadd1vaelseainlet[@inline]add2v1v2a=n:=!n+2;sum_len:=String.lengthv2+String.lengthv1+!sum_len;v2::v1::ainlet[@inline]add2_condcondv1v2a=ifcondthenadd2 v1v2aelseainlet a=add1_cond(c.unshare_user_mandatory||c.unshare_user)"--unshare-user"c.args|>add1_condc.unshare_ipc"--unshare-ipc"|>add1_condc.unshare_pid"--unshare-pid"|>add1_condc.unshare_net"--unshare-net"|>add1_cond(c.unshare_uts_mandatory||c.unshare_uts)"--unshare-uts"|>add1_condc.unshare_cgroup"--unshare-cgroup"|>add2_cond(c.uid>=0)"--uid"(string_of_intc.uid)|>add2_cond (c.gid>=0)"--gid"(string_of_intc.gid)|>add2_cond (c.hostname<>"")"--hostname"c.hostname|>add2_cond(c.proc<>"")"--proc"c.proc|>add2_cond(c.dev<>"")"--dev"c.dev|>add1_condc.new_session"--new-session"#ifBWRAP_VERSION>=(0,1,8)|>add1_condc.die_with_parent"--die-with-parent"#endifinleta=ifenvthen((* Unset all variables of the environment and then set the ones
declared in [c]. *)lete=Unix.environment()inleta=Array.fold_left(funae->match String.split_on_char'='ewith|v::_->add2"--unsetenv"va|[]->assertfalse(* See split_on_char *))aeinSMap.fold(funvarva->n:=!n+3;sum_len:=String.lengthv+String.lengthvar+8+!sum_len;v::var::"--setenv"::a)c.enva)elseain(* Command to run. *)leta=add1(Filename.quotecmd)ainlet a=List.fold_left(funax->add1(Filename.quote x)a)aargsinString.rev_concat""a~n:!n~sum_len:!sum_lenletopen_process_inccmdargs =Unix.open_process_in (make_cmdccmdargs~env:true)letclose_process_in=Unix.close_process_inletopen_process_outccmdargs=Unix.open_process_out(make_cmd ccmdargs~env:true)letclose_process_out=Unix.close_process_outletopen_processccmdargs=Unix.open_process(make_cmd ccmdargs~env:true)letclose_process=Unix.close_processletmake_envc=Array.of_list(SMap.fold(funvarvl->(var^"="^v)::l)c.env[])letopen_process_fullccmdargs=Unix.open_process_full(make_cmd ccmdargs~env:false)(make_envc)letclose_process_full=Unix.close_process_full