/* Python interpreter main program */ #include "Python.h" #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_fileutils.h" // struct _Py_stat_struct #include "pycore_import.h" // _PyImport_Fini2() #include "pycore_initconfig.h" // _PyArgv #include "pycore_interp.h" // _PyInterpreterState.sysdict #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() #include "pycore_pylifecycle.h" // _Py_PreInitializeFromPyArgv() #include "pycore_pystate.h" // _PyInterpreterState_GET() #include "pycore_pythonrun.h" // _PyRun_AnyFile() #include "pycore_sysmodule.h" // _PySys_FormatV() #include "pycore_tuple.h" // _PyTuple_FromPair #include "pycore_unicodeobject.h" // _PyUnicode_Dedent() /* Includes for exit_sigint() */ #include // perror() #ifdef HAVE_SIGNAL_H # include // SIGINT #endif #if defined(HAVE_GETPID) && defined(HAVE_UNISTD_H) # include // getpid() #endif #ifdef MS_WINDOWS # include // STATUS_CONTROL_C_EXIT #endif /* End of includes for exit_sigint() */ #define COPYRIGHT \ "Type \"help\", \"copyright\", \"credits\" or \"license\" " \ "for more information." /* --- pymain_init() ---------------------------------------------- */ static PyStatus pymain_init(const _PyArgv *args) { PyStatus status; status = _PyRuntime_Initialize(); if (_PyStatus_EXCEPTION(status)) { return status; } PyPreConfig preconfig; PyPreConfig_InitPythonConfig(&preconfig); status = _Py_PreInitializeFromPyArgv(&preconfig, args); if (_PyStatus_EXCEPTION(status)) { return status; } PyConfig config; PyConfig_InitPythonConfig(&config); /* pass NULL as the config: config is read from command line arguments, environment variables, configuration files */ if (args->use_bytes_argv) { status = PyConfig_SetBytesArgv(&config, args->argc, args->bytes_argv); } else { status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv); } if (_PyStatus_EXCEPTION(status)) { goto done; } status = Py_InitializeFromConfig(&config); if (_PyStatus_EXCEPTION(status)) { goto done; } status = _PyStatus_OK(); done: PyConfig_Clear(&config); return status; } /* --- pymain_run_python() ---------------------------------------- */ static void pymain_error_format(const char *format, ...) { va_list vargs; va_start(vargs, format); PySys_WriteStderr("python: "); _PySys_FormatV(&_Py_ID(stderr), stderr, format, vargs); PySys_WriteStderr("\n"); va_end(vargs); } // See also pyrun_error() static void pymain_error(const char *msg) { PySys_FormatStderr("python: %s\n", msg); } static int pymain_check_signals(void) { return Py_MakePendingCalls(); } /* Non-zero if filename, command (-c) or module (-m) is set on the command line */ static inline int config_run_code(const PyConfig *config) { return (config->run_command != NULL || config->run_filename != NULL || config->run_module != NULL); } /* Return non-zero if stdin is a TTY or if -i command line option is used */ static int stdin_is_interactive(const PyConfig *config) { return (isatty(fileno(stdin)) || config->interactive); } /* Display the current Python exception and return an exitcode */ static int pymain_err_print(int *exitcode_p) { int exitcode; if (_Py_HandleSystemExitAndKeyboardInterrupt(&exitcode)) { *exitcode_p = exitcode; return 1; } PyErr_Print(); return 0; } static int pymain_exit_err_print(void) { int exitcode = 1; pymain_err_print(&exitcode); return exitcode; } // If filename is a package (ex: directory or ZIP file) which contains // __main__.py, main_importer_path is set to filename and will be prepended to // sys.path. // // Otherwise, main_importer_path is left unchanged. // // Write an exitcode into *exitcode and return 1 if we have to exit Python. // Return 0 otherwise. static int pymain_get_importer(const PyConfig *config, PyObject **importer_p, int *exitcode) { const wchar_t *filename = config->run_filename; if (filename == NULL) { return 0; } PyObject *sys_path0 = PyUnicode_FromWideChar(filename, -1); if (sys_path0 == NULL) { goto error; } PyObject *importer = PyImport_GetImporter(sys_path0); if (importer == NULL) { goto error; } if (importer == Py_None) { Py_DECREF(sys_path0); Py_DECREF(importer); return 0; } Py_DECREF(importer); *importer_p = sys_path0; return 0; error: Py_XDECREF(sys_path0); pymain_error("Failed checking if argv[0] is an import path entry:"); return pymain_err_print(exitcode); } static int pymain_sys_path_add_path0(PyObject *path0) { PyObject *sys_path; PyInterpreterState *interp = _PyInterpreterState_GET(); PyObject *sysdict = interp->sysdict; if (sysdict != NULL) { sys_path = PyDict_GetItemWithError(sysdict, &_Py_ID(path)); if (sys_path == NULL && PyErr_Occurred()) { return -1; } } else { sys_path = NULL; } if (sys_path == NULL) { PyErr_SetString(PyExc_RuntimeError, "unable to get sys.path"); return -1; } if (PyList_Insert(sys_path, 0, path0)) { return -1; } return 0; } static void pymain_header(const PyConfig *config) { if (config->quiet) { return; } if (!config->verbose && (config_run_code(config) || !stdin_is_interactive(config))) { return; } fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform()); if (config->site_import) { fprintf(stderr, "%s\n", COPYRIGHT); } } static int pymain_import_readline(const PyConfig *config) { if (pymain_check_signals() < 0) { return -1; } if (config->isolated) { return 0; } if (!config->inspect && config_run_code(config)) { return 0; } if (!isatty(fileno(stdin))) { return 0; } PyObject *mod = PyImport_ImportModule("readline"); if (mod == NULL) { PyErr_Clear(); } else { Py_DECREF(mod); } mod = PyImport_ImportModule("rlcompleter"); if (mod == NULL) { PyErr_Clear(); } else { Py_DECREF(mod); } return 0; } static int pymain_run_command(wchar_t *command) { PyObject *unicode, *bytes; unicode = PyUnicode_FromWideChar(command, -1); if (unicode == NULL) { goto error; } if (PySys_Audit("cpython.run_command", "O", unicode) < 0) { return pymain_exit_err_print(); } Py_SETREF(unicode, _PyUnicode_Dedent(unicode)); if (unicode == NULL) { goto error; } bytes = PyUnicode_AsUTF8String(unicode); Py_DECREF(unicode); if (bytes == NULL) { goto error; } PyCompilerFlags cf = _PyCompilerFlags_INIT; cf.cf_flags |= PyCF_IGNORE_COOKIE; PyObject *result = NULL; PyObject *string_obj = PyUnicode_FromString(""); if (string_obj != NULL) { result = _PyRun_SimpleString(PyBytes_AsString(bytes), string_obj, &cf); Py_DECREF(string_obj); } Py_DECREF(bytes); if (result == NULL) { return pymain_exit_err_print(); } return 0; error: pymain_error("Unable to decode the command from the command line:"); return pymain_exit_err_print(); } static int pymain_run_pyrepl(int pythonstartup) { int exitcode = 0; PyObject *console = NULL; PyObject *empty_tuple = NULL; PyObject *kwargs = NULL; PyObject *console_result = NULL; PyObject *main_module = NULL; PyObject *pyrepl = PyImport_ImportModule("_pyrepl.main"); if (pyrepl == NULL) { pymain_error("Could not import _pyrepl.main"); goto error; } console = PyObject_GetAttrString(pyrepl, "interactive_console"); if (console == NULL) { pymain_error("Could not access _pyrepl.main.interactive_console"); goto error; } empty_tuple = PyTuple_New(0); if (empty_tuple == NULL) { goto error; } kwargs = PyDict_New(); if (kwargs == NULL) { goto error; } main_module = PyImport_AddModuleRef("__main__"); if (main_module == NULL) { goto error; } PyObject *value = pythonstartup ? Py_True : Py_False; if (PyDict_SetItemString(kwargs, "mainmodule", main_module) || PyDict_SetItemString(kwargs, "pythonstartup", value)) { goto error; } console_result = PyObject_Call(console, empty_tuple, kwargs); if (console_result == NULL) { goto error; } done: Py_XDECREF(console_result); Py_XDECREF(kwargs); Py_XDECREF(empty_tuple); Py_XDECREF(console); Py_XDECREF(pyrepl); Py_XDECREF(main_module); return exitcode; error: exitcode = pymain_exit_err_print(); goto done; } static int pymain_run_module(const wchar_t *modname, int set_argv0) { int exitcode = 0; PyObject *module = NULL; PyObject *runmodule = NULL; PyObject *runargs = NULL; PyObject *result = NULL; if (PySys_Audit("cpython.run_module", "u", modname) < 0) { goto error; } runmodule = PyImport_ImportModuleAttrString("runpy", "_run_module_as_main"); if (runmodule == NULL) { pymain_error("Could not import runpy._run_module_as_main"); goto error; } module = PyUnicode_FromWideChar(modname, -1); if (module == NULL) { pymain_error("Could not convert module name to unicode"); goto error; } runargs = _PyTuple_FromPair(module, set_argv0 ? Py_True : Py_False); if (runargs == NULL) { pymain_error("Could not create arguments " "for runpy._run_module_as_main"); goto error; } result = PyObject_Call(runmodule, runargs, NULL); if (result == NULL) { goto error; } done: Py_XDECREF(module); Py_XDECREF(runmodule); Py_XDECREF(runargs); Py_XDECREF(result); return exitcode; error: exitcode = pymain_exit_err_print(); goto done; } static int pymain_run_file_obj(PyObject *filename, int skip_source_first_line) { if (PySys_Audit("cpython.run_file", "O", filename) < 0) { return pymain_exit_err_print(); } FILE *fp = Py_fopen(filename, "rb"); if (fp == NULL) { pymain_error_format("can't open file %R:", filename); pymain_exit_err_print(); return 2; } if (skip_source_first_line) { int ch; /* Push back first newline so line numbers remain the same */ while ((ch = getc(fp)) != EOF) { if (ch == '\n') { (void)ungetc(ch, fp); break; } } } struct _Py_stat_struct sb; if (_Py_fstat_noraise(fileno(fp), &sb) == 0 && S_ISDIR(sb.st_mode)) { pymain_error_format("%R is a directory, cannot continue", filename); fclose(fp); return 1; } if (pymain_check_signals() < 0) { fclose(fp); return pymain_exit_err_print(); } /* _PyRun_AnyFile(closeit=1) calls fclose(fp) before running code */ PyCompilerFlags cf = _PyCompilerFlags_INIT; PyObject *result = _PyRun_AnyFile(fp, filename, 1, &cf); if (result == NULL) { return pymain_exit_err_print(); } Py_DECREF(result); return 0; } static int pymain_run_file(const PyConfig *config) { PyObject *filename = PyUnicode_FromWideChar(config->run_filename, -1); if (filename == NULL) { return pymain_exit_err_print(); } int exitcode = pymain_run_file_obj(filename, config->skip_source_first_line); Py_XDECREF(filename); return exitcode; } static int pymain_run_startup(PyConfig *config, int *exitcode) { int ret = 0; PyObject *startup = NULL; if (!config->use_environment) { goto done; } #ifdef MS_WINDOWS const wchar_t *env = _wgetenv(L"PYTHONSTARTUP"); if (env == NULL || env[0] == L'\0') { goto done; } startup = PyUnicode_FromWideChar(env, -1); if (startup == NULL) { goto error; } #else const char *env = _Py_GetEnv(config->use_environment, "PYTHONSTARTUP"); if (env == NULL) { goto done; } startup = PyUnicode_DecodeFSDefault(env); if (startup == NULL) { goto error; } #endif if (PySys_Audit("cpython.run_startup", "O", startup) < 0) { goto error; } FILE *fp = Py_fopen(startup, "r"); if (fp == NULL) { pymain_error("Could not open PYTHONSTARTUP"); goto error; } PyCompilerFlags cf = _PyCompilerFlags_INIT; PyObject *result = _PyRun_SimpleFile(fp, startup, 0, &cf); fclose(fp); if (result == NULL) { goto error; } Py_DECREF(result); done: Py_XDECREF(startup); return ret; error: ret = pymain_err_print(exitcode); goto done; } /* Write an exitcode into *exitcode and return 1 if we have to exit Python. Return 0 otherwise. */ static int pymain_run_interactive_hook(int *exitcode) { PyObject *hook; if (PySys_GetOptionalAttrString("__interactivehook__", &hook) < 0) { goto error; } if (hook == NULL) { return 0; } if (PySys_Audit("cpython.run_interactivehook", "O", hook) < 0) { Py_DECREF(hook); goto error; } PyObject *result = _PyObject_CallNoArgs(hook); Py_DECREF(hook); if (result == NULL) { goto error; } Py_DECREF(result); return 0; error: pymain_error("Failed calling sys.__interactivehook__:"); return pymain_err_print(exitcode); } static int pymain_set_inspect(PyConfig *config, int inspect, int *exitcode) { PyObject *value = PyLong_FromLong(inspect); if (value == NULL || PyConfig_Set("inspect", value) < 0) { Py_XDECREF(value); pymain_error("Could not set the inspect flag"); return pymain_err_print(exitcode); } else { assert(config->inspect == inspect); } Py_XDECREF(value); return 0; } static int _pymain_run_repl(PyConfig *config, int startup) { if (pymain_check_signals() < 0) { goto error; } if (PySys_Audit("cpython.run_stdin", NULL) < 0) { goto error; } if (isatty(fileno(stdin)) && !_Py_GetEnv(config->use_environment, "PYTHON_BASIC_REPL")) { PyObject *pyrepl = PyImport_ImportModule("_pyrepl"); if (pyrepl != NULL) { int exitcode = pymain_run_pyrepl(startup); Py_DECREF(pyrepl); return exitcode; } if (!PyErr_ExceptionMatches(PyExc_ModuleNotFoundError)) { pymain_error("Could not import _pyrepl.main"); goto error; } PyErr_Clear(); } PyCompilerFlags cf = _PyCompilerFlags_INIT; PyObject *result = NULL; PyObject *stdin_obj = PyUnicode_FromString(""); if (stdin_obj != NULL) { result = _PyRun_AnyFile(stdin, stdin_obj, 0, &cf); Py_DECREF(stdin_obj); } if (result == NULL) { goto error; } Py_DECREF(result); return 0; error: return pymain_exit_err_print(); } static int pymain_run_stdin(PyConfig *config) { if (stdin_is_interactive(config)) { // do exit on SystemExit int exitcode; if (pymain_set_inspect(config, 0, &exitcode)) { return exitcode; } if (pymain_run_startup(config, &exitcode)) { return exitcode; } if (pymain_run_interactive_hook(&exitcode)) { return exitcode; } } return _pymain_run_repl(config, 0); } static void pymain_repl(PyConfig *config, int *exitcode) { /* Check this environment variable at the end, to give programs the opportunity to set it from Python. */ if (!config->inspect && _Py_GetEnv(config->use_environment, "PYTHONINSPECT")) { if (pymain_set_inspect(config, 1, exitcode)) { return; } } if (!(config->inspect && stdin_is_interactive(config) && config_run_code(config))) { return; } if (pymain_set_inspect(config, 0, exitcode)) { return; } if (pymain_run_interactive_hook(exitcode)) { return; } *exitcode = _pymain_run_repl(config, 1); } static int pymain_set_path0(PyObject *main_importer_path) { PyConfig *config = (PyConfig *)_Py_GetConfig(); PyObject *path0 = NULL; if (main_importer_path != NULL) { path0 = Py_NewRef(main_importer_path); } else if (!config->safe_path) { int res = _PyPathConfig_ComputeSysPath0(&config->argv, &path0); if (res < 0) { return -1; } else if (res == 0) { Py_CLEAR(path0); } } if (path0 == NULL) { return 0; } // XXX Apply config->sys_path_0 in init_interp_main(). We have // to be sure to get readline/rlcompleter imported at the correct time. wchar_t *wstr = PyUnicode_AsWideCharString(path0, NULL); if (wstr == NULL) { goto error; } PyStatus status = PyConfig_SetString(config, &config->sys_path_0, wstr); PyMem_Free(wstr); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); goto error; } int res = pymain_sys_path_add_path0(path0); Py_DECREF(path0); return res; error: Py_DECREF(path0); return -1; } static void pymain_run_python(int *exitcode) { int set_running_main = 0; PyObject *main_importer_path = NULL; PyInterpreterState *interp = _PyInterpreterState_GET(); /* pymain_repl() and pymain_run_stdin() modify the config */ PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); /* ensure path config is written into global variables */ PyStatus status = _PyPathConfig_UpdateGlobal(config); if (_PyStatus_EXCEPTION(status)) { _PyErr_SetFromPyStatus(status); goto error; } // XXX Calculate config->sys_path_0 in getpath.py. // The tricky part is that we can't check the path importers yet // at that point. assert(config->sys_path_0 == NULL); if (pymain_get_importer(config, &main_importer_path, exitcode)) { return; } // import readline and rlcompleter before script dir is added to sys.path if (pymain_import_readline(config) < 0) { goto error; } if (pymain_set_path0(main_importer_path) < 0) { goto error; } pymain_header(config); _PyInterpreterState_SetRunningMain(interp); set_running_main = 1; assert(!PyErr_Occurred()); if (pymain_check_signals() < 0) { goto error; } if (config->run_command) { *exitcode = pymain_run_command(config->run_command); } else if (config->run_module) { *exitcode = pymain_run_module(config->run_module, 1); } else if (main_importer_path != NULL) { *exitcode = pymain_run_module(L"__main__", 0); } else if (config->run_filename != NULL) { *exitcode = pymain_run_file(config); } else { *exitcode = pymain_run_stdin(config); } if (pymain_check_signals() < 0) { goto error; } pymain_repl(config, exitcode); goto done; error: *exitcode = pymain_exit_err_print(); done: if (set_running_main) { _PyInterpreterState_SetNotRunningMain(interp); } Py_XDECREF(main_importer_path); } /* --- pymain_main() ---------------------------------------------- */ static void pymain_free(void) { _PyImport_Fini2(); /* Free global variables which cannot be freed in Py_Finalize(): configuration options set before Py_Initialize() which should remain valid after Py_Finalize(), since Py_Initialize()-Py_Finalize() can be called multiple times. */ _PyPathConfig_ClearGlobal(); _Py_ClearArgcArgv(); _PyRuntime_Finalize(); } static int exit_sigint(void) { /* bpo-1054041: We need to exit via the * SIG_DFL handler for SIGINT if KeyboardInterrupt went unhandled. * If we don't, a calling process such as a shell may not know * about the user's ^C. https://www.cons.org/cracauer/sigint.html */ #if defined(HAVE_GETPID) && defined(HAVE_KILL) && !defined(MS_WINDOWS) if (PyOS_setsig(SIGINT, SIG_DFL) == SIG_ERR) { perror("signal"); /* Impossible in normal environments. */ } else { kill(getpid(), SIGINT); } /* If setting SIG_DFL failed, or kill failed to terminate us, * there isn't much else we can do aside from an error code. */ #endif /* HAVE_GETPID && !MS_WINDOWS */ #ifdef MS_WINDOWS /* cmd.exe detects this, prints ^C, and offers to terminate. */ /* https://msdn.microsoft.com/en-us/library/cc704588.aspx */ return STATUS_CONTROL_C_EXIT; #else return SIGINT + 128; #endif /* !MS_WINDOWS */ } static void _Py_NO_RETURN pymain_exit_error(PyStatus status) { if (_PyStatus_IS_EXIT(status)) { /* If it's an error rather than a regular exit, leave Python runtime alive: Py_ExitStatusException() uses the current exception and use sys.stdout in this case. */ pymain_free(); } Py_ExitStatusException(status); } int Py_RunMain(void) { int exitcode = 0; _PyRuntime.signals.unhandled_keyboard_interrupt = 0; pymain_run_python(&exitcode); if (Py_FinalizeEx() < 0) { /* Value unlikely to be confused with a non-error exit status or other special meaning */ exitcode = 120; } pymain_free(); if (_PyRuntime.signals.unhandled_keyboard_interrupt) { exitcode = exit_sigint(); } return exitcode; } static int pymain_main(_PyArgv *args) { PyStatus status = pymain_init(args); if (_PyStatus_IS_EXIT(status)) { pymain_free(); return status.exitcode; } if (_PyStatus_EXCEPTION(status)) { pymain_exit_error(status); } return Py_RunMain(); } int Py_Main(int argc, wchar_t **argv) { _PyArgv args = { .argc = argc, .use_bytes_argv = 0, .bytes_argv = NULL, .wchar_argv = argv}; return pymain_main(&args); } int Py_BytesMain(int argc, char **argv) { _PyArgv args = { .argc = argc, .use_bytes_argv = 1, .bytes_argv = argv, .wchar_argv = NULL}; return pymain_main(&args); }