int main(int argc, const char* argv[]) { printf("[BEGIN] crt-vars-libSystem\n"); bool success = true; if ( _NSGetArgv() != &NXArgv ) { printf("[FAIL] crt-libSystem: _NSGetArgv() != &NXArgv (%p!=%p) for %s", _NSGetArgv(), &NXArgv, argv[0]); success = false; } if ( _NSGetArgc() != &NXArgc ) { printf("[FAIL] crt-libSystem: _NSGetArgc() != &NXArgc (%p!=%p) for %s", _NSGetArgc(), &NXArgc, argv[0]); success = false; } if ( _NSGetEnviron() != &environ ) { printf("[FAIL] crt-libSystem: _NSGetEnviron() != &environv (%p!=%p) for %s", _NSGetEnviron(), &environ, argv[0]); success = false; } if ( _NSGetProgname() != &__progname ) { printf("[FAIL] crt-libSystem: _NSGetProgname() != &__progname (%p!=%p) for %s", _NSGetProgname(), &__progname, argv[0]); success = false; } if ( _NSGetMachExecuteHeader() != &_mh_execute_header ) { printf("[FAIL] crt-libSystem: _NSGetMachExecuteHeader() != &_mh_execute_headerv (%p!=%p) for %s", _NSGetMachExecuteHeader(), &_mh_execute_header, argv[0]); success = false; } if ( sVars->NXArgvPtr != &NXArgv ) { printf("[FAIL] crt-libSystem: sVars->NXArgvPtr != &NXArg (%p!=%p) for %s", sVars->NXArgvPtr, &NXArgv, argv[0]); success = false; } if ( sVars->NXArgcPtr != &NXArgc ) { printf("[FAIL] crt-libSystem: sVars->NXArgcPtr != &NXArgc (%p!=%p) for %s", sVars->NXArgcPtr, &NXArgc, argv[0]); success = false; } if ( sVars->environPtr != &environ ) { printf("[FAIL] crt-libSystem: sVars->environPtr != &environ (%p!=%p) for %s", sVars->environPtr, &environ, argv[0]); success = false; } if ( sVars->__prognamePtr != &__progname ) { printf("[FAIL] crt-libSystem: sVars->__prognamePtr != &__progname (%p!=%p) for %s", sVars->__prognamePtr, &__progname, argv[0]); success = false; } if ( sVars->mh != &_mh_execute_header ) { printf("[FAIL] crt-libSystem: sVars->mh != &_mh_execute_header (%p!=%p) for %s", sVars->mh, &_mh_execute_header, argv[0]); success = false; } if ( success ) printf("[PASS] crt-vars-libSystem\n"); return 0; }
static void on_load(void) { #ifdef HAVE_NSGETENVIRON environ = *_NSGetEnviron(); #endif if (!initialized) initialized = bear_capture_env_t(&initial_env); }
static void sanitizeEnviron (void) { char **e = NULL; int i; #if HAVE_DECL___ENVIRON e = __environ; #elif HAVE_DECL__NSGETENVIRON { char ***ep = _NSGetEnviron(); if (ep) e = *ep; } #endif if (!e) return; for (i = 0; e [i]; i++) { char *value; value = strchr (e [i], '='); if (!value) continue; value++; if (!strncmp (value, "() {", 4)) { error (WARNING, "reset environment: %s", e [i]); value [0] = '\0'; } } }
char *os_getenvname_at_index(size_t index) { # if defined(AMIGA) || defined(__MRC__) || defined(__SC__) // No environ[] on the Amiga and on the Mac (using MPW). return NULL; # else # if defined(HAVE__NSGETENVIRON) char **environ = *_NSGetEnviron(); # elif !defined(__WIN32__) // Borland C++ 5.2 has this in a header file. extern char **environ; # endif // check if index is inside the environ array for (size_t i = 0; i < index; i++) { if (environ[i] == NULL) { return NULL; } } char *str = environ[index]; if (str == NULL) { return NULL; } int namesize = 0; while (str[namesize] != '=' && str[namesize] != NUL) { namesize++; } char *name = (char *)vim_strnsave((char_u *)str, namesize); return name; # endif }
static int set_uncolog_osx(const char *logfn) { char **env; size_t n; #ifdef __linux__ env = environ; #elif defined(__APPLE__) env = *_NSGetEnviron(); #else # error "unknown env" #endif if (strlen(logfn) >= UNCO_LOG_PATH_MAX) { fprintf(stderr, "unco:log file name is too long:%s\n", logfn); return -1; } // find and replace for (n = 0; env[n] != NULL; ++n) { if (strncmp(env[n], "UNCO_LOG_PLACEHOLDER=", sizeof("UNCO_LOG_PLACEHOLDER=") - 1) == 0) break; } if (env[n] == NULL) { fprintf(stderr, "unco:env var UNCO_LOG_PLACEHOLDER not set\n"); return -1; } snprintf(env[n], strlen(env[n]) + 1, "UNCO_LOG=%s", logfn); return 0; }
pid_t rb_spawn_process(const char *path, const char **argv) { pid_t pid; const void *arghack = argv; char **myenviron; int error; posix_spawnattr_t spattr; posix_spawnattr_init(&spattr); #ifdef POSIX_SPAWN_USEVFORK posix_spawnattr_setflags(&spattr, POSIX_SPAWN_USEVFORK); #endif #ifdef __APPLE__ myenviron = *_NSGetEnviron(); /* apple needs to go f**k themselves for this */ #else myenviron = environ; #endif error = posix_spawn(&pid, path, NULL, &spattr, arghack, myenviron); posix_spawnattr_destroy(&spattr); if (error != 0) { errno = error; pid = -1; } return pid; }
/* return YAP's environment */ static YAP_Bool p_environ(void) { #if HAVE_ENVIRON && 0 #if HAVE__NSGETENVIRON char **ptr = _NSGetEnviron(); #elif defined(__MINGW32__) || _MSC_VER extern char **_environ; char **ptr = _environ; #else extern char **environ; char **ptr = environ; #endif YAP_Term t1 = YAP_ARG1; long int i; i = YAP_IntOfTerm(t1); if (ptr[i] == NULL) return (FALSE); else { YAP_Term t = YAP_BufferToString(ptr[i]); return (YAP_Unify(t, YAP_ARG2)); } #else YAP_Error(0, 0L, "environ not available in this configuration"); return (FALSE); #endif }
extern "C" CDECL int rust_run_program(const char* argv[], void* envp, const char* dir, int in_fd, int out_fd, int err_fd) { int pid = fork(); if (pid != 0) return pid; sigset_t sset; sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); if (in_fd) dup2(in_fd, 0); if (out_fd) dup2(out_fd, 1); if (err_fd) dup2(err_fd, 2); /* Close all other fds. */ for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd); if (dir) { chdir(dir); } #ifdef __APPLE__ if (envp) { *_NSGetEnviron() = (char **)envp; } execvp(argv[0], (char * const *)argv); #else if (!envp) { envp = environ; } execvpe(argv[0], (char * const *)argv, (char * const *)envp); #endif exit(1); }
extern "C" CDECL int rust_run_program(const char* argv[], void* envp, const char* dir, int in_fd, int out_fd, int err_fd) { int pid = fork(); if (pid != 0) return pid; sigset_t sset; sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); if (in_fd) dup2(in_fd, 0); if (out_fd) dup2(out_fd, 1); if (err_fd) dup2(err_fd, 2); /* Close all other fds. */ for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd); if (dir) { int result = chdir(dir); // FIXME: need error handling assert(!result && "chdir failed"); } if (envp) { #ifdef __APPLE__ *_NSGetEnviron() = (char **)envp; #else environ = (char **)envp; #endif } execvp(argv[0], (char * const *)argv); exit(1); }
DLLEXPORT int jl_spawn(char *name, char **argv, uv_loop_t *loop, uv_process_t *proc, jl_value_t *julia_struct, uv_handle_type stdin_type,uv_pipe_t *stdin_pipe, uv_handle_type stdout_type,uv_pipe_t *stdout_pipe, uv_handle_type stderr_type,uv_pipe_t *stderr_pipe) { #ifdef __APPLE__ char **environ = *_NSGetEnviron(); #endif uv_process_options_t opts; uv_stdio_container_t stdio[3]; int error; opts.file = name; #ifndef __WIN32__ opts.env = environ; #else opts.env = NULL; #endif opts.cwd = NULL; opts.args = argv; opts.flags = 0; opts.stdio = stdio; opts.stdio_count = 3; stdio[0].type = stdin_type; stdio[0].data.stream = (uv_stream_t*)(stdin_pipe); stdio[1].type = stdout_type; stdio[1].data.stream = (uv_stream_t*)(stdout_pipe); stdio[2].type = stderr_type; stdio[2].data.stream = (uv_stream_t*)(stderr_pipe); //opts.detached = 0; #This has been removed upstream to be uncommented once it is possible again opts.exit_cb = &jl_return_spawn; error = uv_spawn(loop,proc,opts); proc->data = julia_struct; return error; }
jl_value_t *jl_environ(int i) { #ifdef __APPLE__ char **environ = *_NSGetEnviron(); #endif char *env = environ[i]; return env ? jl_pchar_to_string(env, strlen(env)) : jl_nothing; }
static void vg_cleanup_env(void) { HChar **envp = (HChar**)*_NSGetEnviron(); env_unsetenv(envp, "VALGRIND_LAUNCHER"); env_unsetenv(envp, "DYLD_SHARED_REGION"); // GrP fixme should be more like mash_colon_env() env_unsetenv(envp, "DYLD_INSERT_LIBRARIES"); }
VixError VixToolsNewEnvIterator(void *userToken, // IN #ifdef __FreeBSD__ char **envp, // IN #endif VixToolsEnvIterator **envItr) // OUT { VixError err = VIX_OK; VixToolsEnvIterator *it = Util_SafeMalloc(sizeof *it); if (NULL == envItr) { err = VIX_E_FAIL; goto abort; } *envItr = NULL; #ifdef _WIN32 if (PROCESS_CREATOR_USER_TOKEN != userToken) { /* * The process is impersonating a user, so retrieve the user's * environment block instead of using the process's environment. */ it->envType = VIX_TOOLS_ENV_TYPE_ENV_BLOCK; err = VixToolsGetEnvBlock(userToken, &it->data.eb.envBlock); if (VIX_FAILED(err)) { goto abort; } it->data.eb.currEnvVar = it->data.eb.envBlock; } else { /* * The action is being performed as the user running the process * so the process's environment is fine. * TODO: Is this totally equivilent to the behavior when impersonated? * Would fetching the environment block include changes to the user's * or system's environment made after the process is running? */ it->envType = VIX_TOOLS_ENV_TYPE_ENVIRON; it->data.environ = _wenviron; } #elif defined(__APPLE__) it->environ = *_NSGetEnviron(); #elif defined(__FreeBSD__) it->environ = envp; #else it->environ = environ; #endif *envItr = it; abort: if (VIX_FAILED(err)) { free(it); } return err; }
List<String> Process::environment() { #ifdef OS_Darwin char **cur = *_NSGetEnviron(); #else extern char** environ; char** cur = environ; #endif List<String> env; while (*cur) { env.push_back(*cur); ++cur; } return env; }
PR_IMPLEMENT(char **) PR_DuplicateEnvironment(void) { char **the_environ, **result, **end, **src, **dst; _PR_LOCK_ENV(); #ifdef DARWIN the_environ = *(_NSGetEnviron()); #else the_environ = environ; #endif for (end = the_environ; *end != NULL; end++) /* empty loop body */; result = (char **)PR_Malloc(sizeof(char *) * (end - the_environ + 1)); if (result != NULL) { for (src = the_environ, dst = result; src != end; src++, dst++) { size_t len; len = strlen(*src) + 1; *dst = PR_Malloc(len); if (*dst == NULL) { /* Allocation failed. Must clean up the half-copied env. */ char **to_delete; for (to_delete = result; to_delete != dst; to_delete++) { PR_Free(*to_delete); } PR_Free(result); result = NULL; goto out; } memcpy(*dst, *src, len); } *dst = NULL; } out: _PR_UNLOCK_ENV(); return result; }
void RNG_SystemInfoForRNG(void) { FILE *fp; char buf[BUFSIZ]; size_t bytes; const char * const *cp; char *randfile; #ifdef DARWIN #if TARGET_OS_IPHONE /* iOS does not expose a way to access environ. */ char **environ = NULL; #else char **environ = *_NSGetEnviron(); #endif #else extern char **environ; #endif #ifdef BEOS static const char * const files[] = { "/boot/var/swap", "/boot/var/log/syslog", "/boot/var/tmp", "/boot/home/config/settings", "/boot/home", 0 }; #else static const char * const files[] = { "/etc/passwd", "/etc/utmp", "/tmp", "/var/tmp", "/usr/tmp", 0 }; #endif #if defined(BSDI) static char netstat_ni_cmd[] = "netstat -nis"; #else static char netstat_ni_cmd[] = "netstat -ni"; #endif GiveSystemInfo(); bytes = RNG_GetNoise(buf, sizeof(buf)); RNG_RandomUpdate(buf, bytes); /* * Pass the C environment and the addresses of the pointers to the * hash function. This makes the random number function depend on the * execution environment of the user and on the platform the program * is running on. */ if (environ != NULL) { cp = (const char * const *) environ; while (*cp) { RNG_RandomUpdate(*cp, strlen(*cp)); cp++; } RNG_RandomUpdate(environ, (char*)cp - (char*)environ); } /* Give in system information */ if (gethostname(buf, sizeof(buf)) == 0) { RNG_RandomUpdate(buf, strlen(buf)); } GiveSystemInfo(); /* grab some data from system's PRNG before any other files. */ bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); /* If the user points us to a random file, pass it through the rng */ randfile = getenv("NSRANDFILE"); if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) { char *randCountString = getenv("NSRANDCOUNT"); int randCount = randCountString ? atoi(randCountString) : 0; if (randCount != 0) { RNG_FileUpdate(randfile, randCount); } else { RNG_FileForRNG(randfile); } } /* pass other files through */ for (cp = files; *cp; cp++) RNG_FileForRNG(*cp); /* * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen * in a pthreads environment. Therefore, we call safe_popen last and on * BSD/OS we do not call safe_popen when we succeeded in getting data * from /dev/urandom. * * Bug 174993: On platforms providing /dev/urandom, don't fork netstat * either, if data has been gathered successfully. */ #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \ || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \ || defined(HPUX) if (bytes) return; #endif #ifdef SOLARIS /* * On Solaris, NSS may be initialized automatically from libldap in * applications that are unaware of the use of NSS. safe_popen forks, and * sometimes creates issues with some applications' pthread_atfork handlers. * We always have /dev/urandom on Solaris 9 and above as an entropy source, * and for Solaris 8 we have the libkstat interface, so we don't need to * fork netstat. */ #undef DO_NETSTAT if (!bytes) { /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */ PRUint32 kstat_bytes = 0; if (SECSuccess != RNG_kstat(&kstat_bytes)) { PORT_Assert(0); } bytes += kstat_bytes; PORT_Assert(bytes); } #endif #ifdef DO_NETSTAT fp = safe_popen(netstat_ni_cmd); if (fp != NULL) { while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) RNG_RandomUpdate(buf, bytes); safe_pclose(fp); } #endif }
rpmRC rpmjsRunFile(rpmjs js, const char * fn, char *const * Iargv, const char ** resultp) { rpmRC rc = RPMRC_FAIL; if (js == NULL) js = rpmjsI(); if (fn != NULL) { #if defined(WITH_GPSEE) gpsee_interpreter_t * I = js->I; FILE * fp = rpmjsOpenFile(js, fn, resultp); if (fp == NULL) { I->grt->exitType = et_execFailure; /* XXX FIXME: strerror in *resultp */ goto exit; } #ifdef NOTYET /* XXX FIXME */ processInlineFlags(js, fp, &verbosity); gpsee_setVerbosity(verbosity); #endif /* Just compile and exit? */ if (F_ISSET(js->flags, NOEXEC)) { JSScript *script = NULL; JSObject *scrobj = NULL; if (!gpsee_compileScript(I->cx, fn, fp, NULL, &script, I->realm->globalObject, &scrobj)) { I->grt->exitType = et_exception; /* XXX FIXME: isatty(3) */ gpsee_reportUncaughtException(I->cx, JSVAL_NULL, (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) || ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) && isatty(STDERR_FILENO))); } else { I->grt->exitType = et_finished; rc = RPMRC_OK; } } else { char *const * Ienviron = NULL; if (F_ISSET(js->flags, ALLOW)) { #if defined(__APPLE__) Ienviron = (char *const *) _NSGetEnviron(); #else Ienviron = environ; #endif } I->grt->exitType = et_execFailure; if (gpsee_runProgramModule(I->cx, fn, NULL, fp, Iargv, Ienviron) == JS_FALSE) { int code = gpsee_getExceptionExitCode(I->cx); if (code >= 0) { I->grt->exitType = et_requested; I->grt->exitCode = code; /* XXX FIXME: format and return code in *resultp. */ /* XXX hack tp get code into rc -> ec by negating */ rc = -code; } else if (JS_IsExceptionPending(I->cx)) { /* XXX FIXME: isatty(3) */ gpsee_reportUncaughtException(I->cx, JSVAL_NULL, (gpsee_verbosity(0) >= GSR_FORCE_STACK_DUMP_VERBOSITY) || ((gpsee_verbosity(0) >= GPSEE_ERROR_OUTPUT_VERBOSITY) && isatty(STDERR_FILENO))); } } else { I->grt->exitType = et_finished; rc = RPMRC_OK; } } fclose(fp); fp = NULL; #endif /* WITH_GPSEE */ } #if defined(WITH_GPSEE) exit: #endif /* WITH_GPSEE */ RPMJSDBG(0, (stderr, "<== %s(%p,%s) rc %d |%s|\n", __FUNCTION__, js, fn, rc, (resultp ? *resultp :""))); return rc; }
int main(int argc, const char **argv) #endif { bContext *C = CTX_create(); SYS_SystemHandle syshandle; #ifndef WITH_PYTHON_MODULE bArgs *ba; #endif #ifdef WIN32 wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); int argci = 0; char **argv = MEM_mallocN(argc * sizeof(char *), "argv array"); for (argci = 0; argci < argc; argci++) { argv[argci] = alloc_utf_8_from_16(argv_16[argci], 0); } LocalFree(argv_16); #endif #ifdef WITH_PYTHON_MODULE #ifdef __APPLE__ environ = *_NSGetEnviron(); #endif #undef main evil_C = C; #endif #ifdef WITH_BINRELOC br_init(NULL); #endif #ifdef WITH_LIBMV libmv_initLogging(argv[0]); #endif setCallbacks(); #if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE) /* patch to ignore argument finder gives us (pid?) */ if (argc == 2 && strncmp(argv[1], "-psn_", 5) == 0) { extern int GHOST_HACK_getFirstFile(char buf[]); static char firstfilebuf[512]; argc = 1; if (GHOST_HACK_getFirstFile(firstfilebuf)) { argc = 2; argv[1] = firstfilebuf; } } #endif #ifdef __FreeBSD__ fpsetmask(0); #endif /* initialize path to executable */ BLI_init_program_path(argv[0]); BLI_threadapi_init(); initglobals(); /* blender.c */ IMB_init(); BKE_images_init(); BKE_brush_system_init(); BLI_callback_global_init(); #ifdef WITH_GAMEENGINE syshandle = SYS_GetSystem(); #else syshandle = 0; #endif /* first test for background */ #ifndef WITH_PYTHON_MODULE ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */ setupArguments(C, ba, &syshandle); BLI_argsParse(ba, 1, NULL, NULL); if (use_crash_handler) { /* after parsing args */ signal(SIGSEGV, blender_crash_handler); } #else G.factory_startup = true; /* using preferences or user startup makes no sense for py-as-module */ (void)syshandle; #endif #ifdef WITH_FFMPEG IMB_ffmpeg_init(); #endif /* after level 1 args, this is so playanim skips RNA init */ RNA_init(); RE_engines_init(); init_nodesystem(); /* end second init */ #if defined(WITH_PYTHON_MODULE) || defined(WITH_HEADLESS) G.background = true; /* python module mode ALWAYS runs in background mode (for now) */ #else /* for all platforms, even windos has it! */ if (G.background) { signal(SIGINT, blender_esc); /* ctrl c out bg render */ } #endif /* background render uses this font too */ BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size); /* Initialize ffmpeg if built in, also needed for bg mode if videos are * rendered via ffmpeg */ sound_init_once(); init_def_material(); if (G.background == 0) { #ifndef WITH_PYTHON_MODULE BLI_argsParse(ba, 2, NULL, NULL); BLI_argsParse(ba, 3, NULL, NULL); #endif WM_init(C, argc, (const char **)argv); /* this is properly initialized with user defs, but this is default */ /* call after loading the startup.blend so we can read U.tempdir */ BLI_init_temporary_dir(U.tempdir); #ifdef WITH_SDL BLI_setenv("SDL_VIDEODRIVER", "dummy"); #endif } else { #ifndef WITH_PYTHON_MODULE BLI_argsParse(ba, 3, NULL, NULL); #endif WM_init(C, argc, (const char **)argv); /* don't use user preferences temp dir */ BLI_init_temporary_dir(NULL); } #ifdef WITH_PYTHON /** * NOTE: the U.pythondir string is NULL until WM_init() is executed, * so we provide the BPY_ function below to append the user defined * python-dir to Python's sys.path at this point. Simply putting * WM_init() before #BPY_python_start() crashes Blender at startup. */ /* TODO - U.pythondir */ #else printf("\n* WARNING * - Blender compiled without Python!\nthis is not intended for typical usage\n\n"); #endif CTX_py_init_set(C, 1); WM_keymap_init(C); #ifdef WITH_FREESTYLE /* initialize Freestyle */ FRS_initialize(); FRS_set_context(C); #endif /* OK we are ready for it */ #ifndef WITH_PYTHON_MODULE BLI_argsParse(ba, 4, load_file, C); if (G.background == 0) { if (!G.file_loaded) if (U.uiflag2 & USER_KEEP_SESSION) WM_recover_last_session(C, NULL); } #endif #ifndef WITH_PYTHON_MODULE BLI_argsFree(ba); #endif #ifdef WIN32 while (argci) { free(argv[--argci]); } MEM_freeN(argv); argv = NULL; #endif #ifdef WITH_PYTHON_MODULE return 0; /* keep blender in background mode running */ #endif if (G.background) { /* actually incorrect, but works for now (ton) */ WM_exit(C); } else { if (G.fileflags & G_FILE_AUTOPLAY) { if (G.f & G_SCRIPT_AUTOEXEC) { if (WM_init_game(C)) { return 0; } } else { if (!(G.f & G_SCRIPT_AUTOEXEC_FAIL_QUIET)) { G.f |= G_SCRIPT_AUTOEXEC_FAIL; BLI_snprintf(G.autoexec_fail, sizeof(G.autoexec_fail), "Game AutoStart"); } } } if (!G.file_loaded) { WM_init_splash(C); } } WM_main(C); return 0; } /* end of int main(argc, argv) */
int NaClMainForChromium(int handle_count, const NaClHandle *handles, int debug) { char *av[1]; int ac = 1; const char **envp; struct NaClApp state; int main_thread_only = 1; int export_addr_to = kSrpcFd; /* Used to be set by -X. */ struct NaClApp *nap; NaClErrorCode errcode; int ret_code = 1; struct NaClEnvCleanser env_cleanser; #if NACL_OSX /* Mac dynamic libraries cannot access the environ variable directly. */ envp = (const char **) *_NSGetEnviron(); #else /* Overzealous code style check is overzealous. */ /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ extern char **environ; envp = (const char **) environ; #endif NaClAllModulesInit(); /* Add a handler to catch untrusted errors only */ NaClSignalHandlerAdd(NaClSignalHandleUntrusted); /* to be passed to NaClMain, eventually... */ av[0] = "NaClMain"; if (!NaClAppCtor(&state)) { fprintf(stderr, "Error while constructing app state\n"); goto done; } state.restrict_to_main_thread = main_thread_only; nap = &state; errcode = LOAD_OK; /* import IMC handle - used to be "-i" */ CHECK(handle_count == 3); NaClAddImcHandle(nap, handles[0], export_addr_to); NaClAddImcHandle(nap, handles[1], 6); /* async_receive_desc */ NaClAddImcHandle(nap, handles[2], 7); /* async_send_desc */ /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure this operating system platform is supported. */ errcode = NaClRunSelQualificationTests(); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "Error while loading in SelMain: %s\n", NaClErrorString(errcode)); } /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(&state); /* * If export_addr_to is set to a non-negative integer, we create a * bound socket and socket address pair and bind the former to * descriptor 3 and the latter to descriptor 4. The socket address * is written out to the export_addr_to descriptor. * * The service runtime also accepts a connection on the bound socket * and spawns a secure command channel thread to service it. * * If export_addr_to is -1, we only create the bound socket and * socket address pair, and we do not export to an IMC socket. This * use case is typically only used in testing, where we only "dump" * the socket address to stdout or similar channel. */ if (-2 < export_addr_to) { NaClCreateServiceSocket(nap); if (0 <= export_addr_to) { NaClSendServiceAddressTo(nap, export_addr_to); /* * NB: spawns a thread that uses the command channel. we do * this after NaClAppLoadFile so that NaClApp object is more * fully populated. Hereafter any changes to nap should be done * while holding locks. */ NaClSecureCommandChannel(nap); } } if (NULL != nap->secure_channel && LOAD_OK == errcode) { /* * wait for start_module RPC call on secure channel thread. */ errcode = NaClWaitForStartModuleCommand(nap); } /* * error reporting done; can quit now if there was an error earlier. */ if (LOAD_OK != errcode) { goto done; } /* * Enable debugging if requested. */ if (debug) NaClDebugSetAllow(1); NaClEnvCleanserCtor(&env_cleanser); if (!NaClEnvCleanserInit(&env_cleanser, envp)) { NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n"); } /* * only nap->ehdrs.e_entry is usable, no symbol table is * available. */ if (!NaClCreateMainThread(nap, ac, av, NaClEnvCleanserEnvironment(&env_cleanser))) { fprintf(stderr, "creating main thread failed\n"); goto done; } NaClEnvCleanserDtor(&env_cleanser); ret_code = NaClWaitForMainThreadToExit(nap); /* * exit_group or equiv kills any still running threads while module * addr space is still valid. otherwise we'd have to kill threads * before we clean up the address space. */ return ret_code; done: fflush(stdout); NaClAllModulesFini(); return ret_code; }
extern "C" CDECL rust_str * rust_getcwd() { rust_task *task = rust_get_current_task(); LOG(task, task, "rust_getcwd()"); char cbuf[BUF_BYTES]; #if defined(__WIN32__) if (!_getcwd(cbuf, sizeof(cbuf))) { #else if (!getcwd(cbuf, sizeof(cbuf))) { #endif task->fail(); return NULL; } return make_str(task->kernel, cbuf, strlen(cbuf), "rust_str(getcwd)"); } #if defined(__WIN32__) extern "C" CDECL rust_vec_box * rust_env_pairs() { rust_task *task = rust_get_current_task(); size_t envc = 0; LPTCH ch = GetEnvironmentStringsA(); LPTCH c; for (c = ch; *c; c += strlen(c) + 1) { ++envc; } c = ch; rust_vec_box *v = (rust_vec_box *) task->kernel->malloc(vec_size<rust_vec_box*>(envc), "str vec interior"); v->body.fill = v->body.alloc = sizeof(rust_vec*) * envc; for (size_t i = 0; i < envc; ++i) { size_t n = strlen(c); rust_str *str = make_str(task->kernel, c, n, "str"); ((rust_str**)&v->body.data)[i] = str; c += n + 1; } if (ch) { FreeEnvironmentStrings(ch); } return v; } #else extern "C" CDECL rust_vec_box * rust_env_pairs() { rust_task *task = rust_get_current_task(); #ifdef __APPLE__ char **environ = *_NSGetEnviron(); #endif char **e = environ; size_t envc = 0; while (*e) { ++envc; ++e; } return make_str_vec(task->kernel, envc, environ); } #endif extern "C" CDECL void unsupervise() { rust_task *task = rust_get_current_task(); task->unsupervise(); }
static int reexec(cpu_type_t cputype, const char *guardenv) { posix_spawnattr_t attr; int ret, envcount; size_t copied = 0; char **argv, **oldenvp, **newenvp; char execpath[MAXPATHLEN+1]; uint32_t execsize; char guardstr[32]; argv = *_NSGetArgv(); oldenvp = *_NSGetEnviron(); for (envcount = 0; oldenvp[envcount]; envcount++); // if there are 4 elements and a NULL, envcount will be 4 newenvp = calloc(envcount+2, sizeof(newenvp[0])); for (envcount = 0; oldenvp[envcount]; envcount++) { newenvp[envcount] = oldenvp[envcount]; } snprintf(guardstr, sizeof(guardstr), "%s=1", guardenv); newenvp[envcount++] = guardstr; newenvp[envcount] = NULL; execsize = (uint32_t)sizeof(execpath); ret = _NSGetExecutablePath(execpath, &execsize); if (ret != 0) { return -1; } ret = posix_spawnattr_init(&attr); if (ret != 0) { return -1; } ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC); if (ret != 0) { return -1; } ret = posix_spawnattr_setbinpref_np(&attr, 1, &cputype, &copied); if (ret != 0 || copied != 1) { return -1; } #if 0 fprintf(stderr, "reexec: %s (arch=%d)\n", execpath, cputype); for (envcount=0; newenvp[envcount]; envcount++) { fprintf(stderr, "env[%d] = %s\n", envcount, newenvp[envcount]); } for (envcount=0; argv[envcount]; envcount++) { fprintf(stderr, "argv[%d] = %s\n", envcount, argv[envcount]); } #endif ret = posix_spawn(NULL, execpath, NULL, &attr, argv, newenvp); if (ret != 0) { errno = ret; return -1; } /* should not be reached */ return 0; }
int NaClMainForChromium(int handle_count, const NaClHandle *handles, int debug) { char *av[1]; int ac = 1; const char **envp; struct NaClApp state; int main_thread_only = 1; char *nacl_file = "test_nexe/hello_ppapi.nexe"; struct NaClApp *nap; enum NaClAbiCheckOption check_abi = NACL_ABI_CHECK_OPTION_CHECK; struct GioFile gout; struct GioMemoryFileSnapshot gf; NaClErrorCode errcode; int ret_code = 1; struct NaClEnvCleanser env_cleanser; #if NACL_OSX /* Mac dynamic libraries cannot access the environ variable directly. */ envp = (const char **) *_NSGetEnviron(); #else /* Overzealous code style check is overzealous. */ /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ extern char **environ; envp = (const char **) environ; #endif NaClAllModulesInit(); /* Add a handler to catch untrusted errors only */ NaClSignalHandlerAdd(NaClSignalHandleUntrusted); /* to be passed to NaClMain, eventually... */ av[0] = "NaClMain"; if (!NaClAppCtor(&state)) { fprintf(stderr, "Error while constructing app state\n"); goto done; } state.restrict_to_main_thread = main_thread_only; nap = &state; errcode = LOAD_OK; /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure this operating system platform is supported. */ errcode = NaClRunSelQualificationTests(); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "Error while loading in SelMain: %s\n", NaClErrorString(errcode)); } /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(&state); if (0 == GioMemoryFileSnapshotCtor(&gf, nacl_file)) { perror("sel_main"); fprintf(stderr, "Cannot open \"%s\".\n", nacl_file); errcode = LOAD_OPEN_ERROR; } if (LOAD_OK == errcode) { errcode = NaClAppLoadFile((struct Gio *) &gf, nap, check_abi); if (LOAD_OK != errcode) { fprintf(stderr, "Error while loading \"%s\": %s\n", nacl_file, NaClErrorString(errcode)); fprintf(stderr, ("Using the wrong type of nexe (nacl-x86-32" " on an x86-64 or vice versa)\n" "or a corrupt nexe file may be" " responsible for this error.\n")); } NaClXMutexLock(&nap->mu); nap->module_load_status = errcode; NaClXCondVarBroadcast(&nap->cv); NaClXMutexUnlock(&nap->mu); } if (LOAD_OK == errcode) { if (verbosity) { gprintf((struct Gio *) &gout, "printing NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); } /* * Finish setting up the NaCl App. This includes dup'ing * descriptors 0-2 and making them available to the NaCl App. */ errcode = NaClAppPrepareToLaunch(nap, 0, 1, 2); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "NaClAppPrepareToLaunch returned %d", errcode); } } if (-1 == (*((struct Gio *) &gf)->vtbl->Close)((struct Gio *) &gf)) { fprintf(stderr, "Error while closing \"%s\".\n", nacl_file); } (*((struct Gio *) &gf)->vtbl->Dtor)((struct Gio *) &gf); /* * Print out a marker for scripts to use to mark the start of app * output. */ NaClLog(1, "NACL: Application output follows\n"); /* * Make sure all the file buffers are flushed before entering * the application code. */ fflush((FILE *) NULL); /* * Enable debugging if requested. */ if (debug) NaClDebugSetAllow(1); NaClEnvCleanserCtor(&env_cleanser); if (!NaClEnvCleanserInit(&env_cleanser, envp)) { NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n"); } /* * only nap->ehdrs.e_entry is usable, no symbol table is * available. */ if (!NaClCreateMainThread(nap, ac, av, NaClEnvCleanserEnvironment(&env_cleanser))) { fprintf(stderr, "creating main thread failed\n"); goto done; } NaClEnvCleanserDtor(&env_cleanser); ret_code = NaClWaitForMainThreadToExit(nap); /* * exit_group or equiv kills any still running threads while module * addr space is still valid. otherwise we'd have to kill threads * before we clean up the address space. */ return ret_code; done: fflush(stdout); NaClAllModulesFini(); return ret_code; }
int main (int argc, char *const *argv, char *const *envp, const char **apple) { #if defined (DEBUG_LLDB_LAUNCHER) const char *program_name = strrchr(apple[0], '/'); if (program_name) program_name++; // Skip the last slash.. else program_name = apple[0]; printf("%s called with:\n", program_name); for (int i=0; i<argc; ++i) printf("argv[%u] = '%s'\n", i, argv[i]); #endif cpu_type_t cpu_type = 0; bool show_usage = false; int ch; int disable_aslr = 0; // By default we disable ASLR bool pass_env = true; std::string unix_socket_name; std::string working_dir; #if __GLIBC__ optind = 0; #else optreset = 1; optind = 1; #endif while ((ch = getopt_long_only(argc, argv, "a:deE:hsu:?", g_long_options, NULL)) != -1) { switch (ch) { case 0: break; case 'a': // "-a i386" or "--arch=i386" if (optarg) { if (streq (optarg, "i386")) cpu_type = CPU_TYPE_I386; else if (streq (optarg, "x86_64")) cpu_type = CPU_TYPE_X86_64; else if (streq (optarg, "x86_64h")) cpu_type = 0; // Don't set CPU type when we have x86_64h else if (strstr (optarg, "arm") == optarg) cpu_type = CPU_TYPE_ARM; else { ::fprintf (stderr, "error: unsupported cpu type '%s'\n", optarg); ::exit (1); } } break; case 'd': disable_aslr = 1; break; case 'e': pass_env = false; break; case 'E': { // Since we will exec this program into our new program, we can just set environment // variables in this process and they will make it into the child process. std::string name; std::string value; const char *equal_pos = strchr (optarg, '='); if (equal_pos) { name.assign (optarg, equal_pos - optarg); value.assign (equal_pos + 1); } else { name = optarg; } ::setenv (name.c_str(), value.c_str(), 1); } break; case 's': // Create a new session to avoid having control-C presses kill our current // terminal session when this program is launched from a .command file ::setsid(); break; case 'u': unix_socket_name.assign (optarg); break; case 'w': { struct stat working_dir_stat; if (stat (optarg, &working_dir_stat) == 0) working_dir.assign (optarg); else ::fprintf(stderr, "warning: working directory doesn't exist: '%s'\n", optarg); } break; case 'h': case '?': default: show_usage = true; break; } } argc -= optind; argv += optind; if (show_usage || argc <= 0 || unix_socket_name.empty()) usage(); #if defined (DEBUG_LLDB_LAUNCHER) printf ("\n%s post options:\n", program_name); for (int i=0; i<argc; ++i) printf ("argv[%u] = '%s'\n", i, argv[i]); #endif // Open the socket that was passed in as an option struct sockaddr_un saddr_un; int s = ::socket (AF_UNIX, SOCK_STREAM, 0); if (s < 0) { perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); exit(1); } saddr_un.sun_family = AF_UNIX; ::strncpy(saddr_un.sun_path, unix_socket_name.c_str(), sizeof(saddr_un.sun_path) - 1); saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; saddr_un.sun_len = SUN_LEN (&saddr_un); if (::connect (s, (struct sockaddr *)&saddr_un, SUN_LEN (&saddr_un)) < 0) { perror("error: connect (socket, &saddr_un, saddr_un_len)"); exit(1); } // We were able to connect to the socket, now write our PID so whomever // launched us will know this process's ID char pid_str[64]; const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%i", ::getpid()); const int bytes_sent = ::send (s, pid_str, pid_str_len, 0); if (pid_str_len != bytes_sent) { perror("error: send (s, pid_str, pid_str_len, 0)"); exit (1); } // We are done with the socket close (s); system("clear"); printf ("Launching: '%s'\n", argv[0]); if (working_dir.empty()) { char cwd[PATH_MAX]; const char *cwd_ptr = getcwd(cwd, sizeof(cwd)); printf ("Working directory: '%s'\n", cwd_ptr); } else { printf ("Working directory: '%s'\n", working_dir.c_str()); } printf ("%i arguments:\n", argc); for (int i=0; i<argc; ++i) printf ("argv[%u] = '%s'\n", i, argv[i]); // Now we posix spawn to exec this process into the inferior that we want // to debug. posix_spawn_for_debug (argv, pass_env ? *_NSGetEnviron() : NULL, // Pass current environment as we may have modified it if "--env" options was used, do NOT pass "envp" here working_dir.empty() ? NULL : working_dir.c_str(), cpu_type, disable_aslr); return 0; }
bool wxGetEnvMap(wxEnvVariableHashMap *map) { wxCHECK_MSG( map, false, wxS("output pointer can't be NULL") ); #if defined(__VISUALC__) // This variable only exists to force the CRT to fill the wide char array, // it might only have it in narrow char version until now as we use main() // (and not _wmain()) as our entry point. static wxChar* s_dummyEnvVar = _tgetenv(wxT("TEMP")); wxChar **env = _tenviron; #elif defined(__VMS) // Now this routine wil give false for OpenVMS // TODO : should we do something with logicals? char **env=NULL; #elif defined(__DARWIN__) #if wxOSX_USE_COCOA_OR_CARBON // Under Mac shared libraries don't have access to the global environ // variable so use this Mac-specific function instead as advised by // environ(7) under Darwin char ***penv = _NSGetEnviron(); if ( !penv ) return false; char **env = *penv; #else char **env=NULL; // todo translate NSProcessInfo environment into map #endif #else // non-MSVC non-Mac // Not sure if other compilers have _tenviron so use the (more standard) // ANSI version only for them. // Both POSIX and Single UNIX Specification say that this variable must // exist but not that it must be declared anywhere and, indeed, it's not // declared in several common systems (some BSDs, Solaris with native CC) // so we (re)declare it ourselves to deal with these cases. However we do // not do this under MSW where there can be DLL-related complications, i.e. // the variable might be DLL-imported or not. Luckily we don't have to // worry about this as all MSW compilers do seem to define it in their // standard headers anyhow so we can just rely on already having the // correct declaration. And if this turns out to be wrong, we can always // add a configure test checking whether it is declared later. #ifndef __WINDOWS__ extern char **environ; #endif // !__WINDOWS__ char **env = environ; #endif if ( env ) { wxString name, value; while ( *env ) { const wxString var(*env); name = var.BeforeFirst(wxS('='), &value); (*map)[name] = value; env++; } return true; } return false; }
static PRProcess * ForkAndExec( const char *path, char *const *argv, char *const *envp, const PRProcessAttr *attr) { PRProcess *process; int nEnv, idx; char *const *childEnvp; char **newEnvp = NULL; int flags; process = PR_NEW(PRProcess); if (!process) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } childEnvp = envp; if (attr && attr->fdInheritBuffer) { PRBool found = PR_FALSE; if (NULL == childEnvp) { #ifdef DARWIN childEnvp = *(_NSGetEnviron()); #else childEnvp = environ; #endif } for (nEnv = 0; childEnvp[nEnv]; nEnv++) { } newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *)); if (NULL == newEnvp) { PR_DELETE(process); PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } for (idx = 0; idx < nEnv; idx++) { newEnvp[idx] = childEnvp[idx]; if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) { newEnvp[idx] = attr->fdInheritBuffer; found = PR_TRUE; } } if (!found) { newEnvp[idx++] = attr->fdInheritBuffer; } newEnvp[idx] = NULL; childEnvp = newEnvp; } #ifdef AIX process->md.pid = (*pr_wp.forkptr)(); #elif defined(NTO) || defined(SYMBIAN) /* * fork() & exec() does not work in a multithreaded process. * Use spawn() instead. */ { int fd_map[3] = { 0, 1, 2 }; if (attr) { if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) { fd_map[0] = dup(attr->stdinFd->secret->md.osfd); flags = fcntl(fd_map[0], F_GETFL, 0); if (flags & O_NONBLOCK) fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK); } if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) { fd_map[1] = dup(attr->stdoutFd->secret->md.osfd); flags = fcntl(fd_map[1], F_GETFL, 0); if (flags & O_NONBLOCK) fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK); } if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) { fd_map[2] = dup(attr->stderrFd->secret->md.osfd); flags = fcntl(fd_map[2], F_GETFL, 0); if (flags & O_NONBLOCK) fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK); } PR_ASSERT(attr->currentDirectory == NULL); /* not implemented */ } #ifdef SYMBIAN /* In Symbian OS, we use posix_spawn instead of fork() and exec() */ posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp); #else process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp); #endif if (fd_map[0] != 0) close(fd_map[0]); if (fd_map[1] != 1) close(fd_map[1]); if (fd_map[2] != 2) close(fd_map[2]); } #else process->md.pid = fork(); #endif if ((pid_t) -1 == process->md.pid) { PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); PR_DELETE(process); if (newEnvp) { PR_DELETE(newEnvp); } return NULL; } else if (0 == process->md.pid) { /* the child process */ /* * If the child process needs to exit, it must call _exit(). * Do not call exit(), because exit() will flush and close * the standard I/O file descriptors, and hence corrupt * the parent process's standard I/O data structures. */ #if !defined(NTO) && !defined(SYMBIAN) if (attr) { /* the osfd's to redirect stdin, stdout, and stderr to */ int in_osfd = -1, out_osfd = -1, err_osfd = -1; if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) { in_osfd = attr->stdinFd->secret->md.osfd; if (dup2(in_osfd, 0) != 0) { _exit(1); /* failed */ } flags = fcntl(0, F_GETFL, 0); if (flags & O_NONBLOCK) { fcntl(0, F_SETFL, flags & ~O_NONBLOCK); } } if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) { out_osfd = attr->stdoutFd->secret->md.osfd; if (dup2(out_osfd, 1) != 1) { _exit(1); /* failed */ } flags = fcntl(1, F_GETFL, 0); if (flags & O_NONBLOCK) { fcntl(1, F_SETFL, flags & ~O_NONBLOCK); } } if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) { err_osfd = attr->stderrFd->secret->md.osfd; if (dup2(err_osfd, 2) != 2) { _exit(1); /* failed */ } flags = fcntl(2, F_GETFL, 0); if (flags & O_NONBLOCK) { fcntl(2, F_SETFL, flags & ~O_NONBLOCK); } } if (in_osfd != -1) { close(in_osfd); } if (out_osfd != -1 && out_osfd != in_osfd) { close(out_osfd); } if (err_osfd != -1 && err_osfd != in_osfd && err_osfd != out_osfd) { close(err_osfd); } if (attr->currentDirectory) { if (chdir(attr->currentDirectory) < 0) { _exit(1); /* failed */ } } } if (childEnvp) { (void)execve(path, argv, childEnvp); } else { /* Inherit the environment of the parent. */ (void)execv(path, argv); } /* Whoops! It returned. That's a bad sign. */ _exit(1); #endif /* !NTO */ } if (newEnvp) { PR_DELETE(newEnvp); } #if defined(_PR_NATIVE_THREADS) PR_Lock(pr_wp.ml); if (0 == pr_wp.numProcs++) { PR_NotifyCondVar(pr_wp.cv); } PR_Unlock(pr_wp.ml); #endif return process; }
int NaClSelLdrMain(int argc, char **argv) { int opt; char *rest; struct redir *entry; struct redir *redir_queue; struct redir **redir_qend; struct NaClApp state; char *nacl_file = NULL; char *blob_library_file = NULL; int rpc_supplies_nexe = 0; int export_addr_to = -1; struct NaClApp *nap = &state; struct GioFile gout; NaClErrorCode errcode = LOAD_INTERNAL; struct GioMemoryFileSnapshot blob_file; int ret_code; struct DynArray env_vars; char *log_file = NULL; int verbosity = 0; int fuzzing_quit_after_load = 0; int debug_mode_bypass_acl_checks = 0; int debug_mode_ignore_validator = 0; int skip_qualification = 0; int handle_signals = 0; int enable_debug_stub = 0; struct NaClPerfCounter time_all_main; const char **envp; struct NaClEnvCleanser env_cleanser; #if NACL_OSX /* Mac dynamic libraries cannot access the environ variable directly. */ envp = (const char **) *_NSGetEnviron(); #else /* Overzealous code style check is overzealous. */ /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ extern char **environ; envp = (const char **) environ; #endif ret_code = 1; redir_queue = NULL; redir_qend = &redir_queue; memset(&state, 0, sizeof state); NaClAllModulesInit(); NaClBootstrapChannelErrorReporterInit(); NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, &state); verbosity = NaClLogGetVerbosity(); NaClPerfCounterCtor(&time_all_main, "SelMain"); fflush((FILE *) NULL); NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv); if (!GioFileRefCtor(&gout, stdout)) { fprintf(stderr, "Could not create general standard output channel\n"); exit(1); } if (!NaClAppCtor(&state)) { NaClLog(LOG_FATAL, "NaClAppCtor() failed\n"); } if (!DynArrayCtor(&env_vars, 0)) { NaClLog(LOG_FATAL, "Failed to allocate env var array\n"); } /* * On platforms with glibc getopt, require POSIXLY_CORRECT behavior, * viz, no reordering of the arglist -- stop argument processing as * soon as an unrecognized argument is encountered, so that, for * example, in the invocation * * sel_ldr foo.nexe -vvv * * the -vvv flags are made available to the nexe, rather than being * consumed by getopt. This makes the behavior of the Linux build * of sel_ldr consistent with the Windows and OSX builds. */ while ((opt = my_getopt(argc, argv, #if NACL_LINUX "+D:z:" #endif "aB:ceE:f:Fgh:i:l:Qr:RsSvw:X:Z")) != -1) { switch (opt) { case 'a': fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n"); debug_mode_bypass_acl_checks = 1; break; case 'B': blob_library_file = optarg; break; case 'c': ++debug_mode_ignore_validator; break; #if NACL_LINUX case 'D': NaClHandleRDebug(optarg, argv[0]); break; #endif case 'e': nap->enable_exception_handling = 1; break; case 'E': /* * For simplicity, we treat the environment variables as a * list of strings rather than a key/value mapping. We do not * try to prevent duplicate keys or require the strings to be * of the form "KEY=VALUE". This is in line with how execve() * works in Unix. * * We expect that most callers passing "-E" will either pass * in a fixed list or will construct the list using a * high-level language, in which case de-duplicating keys * outside of sel_ldr is easier. However, we could do * de-duplication here if it proves to be worthwhile. */ if (!DynArraySet(&env_vars, env_vars.num_entries, optarg)) { NaClLog(LOG_FATAL, "Adding item to env_vars failed\n"); } break; case 'f': nacl_file = optarg; break; case 'F': fuzzing_quit_after_load = 1; break; case 'g': enable_debug_stub = 1; break; case 'h': case 'r': case 'w': /* import host descriptor */ entry = malloc(sizeof *entry); if (NULL == entry) { fprintf(stderr, "No memory for redirection queue\n"); exit(1); } entry->next = NULL; entry->nacl_desc = strtol(optarg, &rest, 0); entry->tag = HOST_DESC; entry->u.host.d = strtol(rest+1, (char **) 0, 0); entry->u.host.mode = ImportModeMap(opt); *redir_qend = entry; redir_qend = &entry->next; break; case 'i': /* import IMC handle */ entry = malloc(sizeof *entry); if (NULL == entry) { fprintf(stderr, "No memory for redirection queue\n"); exit(1); } entry->next = NULL; entry->nacl_desc = strtol(optarg, &rest, 0); entry->tag = IMC_DESC; entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0); *redir_qend = entry; redir_qend = &entry->next; break; case 'l': log_file = optarg; break; case 'Q': fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - " "Native Client's sandbox will be unreliable!\n"); skip_qualification = 1; break; case 'R': rpc_supplies_nexe = 1; break; /* case 'r': with 'h' and 'w' above */ case 's': nap->validator_stub_out_mode = 1; break; case 'S': handle_signals = 1; break; case 'v': ++verbosity; NaClLogIncrVerbosity(); break; /* case 'w': with 'h' and 'r' above */ case 'X': export_addr_to = strtol(optarg, (char **) 0, 0); break; #if NACL_LINUX case 'z': NaClHandleReservedAtZero(optarg); break; #endif case 'Z': NaClLog(LOG_WARNING, "Enabling Fixed-Feature CPU Mode\n"); nap->fixed_feature_cpu_mode = 1; if (!nap->validator->FixCPUFeatures(nap->cpu_features)) { NaClLog(LOG_ERROR, "This CPU lacks features required by " "fixed-function CPU mode.\n"); exit(1); } break; default: fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt); PrintUsage(); exit(-1); } } if (debug_mode_ignore_validator == 1) fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n"); else if (debug_mode_ignore_validator > 1) fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n"); if (verbosity) { int ix; char const *separator = ""; fprintf(stderr, "sel_ldr argument list:\n"); for (ix = 0; ix < argc; ++ix) { fprintf(stderr, "%s%s", separator, argv[ix]); separator = " "; } putc('\n', stderr); } if (debug_mode_bypass_acl_checks) { NaClInsecurelyBypassAllAclChecks(); } /* * change stdout/stderr to log file now, so that subsequent error * messages will go there. unfortunately, error messages that * result from getopt processing -- usually out-of-memory, which * shouldn't happen -- won't show up. */ if (NULL != log_file) { NaClLogSetFile(log_file); } if (rpc_supplies_nexe) { if (NULL != nacl_file) { fprintf(stderr, "sel_ldr: mutually exclusive flags -f and -R both used\n"); exit(1); } /* post: NULL == nacl_file */ if (export_addr_to < 0) { fprintf(stderr, "sel_ldr: -R requires -X to set up secure command channel\n"); exit(1); } } else { if (NULL == nacl_file && optind < argc) { nacl_file = argv[optind]; ++optind; } if (NULL == nacl_file) { fprintf(stderr, "No nacl file specified\n"); exit(1); } /* post: NULL != nacl_file */ } /* * post condition established by the above code (in Hoare logic * terminology): * * NULL == nacl_file iff rpc_supplies_nexe * * so hence forth, testing !rpc_supplies_nexe suffices for * establishing NULL != nacl_file. */ CHECK((NULL == nacl_file) == rpc_supplies_nexe); /* to be passed to NaClMain, eventually... */ argv[--optind] = (char *) "NaClMain"; state.ignore_validator_result = (debug_mode_ignore_validator > 0); state.skip_validator = (debug_mode_ignore_validator > 1); if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) { state.enable_exception_handling = 1; } if (state.enable_exception_handling || enable_debug_stub) { #if NACL_WINDOWS state.attach_debug_exception_handler_func = NaClDebugExceptionHandlerStandaloneAttach; #elif NACL_LINUX /* NaCl's signal handler is always enabled on Linux. */ #elif NACL_OSX if (!NaClInterceptMachExceptions()) { fprintf(stderr, "ERROR setting up Mach exception interception.\n"); return -1; } #else # error Unknown host OS #endif } if (NACL_LINUX) { handle_signals = 1; } errcode = LOAD_OK; /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure the platform qualification checks pass. * * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck * (see src/third_party/valgrind/). */ if (!skip_qualification && getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) { fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - " "Native Client's sandbox will be unreliable!\n"); skip_qualification = 1; } if (!skip_qualification) { NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode, NaClRunSelQualificationTests()); if (LOAD_OK != pq_error) { errcode = pq_error; nap->module_load_status = pq_error; fprintf(stderr, "Error while loading \"%s\": %s\n", NULL != nacl_file ? nacl_file : "(no file, to-be-supplied-via-RPC)", NaClErrorString(errcode)); } } if (handle_signals) { NaClSignalHandlerInit(); } else { /* * Patch the Windows exception dispatcher to be safe in the case * of faults inside x86-64 sandboxed code. The sandbox is not * secure on 64-bit Windows without this. */ #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \ NACL_BUILD_SUBARCH == 64) NaClPatchWindowsExceptionDispatcher(); #endif } NaClSignalTestCrashOnStartup(); /* * Open both files first because (on Mac OS X at least) * NaClAppLoadFile() enables an outer sandbox. */ if (NULL != blob_library_file) { NaClFileNameForValgrind(blob_library_file); if (0 == GioMemoryFileSnapshotCtor(&blob_file, blob_library_file)) { perror("sel_main"); fprintf(stderr, "Cannot open \"%s\".\n", blob_library_file); exit(1); } NaClPerfCounterMark(&time_all_main, "SnapshotBlob"); NaClPerfCounterIntervalLast(&time_all_main); } NaClAppInitialDescriptorHookup(nap); if (!rpc_supplies_nexe) { struct GioMemoryFileSnapshot main_file; NaClFileNameForValgrind(nacl_file); if (0 == GioMemoryFileSnapshotCtor(&main_file, nacl_file)) { perror("sel_main"); fprintf(stderr, "Cannot open \"%s\".\n", nacl_file); exit(1); } NaClPerfCounterMark(&time_all_main, "SnapshotNaclFile"); NaClPerfCounterIntervalLast(&time_all_main); if (LOAD_OK == errcode) { NaClLog(2, "Loading nacl file %s (non-RPC)\n", nacl_file); errcode = NaClAppLoadFile((struct Gio *) &main_file, nap); if (LOAD_OK != errcode) { fprintf(stderr, "Error while loading \"%s\": %s\n", nacl_file, NaClErrorString(errcode)); fprintf(stderr, ("Using the wrong type of nexe (nacl-x86-32" " on an x86-64 or vice versa)\n" "or a corrupt nexe file may be" " responsible for this error.\n")); } NaClPerfCounterMark(&time_all_main, "AppLoadEnd"); NaClPerfCounterIntervalLast(&time_all_main); NaClXMutexLock(&nap->mu); nap->module_load_status = errcode; NaClXCondVarBroadcast(&nap->cv); NaClXMutexUnlock(&nap->mu); } if (-1 == (*((struct Gio *) &main_file)->vtbl->Close)((struct Gio *) &main_file)) { fprintf(stderr, "Error while closing \"%s\".\n", nacl_file); } (*((struct Gio *) &main_file)->vtbl->Dtor)((struct Gio *) &main_file); if (fuzzing_quit_after_load) { exit(0); } } /* * Execute additional I/O redirections. NB: since the NaClApp * takes ownership of host / IMC socket descriptors, all but * the first run will not get access if the NaClApp closes * them. Currently a normal NaClApp process exit does not * close descriptors, since the underlying host OS will do so * as part of service runtime exit. */ NaClLog(4, "Processing I/O redirection/inheritance from command line\n"); for (entry = redir_queue; NULL != entry; entry = entry->next) { switch (entry->tag) { case HOST_DESC: NaClAddHostDescriptor(nap, entry->u.host.d, entry->u.host.mode, entry->nacl_desc); break; case IMC_DESC: NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc); break; } } /* * If export_addr_to is set to a non-negative integer, we create a * bound socket and socket address pair and bind the former to * descriptor NACL_SERVICE_PORT_DESCRIPTOR (3 [see sel_ldr.h]) and * the latter to descriptor NACL_SERVICE_ADDRESS_DESCRIPTOR (4). * The socket address is sent to the export_addr_to descriptor. * * The service runtime also accepts a connection on the bound socket * and spawns a secure command channel thread to service it. */ if (0 <= export_addr_to) { NaClCreateServiceSocket(nap); /* * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will * not be reported via the crash log mechanism (for Chromium * embedding of NaCl, shown in the JavaScript console). * * Some errors, such as due to NaClRunSelQualificationTests, do not * trigger a LOG_FATAL but instead set module_load_status to be sent * in the start_module RPC reply. Log messages associated with such * errors would be seen, since NaClSetUpBootstrapChannel will get * called. */ NaClSetUpBootstrapChannel(nap, (NaClHandle) export_addr_to); /* * NB: spawns a thread that uses the command channel. we do * this after NaClAppLoadFile so that NaClApp object is more * fully populated. Hereafter any changes to nap should be done * while holding locks. */ NaClSecureCommandChannel(nap); } /* * May have created a thread, so need to synchronize uses of nap * contents henceforth. */ if (rpc_supplies_nexe) { errcode = NaClWaitForLoadModuleStatus(nap); NaClPerfCounterMark(&time_all_main, "WaitForLoad"); NaClPerfCounterIntervalLast(&time_all_main); } else { /************************************************************************** * TODO(bsy): This else block should be made unconditional and * invoked after the LoadModule RPC completes, eliminating the * essentially dulicated code in latter part of NaClLoadModuleRpc. * This cannot be done until we have full saucer separation * technology, since Chrome currently uses sel_main_chrome.c and * relies on the functionality of the duplicated code. *************************************************************************/ if (LOAD_OK == errcode) { if (verbosity) { gprintf((struct Gio *) &gout, "printing NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); } /* * Finish setting up the NaCl App. On x86-32, this means * allocating segment selectors. On x86-64 and ARM, this is * (currently) a no-op. */ errcode = NaClAppPrepareToLaunch(nap); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "NaClAppPrepareToLaunch returned %d", errcode); } NaClPerfCounterMark(&time_all_main, "AppPrepLaunch"); NaClPerfCounterIntervalLast(&time_all_main); } /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(&state); } /* * Tell the debug stub to bind a TCP port before enabling the outer * sandbox. This is only needed on Mac OS X since that is the only * platform where we have an outer sandbox in standalone sel_ldr. * In principle this call should work on all platforms, but Windows * XP seems to have some problems when we do bind()/listen() on a * separate thread from accept(). */ if (enable_debug_stub && NACL_OSX) { if (!NaClDebugBindSocket()) { exit(1); } } /* * Enable the outer sandbox, if one is defined. Do this as soon as * possible. * * This must come after NaClWaitForLoadModuleStatus(), which waits * for another thread to have called NaClAppLoadFile(). * NaClAppLoadFile() does not work inside the Mac outer sandbox in * standalone sel_ldr when using a dynamic code area because it uses * NaClCreateMemoryObject() which opens a file in /tmp. * * We cannot enable the sandbox if file access is enabled. */ if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) { g_enable_outer_sandbox_func(); } if (NULL != blob_library_file) { if (LOAD_OK == errcode) { NaClLog(2, "Loading blob file %s\n", blob_library_file); errcode = NaClAppLoadFileDynamically(nap, (struct Gio *) &blob_file); if (LOAD_OK != errcode) { fprintf(stderr, "Error while loading \"%s\": %s\n", blob_library_file, NaClErrorString(errcode)); } NaClPerfCounterMark(&time_all_main, "BlobLoaded"); NaClPerfCounterIntervalLast(&time_all_main); } if (-1 == (*((struct Gio *) &blob_file)->vtbl->Close)((struct Gio *) &blob_file)) { fprintf(stderr, "Error while closing \"%s\".\n", blob_library_file); } (*((struct Gio *) &blob_file)->vtbl->Dtor)((struct Gio *) &blob_file); if (verbosity) { gprintf((struct Gio *) &gout, "printing post-IRT NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); } } /* * Print out a marker for scripts to use to mark the start of app * output. */ NaClLog(1, "NACL: Application output follows\n"); /* * Make sure all the file buffers are flushed before entering * the application code. */ fflush((FILE *) NULL); if (NULL != nap->secure_service) { NaClErrorCode start_result; /* * wait for start_module RPC call on secure channel thread. */ start_result = NaClWaitForStartModuleCommand(nap); NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand"); NaClPerfCounterIntervalLast(&time_all_main); if (LOAD_OK == errcode) { errcode = start_result; } } /* * error reporting done; can quit now if there was an error earlier. */ if (LOAD_OK != errcode) { NaClLog(4, "Not running app code since errcode is %s (%d)\n", NaClErrorString(errcode), errcode); goto done; } if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) { NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n"); } NaClEnvCleanserCtor(&env_cleanser, 0); if (!NaClEnvCleanserInit(&env_cleanser, envp, (char const *const *)env_vars.ptr_array)) { NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n"); } if (!NaClAppLaunchServiceThreads(nap)) { fprintf(stderr, "Launch service threads failed\n"); goto done; } if (enable_debug_stub) { if (!NaClDebugInit(nap)) { goto done; } } NACL_TEST_INJECTION(BeforeMainThreadLaunches, ()); if (!NaClCreateMainThread(nap, argc - optind, argv + optind, NaClEnvCleanserEnvironment(&env_cleanser))) { fprintf(stderr, "creating main thread failed\n"); goto done; } NaClEnvCleanserDtor(&env_cleanser); NaClPerfCounterMark(&time_all_main, "CreateMainThread"); NaClPerfCounterIntervalLast(&time_all_main); DynArrayDtor(&env_vars); ret_code = NaClWaitForMainThreadToExit(nap); NaClPerfCounterMark(&time_all_main, "WaitForMainThread"); NaClPerfCounterIntervalLast(&time_all_main); NaClPerfCounterMark(&time_all_main, "SelMainEnd"); NaClPerfCounterIntervalTotal(&time_all_main); /* * exit_group or equiv kills any still running threads while module * addr space is still valid. otherwise we'd have to kill threads * before we clean up the address space. */ NaClExit(ret_code); done: fflush(stdout); if (verbosity) { gprintf((struct Gio *) &gout, "exiting -- printing NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); printf("Dumping vmmap.\n"); fflush(stdout); PrintVmmap(nap); fflush(stdout); } /* * If there is a secure command channel, we sent an RPC reply with * the reason that the nexe was rejected. If we exit now, that * reply may still be in-flight and the various channel closure (esp * reverse channel) may be detected first. This would result in a * crash being reported, rather than the error in the RPC reply. * Instead, we wait for the hard-shutdown on the command channel. */ if (LOAD_OK != errcode) { NaClBlockIfCommandChannelExists(nap); } if (verbosity > 0) { printf("Done.\n"); } fflush(stdout); if (handle_signals) NaClSignalHandlerFini(); NaClAllModulesFini(); NaClExit(ret_code); /* Unreachable, but having the return prevents a compiler error. */ return ret_code; }
/******************************************************************************* * Fork a process after a specified delay, and either wait on it to exit or * leave it to run in the background. * * Returns -2 on spawn() failure, -1 on other failure, and depending on wait: * wait: true - exit status of forked program * wait: false - pid of background process *******************************************************************************/ int fork_program(const char * argv0, char * const argv[], Boolean wait) { int result; int spawn_result; pid_t child_pid; int child_status; int normal_iopolicy = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS); char ** environ = *(_NSGetEnviron()); if (!wait) { setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); } spawn_result = posix_spawn(&child_pid, argv0, /* file_actions */ NULL, /* spawnattrs */ NULL, argv, environ); // If we couldn't spawn the process, return -2 with errno for detail if (spawn_result != 0) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel, "posix_spawn failed for %s.", argv0); errno = spawn_result; result = -2; goto finish; } OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel, "started child process %s[%d] (%ssynchronous).", argv0, child_pid, wait ? "" : "a"); if (wait) { OSKextLogSpec logSpec = kOSKextLogDetailLevel; if (waitpid(child_pid, &child_status, 0) == -1) { result = -1; goto finish; } if (WIFEXITED(child_status)) { result = WEXITSTATUS(child_status); if (result) { logSpec = kOSKextLogErrorLevel; } OSKextLog(/* kext */ NULL, logSpec, "Child process %s[%d] exited with status %d.", argv0, child_pid, result); } else if (WIFSIGNALED(child_status)) { result = WTERMSIG(child_status); logSpec = kOSKextLogErrorLevel; OSKextLog(/* kext */ NULL, logSpec, "Child process %s[%d] exited due to signal %d.", argv0, child_pid, result); } else { // shouldn't be any other types of exit result = -1; } } else { result = child_pid; } finish: setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, normal_iopolicy); return result; }
static PRProcess * ForkAndExec( const char *path, char *const *argv, char *const *envp, const PRProcessAttr *attr) { PRProcess *process; int nEnv, idx; char *const *childEnvp; char **newEnvp = NULL; int flags; #ifdef VMS char VMScurdir[FILENAME_MAX+1] = { '\0' } ; #endif process = PR_NEW(PRProcess); if (!process) { PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } childEnvp = envp; if (attr && attr->fdInheritBuffer) { PRBool found = PR_FALSE; if (NULL == childEnvp) { #ifdef DARWIN childEnvp = *(_NSGetEnviron()); #else childEnvp = environ; #endif } for (nEnv = 0; childEnvp[nEnv]; nEnv++) { } newEnvp = (char **) PR_MALLOC((nEnv + 2) * sizeof(char *)); if (NULL == newEnvp) { PR_DELETE(process); PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); return NULL; } for (idx = 0; idx < nEnv; idx++) { newEnvp[idx] = childEnvp[idx]; if (!found && !strncmp(newEnvp[idx], "NSPR_INHERIT_FDS=", 17)) { newEnvp[idx] = attr->fdInheritBuffer; found = PR_TRUE; } } if (!found) { newEnvp[idx++] = attr->fdInheritBuffer; } newEnvp[idx] = NULL; childEnvp = newEnvp; } #ifdef VMS /* ** Since vfork/exec is implemented VERY differently on OpenVMS, we have to ** handle the setting up of the standard streams very differently. And since ** none of this code can ever execute in the context of the child, we have ** to perform the chdir in the parent so the child is born into the correct ** directory (and then switch the parent back again). */ { int decc$set_child_standard_streams(int,int,int); int n, fd_stdin=0, fd_stdout=1, fd_stderr=2; /* Set up any standard streams we are given, assuming defaults */ if (attr) { if (attr->stdinFd) fd_stdin = attr->stdinFd->secret->md.osfd; if (attr->stdoutFd) fd_stdout = attr->stdoutFd->secret->md.osfd; if (attr->stderrFd) fd_stderr = attr->stderrFd->secret->md.osfd; } /* ** Put a lock around anything that isn't going to be thread-safe. */ PR_Lock(_pr_vms_fork_lock); /* ** Prepare the child's streams. We always do this in case a previous fork ** has left the stream assignments in some non-standard way. */ n = decc$set_child_standard_streams(fd_stdin,fd_stdout,fd_stderr); if (n == -1) { PR_SetError(PR_BAD_DESCRIPTOR_ERROR, errno); PR_DELETE(process); if (newEnvp) { PR_DELETE(newEnvp); } PR_Unlock(_pr_vms_fork_lock); return NULL; } /* Switch directory if we have to */ if (attr) { if (attr->currentDirectory) { if ( (getcwd(VMScurdir,sizeof(VMScurdir)) == NULL) || (chdir(attr->currentDirectory) < 0) ) { PR_SetError(PR_DIRECTORY_OPEN_ERROR, errno); PR_DELETE(process); if (newEnvp) { PR_DELETE(newEnvp); } PR_Unlock(_pr_vms_fork_lock); return NULL; } } } } #endif /* VMS */ #ifdef AIX process->md.pid = (*pr_wp.forkptr)(); #elif defined(NTO) || defined(SYMBIAN) /* * fork() & exec() does not work in a multithreaded process. * Use spawn() instead. */ { int fd_map[3] = { 0, 1, 2 }; if (attr) { if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) { fd_map[0] = dup(attr->stdinFd->secret->md.osfd); flags = fcntl(fd_map[0], F_GETFL, 0); if (flags & O_NONBLOCK) fcntl(fd_map[0], F_SETFL, flags & ~O_NONBLOCK); } if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) { fd_map[1] = dup(attr->stdoutFd->secret->md.osfd); flags = fcntl(fd_map[1], F_GETFL, 0); if (flags & O_NONBLOCK) fcntl(fd_map[1], F_SETFL, flags & ~O_NONBLOCK); } if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) { fd_map[2] = dup(attr->stderrFd->secret->md.osfd); flags = fcntl(fd_map[2], F_GETFL, 0); if (flags & O_NONBLOCK) fcntl(fd_map[2], F_SETFL, flags & ~O_NONBLOCK); } PR_ASSERT(attr->currentDirectory == NULL); /* not implemented */ } #ifdef SYMBIAN /* In Symbian OS, we use posix_spawn instead of fork() and exec() */ posix_spawn(&(process->md.pid), path, NULL, NULL, argv, childEnvp); #else process->md.pid = spawn(path, 3, fd_map, NULL, argv, childEnvp); #endif if (fd_map[0] != 0) close(fd_map[0]); if (fd_map[1] != 1) close(fd_map[1]); if (fd_map[2] != 2) close(fd_map[2]); } #else process->md.pid = fork(); #endif if ((pid_t) -1 == process->md.pid) { PR_SetError(PR_INSUFFICIENT_RESOURCES_ERROR, errno); PR_DELETE(process); if (newEnvp) { PR_DELETE(newEnvp); } return NULL; } else if (0 == process->md.pid) { /* the child process */ /* * If the child process needs to exit, it must call _exit(). * Do not call exit(), because exit() will flush and close * the standard I/O file descriptors, and hence corrupt * the parent process's standard I/O data structures. */ #if !defined(NTO) && !defined(SYMBIAN) #ifdef VMS /* OpenVMS has already handled all this above */ #else if (attr) { /* the osfd's to redirect stdin, stdout, and stderr to */ int in_osfd = -1, out_osfd = -1, err_osfd = -1; if (attr->stdinFd && attr->stdinFd->secret->md.osfd != 0) { in_osfd = attr->stdinFd->secret->md.osfd; if (dup2(in_osfd, 0) != 0) { _exit(1); /* failed */ } flags = fcntl(0, F_GETFL, 0); if (flags & O_NONBLOCK) { fcntl(0, F_SETFL, flags & ~O_NONBLOCK); } } if (attr->stdoutFd && attr->stdoutFd->secret->md.osfd != 1) { out_osfd = attr->stdoutFd->secret->md.osfd; if (dup2(out_osfd, 1) != 1) { _exit(1); /* failed */ } flags = fcntl(1, F_GETFL, 0); if (flags & O_NONBLOCK) { fcntl(1, F_SETFL, flags & ~O_NONBLOCK); } } if (attr->stderrFd && attr->stderrFd->secret->md.osfd != 2) { err_osfd = attr->stderrFd->secret->md.osfd; if (dup2(err_osfd, 2) != 2) { _exit(1); /* failed */ } flags = fcntl(2, F_GETFL, 0); if (flags & O_NONBLOCK) { fcntl(2, F_SETFL, flags & ~O_NONBLOCK); } } if (in_osfd != -1) { close(in_osfd); } if (out_osfd != -1 && out_osfd != in_osfd) { close(out_osfd); } if (err_osfd != -1 && err_osfd != in_osfd && err_osfd != out_osfd) { close(err_osfd); } if (attr->currentDirectory) { if (chdir(attr->currentDirectory) < 0) { _exit(1); /* failed */ } } } #endif /* !VMS */ if (childEnvp) { (void)execve(path, argv, childEnvp); } else { /* Inherit the environment of the parent. */ (void)execv(path, argv); } /* Whoops! It returned. That's a bad sign. */ #ifdef VMS /* ** On OpenVMS we are still in the context of the parent, and so we ** can (and should!) perform normal error handling. */ PR_SetError(PR_UNKNOWN_ERROR, errno); PR_DELETE(process); if (newEnvp) { PR_DELETE(newEnvp); } if (VMScurdir[0] != '\0') chdir(VMScurdir); PR_Unlock(_pr_vms_fork_lock); return NULL; #else _exit(1); #endif /* VMS */ #endif /* !NTO */ } if (newEnvp) { PR_DELETE(newEnvp); } #ifdef VMS /* If we switched directories, then remember to switch back */ if (VMScurdir[0] != '\0') { chdir(VMScurdir); /* can't do much if it fails */ } PR_Unlock(_pr_vms_fork_lock); #endif /* VMS */ #if defined(_PR_NATIVE_THREADS) PR_Lock(pr_wp.ml); if (0 == pr_wp.numProcs++) { PR_NotifyCondVar(pr_wp.cv); } PR_Unlock(pr_wp.ml); #endif return process; }
void Options::initialize() { static std::once_flag initializeOptionsOnceFlag; std::call_once( initializeOptionsOnceFlag, [] { // Initialize each of the options with their default values: #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \ name_() = defaultValue_; \ name_##Default() = defaultValue_; JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION overrideDefaults(); // Allow environment vars to override options if applicable. // The evn var should be the name of the option prefixed with // "JSC_". #if PLATFORM(COCOA) bool hasBadOptions = false; for (char** envp = *_NSGetEnviron(); *envp; envp++) { const char* env = *envp; if (!strncmp("JSC_", env, 4)) { if (!Options::setOption(&env[4])) { dataLog("ERROR: invalid option: ", *envp, "\n"); hasBadOptions = true; } } } if (hasBadOptions && Options::validateOptions()) CRASH(); #else // PLATFORM(COCOA) #define FOR_EACH_OPTION(type_, name_, defaultValue_, availability_, description_) \ overrideOptionWithHeuristic(name_(), name_##ID, "JSC_" #name_, Availability::availability_); JSC_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION #endif // PLATFORM(COCOA) #define FOR_EACH_OPTION(aliasedName_, unaliasedName_, equivalence_) \ overrideAliasedOptionWithHeuristic("JSC_" #aliasedName_); JSC_ALIASED_OPTIONS(FOR_EACH_OPTION) #undef FOR_EACH_OPTION #if 0 ; // Deconfuse editors that do auto indentation #endif #if USE(OPTIONS_FILE) { const char* filename = OPTIONS_FILENAME; FILE* optionsFile = fopen(filename, "r"); if (!optionsFile) { dataLogF("Failed to open file %s. Did you add the file-read-data entitlement to WebProcess.sb?\n", filename); return; } StringBuilder builder; char* line; char buffer[BUFSIZ]; while ((line = fgets(buffer, sizeof(buffer), optionsFile))) builder.append(buffer); const char* optionsStr = builder.toString().utf8().data(); dataLogF("Setting options: %s\n", optionsStr); setOptions(optionsStr); int result = fclose(optionsFile); if (result) dataLogF("Failed to close file %s: %s\n", filename, strerror(errno)); } #endif recomputeDependentOptions(); // Do range checks where needed and make corrections to the options: ASSERT(Options::thresholdForOptimizeAfterLongWarmUp() >= Options::thresholdForOptimizeAfterWarmUp()); ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= Options::thresholdForOptimizeSoon()); ASSERT(Options::thresholdForOptimizeAfterWarmUp() >= 0); dumpOptionsIfNeeded(); ensureOptionsAreCoherent(); }); }
#include <vle/utils/Spawn.hpp> #include <vle/utils/i18n.hpp> #include <sys/wait.h> #include <unistd.h> #include <cerrno> #include <cassert> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <iostream> #ifdef __APPLE__ #include <crt_externs.h> extern "C" char ** environ = *_NSGetEnviron(); #endif namespace vle { namespace utils { const unsigned long int Spawn::default_buffer_size = BUFSIZ; struct strdup_functor : std::unary_function < std::string, char* > { char * operator()(const std::string& str) const { return strdup(str.c_str()); } };