123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163openStdLabelsexternalis_osx:unit->bool="spawn_is_osx"[@@noalloc]letis_osx=is_osx()moduleWorking_dir=structtypet=|Pathofstring|FdofUnix.file_descr|InheritendmoduleUnix_backend=structtypet=|Fork|Vforkletdefault=matchSys.getenv"SPAWN_USE_FORK"with|_->Fork|exceptionNot_found->(* We observed issues in the past when using [vfork] on OSX. More
precisely, it seems that [chdir]/[fchdir] is not taken into account
after a vfork. We tried working around this by not doing the directory
change in the sub-process when using [vfork] on OSX, and instead doing
it in the parent via [pthread_chdir]/[pthread_fchdir]. This was
unsuccessful.
In the end we decided not to default to [vfork] on OSX. *)ifis_osxthenForkelseVforkendmoduletypeEnv=sigtypetvalof_list:stringlist->tendmoduleEnv_win32:Env=structtypet=stringletof_listenv=letlen=List.fold_leftenv~init:1~f:(funaccs->acc+String.lengths+1)inletbuf=Buffer.createleninList.iterenv~f:(funs->Buffer.add_stringbufs;Buffer.add_charbuf'\000');Buffer.add_charbuf'\000';Buffer.contentsbufendmoduleEnv_unix:Env=structtypet=stringlistletno_nulls=ifString.containss'\000'thenPrintf.ksprintfinvalid_arg"Spawn.Env.of_list: NUL bytes are not allowed in the environment but \
found one in %S"sletof_listl=List.iterl~f:no_null;lendmoduleEnv:Env=(valifSys.win32then(moduleEnv_win32)else(moduleEnv_unix):Env)externalspawn_unix:env:Env.toption->cwd:Working_dir.t->prog:string->argv:stringlist->stdin:Unix.file_descr->stdout:Unix.file_descr->stderr:Unix.file_descr->use_vfork:bool->int="spawn_unix_byte""spawn_unix"externalspawn_windows:env:Env.toption->cwd:stringoption->prog:string->cmdline:string->stdin:Unix.file_descr->stdout:Unix.file_descr->stderr:Unix.file_descr->int="spawn_windows_byte""spawn_windows"letspawn_windows~env~cwd~prog~argv~stdin~stdout~stderr~use_vfork:_=letcwd=match(cwd:Working_dir.t)with|Pathp->Somep|Fd_->invalid_arg"Spawn.spawn: [cwd=Fd _] is not supported on Windows"|Inherit->Noneinletcmdline=String.concat(List.mapargv~f:Filename.quote)~sep:" "inletprog=match(Filename.is_relativeprog,cwd)with|true,Somep->Filename.concatpprog|_->proginspawn_windows~env~cwd~prog~cmdline~stdin~stdout~stderrletno_nulls=ifString.containss'\000'thenPrintf.ksprintfinvalid_arg"Spawn.spawn: NUL bytes are not allowed in any of the arguments but \
found one in %S"sletspawn?env?(cwd=Working_dir.Inherit)~prog~argv?(stdin=Unix.stdin)?(stdout=Unix.stdout)?(stderr=Unix.stderr)?(unix_backend=Unix_backend.default)()=(matchcwdwith|Paths->no_nulls|Fd_|Inherit->());no_nullprog;List.iterargv~f:no_null;letbackend=ifSys.win32thenspawn_windowselsespawn_unixinletuse_vfork=matchunix_backendwith|Vfork->true|Fork->falseinbackend~env~cwd~prog~argv~stdin~stdout~stderr~use_vforkexternalsafe_pipe:unit->Unix.file_descr*Unix.file_descr="spawn_pipe"letsafe_pipe=ifSys.win32then(fun()->(* CR-someday jdimino: fix race conditions on Windows *)letfdr,fdw=Unix.pipe()inmatchUnix.set_close_on_execfdr;Unix.set_close_on_execfdwwith|()->(fdr,fdw)|exceptionexn->(tryUnix.closefdrwith|_->());(tryUnix.closefdwwith|_->());raiseexn)elsesafe_pipe