Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Source file CCUnix.ml
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296(* This file is free software, part of containers. See file "license" for more details. *)(** {1 High-level Functions on top of Unix} *)type'aor_error=('a,string)resulttype'agen=unit->'aoption(** {2 Calling Commands} *)letint_of_process_status=function|Unix.WEXITEDi|Unix.WSIGNALEDi|Unix.WSTOPPEDi->iletstr_existssp=letrecfspi=ifi=String.lengthsthenfalseelseps.[i]||fsp(i+1)infsp0letreciter_genfg=matchg()with|None->()|Somex->fx;iter_genfgletfinally_fx~h=trylety=fxinignore(h());ywithe->ignore(h());raisee(* print a string, but escaped if required *)letescape_strs=ifstr_existss(function|' '|'"'|'\''|'\n'|'\t'->true|_->false)then(letbuf=Buffer.create(String.lengths)inBuffer.add_charbuf'\'';String.iter(function|'\''->Buffer.add_stringbuf"'\\''"|c->Buffer.add_charbufc)s;Buffer.add_charbuf'\'';Buffer.contentsbuf)elsesletread_all?(size=1024)ic=letbuf=ref(Bytes.createsize)inletlen=ref0intrywhiletruedo(* resize *)if!len=Bytes.length!bufthenbuf:=Bytes.extend!buf0!len;assert(Bytes.length!buf>!len);letn=inputic!buf!len(Bytes.length!buf-!len)inlen:=!len+n;ifn=0thenraiseExit(* exhausted *)done;assertfalse(* never reached*)withExit->Bytes.sub_string!buf0!lentypecall_result=<stdout:string;stderr:string;status:Unix.process_status;errcode:int(** Extracted from status *)>letkbprintf'buffmtk=Printf.kbprintfkbuffmtletcall_full_inner?(bufsize=2048)?(stdin=`Str"")?(env=Unix.environment())~fcmd=(* render the command *)letbuf=Buffer.create256inkbprintf'bufcmd(funbuf->letcmd=Buffer.contentsbufinletoc,ic,errc=Unix.open_process_fullcmdenvin(* send stdin *)(matchstdinwith|`Strs->output_stringics|`Geng->iter_gen(output_stringic)g);close_outic;(* read out and err *)letout=read_all~size:bufsizeocinleterr=read_all~size:bufsizeerrcinletstatus=Unix.close_process_full(oc,ic,errc)inf(out,err,status))letcall_full?bufsize?stdin?envcmd=call_full_inner?bufsize?stdin?envcmd~f:(fun(out,err,status)->objectmethodstdout=outmethodstderr=errmethodstatus=statusmethoderrcode=int_of_process_statusstatusend)letcall?bufsize?stdin?envcmd=call_full_inner?bufsize?stdin?envcmd~f:(fun(out,err,status)->out,err,int_of_process_statusstatus)letcall_stdout?bufsize?stdin?envcmd=call_full_inner?bufsize?stdin?envcmd~f:(fun(out,_err,_status)->out)typeline=stringtypeasync_call_result=<stdout:linegen;stderr:linegen;stdin:line->unit(* send a line *);close_in:unit(* close stdin *);close_err:unit;close_out:unit;close_all:unit(* close all 3 channels *);wait:Unix.process_status(* block until the process ends *);wait_errcode:int(* block until the process ends, then extract errcode *)>letasync_call?(env=Unix.environment())cmd=(* render the command *)letbuf=Buffer.create256inkbprintf'bufcmd(funbuf->letcmd=Buffer.contentsbufinletoc,ic,errc=Unix.open_process_fullcmdenvinobject(self)methodstdout()=trySome(input_lineoc)withEnd_of_file->Nonemethodstderr()=trySome(input_lineerrc)withEnd_of_file->Nonemethodstdinl=output_stringicl;output_charic'\n'methodclose_in=close_outicmethodclose_out=close_inocmethodclose_err=close_inerrcmethodclose_all=close_outic;close_inoc;close_inerrc;()methodwait=Unix.close_process_full(oc,ic,errc)methodwait_errcode=int_of_process_statusself#waitend)letstdoutx=x#stdoutletstderrx=x#stderrletstatusx=x#statusleterrcodex=x#errcodeletwith_in?(mode=0o644)?(flags=[])file~f=letfd=Unix.openfilefile(Unix.O_RDONLY::flags)modeinletic=Unix.in_channel_of_descrfdinfinally_fic~h:(fun()->Unix.closefd)letwith_out?(mode=0o644)?(flags=[Unix.O_CREAT;Unix.O_TRUNC])file~f=letfd=Unix.openfilefile(Unix.O_WRONLY::flags)modeinletoc=Unix.out_channel_of_descrfdinfinally_foc~h:(fun()->flushoc;Unix.closefd)letwith_process_incmd~f=letic=Unix.open_process_incmdinfinally_fic~h:(fun()->ignore(Unix.close_process_inic))letwith_process_outcmd~f=letoc=Unix.open_process_outcmdinfinally_foc~h:(fun()->ignore(Unix.close_process_outoc))typeprocess_full=<stdin:out_channel;stdout:in_channel;stderr:in_channel;close:Unix.process_status>letwith_process_full?envcmd~f=letenv=matchenvwith|None->Unix.environment()|Somee->einletoc,ic,err=Unix.open_process_fullcmdenvinletclose=lazy(Unix.close_process_full(oc,ic,err))inletp=objectmethodstdin=icmethodstdout=ocmethodstderr=errmethodclose=Lazy.forcecloseendinfinally_fp~h:(fun()->p#close)letwith_connectionaddr~f=letic,oc=Unix.open_connectionaddrinfinally_(fun()->ficoc)()~h:(fun()->Unix.shutdown_connectionic)(* make sure that we are a session leader; that is, our children die if we die *)letensure_session_leader=letthunk=lazy(if(notSys.win32)&¬Sys.cygwinthenignore(Unix.setsid()))infun()->Lazy.forcethunkexceptionExitServer(* version of {!Unix.establish_server} that doesn't fork *)letestablish_serversockaddr~f=letsock=Unix.socket(Unix.domain_of_sockaddrsockaddr)Unix.SOCK_STREAM0inUnix.setsockoptsockUnix.SO_REUSEADDRtrue;Unix.bindsocksockaddr;Unix.listensock5;letcontinue=reftrueinwhile!continuedotrylets,_=Unix.acceptsockinletic=Unix.in_channel_of_descrsinletoc=Unix.out_channel_of_descrsinignore(ficoc)withExitServer->continue:=falsedone(** {2 Locking} *)letwith_file_lock~kindfilenamef=letlock_file=Unix.openfilefilename[Unix.O_CREAT;Unix.O_WRONLY]0o644inletlock_action=matchkindwith|`Read->Unix.F_RLOCK|`Write->Unix.F_LOCKinUnix.lockflock_filelock_action0;tryletx=f()inUnix.lockflock_fileUnix.F_ULOCK0;Unix.closelock_file;xwithe->Unix.lockflock_fileUnix.F_ULOCK0;Unix.closelock_file;raiseemoduleInfix=structlet(?|)fmt=call_fullfmtlet(?|&)fmt=async_callfmtendincludeInfix(** {2 Temporary directory} *)letrand_digits_=letst=lazy(Random.State.make_self_init())infun()->letrand=Random.State.bits(Lazy.forcest)land0xFFFFFFinPrintf.sprintf"%06x"randletrmdir_dir=tryignore(Sys.command("rm -r "^dir):int)with_->()letwith_temp_dir?(mode=0o700)?dirpat(f:string->'a):'a=letdir=matchdirwith|Somed->d|None->Filename.get_temp_dir_name()inletraise_errmsg=raise(Sys_errormsg)inletrecloopcount=ifcount<0thenraise_err"mk_temp_dir: too many failing attempts"else(letdir=Filename.concatdir(pat^rand_digits_())inmatchUnix.mkdirdirmodewith|()->finally_fdir~h:(fun()->rmdir_dir)|exceptionUnix.Unix_error(Unix.EEXIST,_,_)->loop(count-1)|exceptionUnix.Unix_error(Unix.EINTR,_,_)->loopcount|exceptionUnix.Unix_error(e,_,_)->raise_err("mk_temp_dir: "^Unix.error_messagee))inloop1000