int fx_muxer_t::parse_args_and_execute(const pal::string_t& own_dir, int argoff, int argc, const pal::char_t* argv[], bool exec_mode, bool* is_an_app) { *is_an_app = true; std::vector<pal::string_t> known_opts = { _X("--additionalprobingpath") }; if (exec_mode) { known_opts.push_back(_X("--depsfile")); } // Parse the known muxer arguments if any. int num_parsed = 0; std::unordered_map<pal::string_t, std::vector<pal::string_t>> opts; if (!parse_known_args(argc - argoff, &argv[argoff], known_opts, &opts, &num_parsed)) { trace::error(_X("Failed to parse supported arguments.")); return InvalidArgFailure; } int cur_i = argoff + num_parsed; if (cur_i >= argc) { return muxer_usage(); } pal::string_t app_candidate = argv[cur_i]; bool is_app_runnable = ends_with(app_candidate, _X(".dll"), false) || ends_with(app_candidate, _X(".exe"), false); // If exec mode is on, then check we have a dll at this point if (exec_mode) { if (!is_app_runnable) { trace::error(_X("dotnet exec needs a dll to execute. Try dotnet [--help]")); return InvalidArgFailure; } } // For non-exec, there is CLI invocation or app.dll execution after known args. else { // Test if we have a real dll at this point. if (!is_app_runnable) { // No we don't have a dll, this must be routed to the CLI. *is_an_app = false; return Success; } } // Transform dotnet [exec] [--additionalprobingpath path] [--depsfile file] dll [args] -> dotnet dll [args] std::vector<const pal::char_t*> vec_argv; const pal::char_t** new_argv = argv; int new_argc = argc; if (cur_i != 1) { vec_argv.resize(argc - cur_i + 1, 0); // +1 for dotnet memcpy(vec_argv.data() + 1, argv + cur_i, (argc - cur_i) * sizeof(pal::char_t*)); vec_argv[0] = argv[0]; new_argv = vec_argv.data(); new_argc = vec_argv.size(); } pal::string_t opts_deps_file = _X("--depsfile"); pal::string_t opts_probe_path = _X("--additionalprobingpath"); pal::string_t deps_file = get_last_known_arg(opts, opts_deps_file, _X("")); std::vector<pal::string_t> probe_paths = opts.count(opts_probe_path) ? opts[opts_probe_path] : std::vector<pal::string_t>(); trace::verbose(_X("Current argv is %s"), app_candidate.c_str()); pal::string_t app_or_deps = deps_file.empty() ? app_candidate : deps_file; pal::string_t no_json = app_candidate; pal::string_t dev_config_file; auto config_file = get_runtime_config_from_file(no_json, &dev_config_file); runtime_config_t config(config_file, dev_config_file); for (const auto& path : config.get_probe_paths()) { probe_paths.push_back(path); } if (!config.is_valid()) { trace::error(_X("Invalid runtimeconfig.json [%s] [%s]"), config.get_path().c_str(), config.get_dev_path().c_str()); return StatusCode::InvalidConfigFile; } if (!deps_file.empty() && !pal::file_exists(deps_file)) { trace::error(_X("Deps file [%s] specified but doesn't exist"), deps_file.c_str()); return StatusCode::InvalidArgFailure; } if (config.get_portable()) { trace::verbose(_X("Executing as a portable app as per config file [%s]"), config_file.c_str()); pal::string_t fx_dir = resolve_fx_dir(own_dir, &config); corehost_init_t init(deps_file, probe_paths, fx_dir, host_mode_t::muxer, &config); return execute_app(fx_dir, &init, new_argc, new_argv); } else { trace::verbose(_X("Executing as a standalone app as per config file [%s]"), config_file.c_str()); pal::string_t impl_dir = get_directory(app_or_deps); if (!library_exists_in_dir(impl_dir, LIBHOSTPOLICY_NAME, nullptr) && !probe_paths.empty() && !deps_file.empty()) { bool found = false; pal::string_t candidate = impl_dir; deps_json_t deps_json(false, deps_file); for (const auto& probe_path : probe_paths) { trace::verbose(_X("Considering %s for hostpolicy library"), probe_path.c_str()); if (deps_json.is_valid() && deps_json.has_hostpolicy_entry() && deps_json.get_hostpolicy_entry().to_full_path(probe_path, &candidate)) { found = true; // candidate contains the right path. break; } } if (!found) { trace::error(_X("Policy library either not found in deps [%s] or not found in %d probe paths."), deps_file.c_str(), probe_paths.size()); return StatusCode::CoreHostLibMissingFailure; } impl_dir = get_directory(candidate); } corehost_init_t init(deps_file, probe_paths, _X(""), host_mode_t::muxer, &config); return execute_app(impl_dir, &init, new_argc, new_argv); } }
int fx_muxer_t::read_config_and_execute( const pal::string_t& own_dir, const pal::string_t& app_candidate, const std::unordered_map<pal::string_t, std::vector<pal::string_t>>& opts, int new_argc, const pal::char_t** new_argv, host_mode_t mode) { pal::string_t opts_fx_version = _X("--fx-version"); pal::string_t opts_deps_file = _X("--depsfile"); pal::string_t opts_probe_path = _X("--additionalprobingpath"); pal::string_t opts_runtime_config = _X("--runtimeconfig"); pal::string_t fx_version = get_last_known_arg(opts, opts_fx_version, _X("")); pal::string_t deps_file = get_last_known_arg(opts, opts_deps_file, _X("")); pal::string_t runtime_config = get_last_known_arg(opts, opts_runtime_config, _X("")); std::vector<pal::string_t> spec_probe_paths = opts.count(opts_probe_path) ? opts.find(opts_probe_path)->second : std::vector<pal::string_t>(); if (!deps_file.empty() && (!pal::realpath(&deps_file) || !pal::file_exists(deps_file))) { trace::error(_X("The specified deps.json [%s] does not exist"), deps_file.c_str()); return StatusCode::InvalidArgFailure; } if (!runtime_config.empty() && (!pal::realpath(&runtime_config) || !pal::file_exists(runtime_config))) { trace::error(_X("The specified runtimeconfig.json [%s] does not exist"), runtime_config.c_str()); return StatusCode::InvalidConfigFile; } pal::string_t config_file, dev_config_file; if (runtime_config.empty()) { trace::verbose(_X("App runtimeconfig.json from [%s]"), app_candidate.c_str()); get_runtime_config_paths_from_app(app_candidate, &config_file, &dev_config_file); } else { trace::verbose(_X("Specified runtimeconfig.json from [%s]"), runtime_config.c_str()); get_runtime_config_paths_from_arg(runtime_config, &config_file, &dev_config_file); } runtime_config_t config(config_file, dev_config_file); if (!config.is_valid()) { trace::error(_X("Invalid runtimeconfig.json [%s] [%s]"), config.get_path().c_str(), config.get_dev_path().c_str()); return StatusCode::InvalidConfigFile; } // Append specified probe paths first and then config file probe paths into realpaths. std::vector<pal::string_t> probe_realpaths; for (const auto& path : spec_probe_paths) { append_realpath(path, &probe_realpaths); } for (const auto& path : config.get_probe_paths()) { append_realpath(path, &probe_realpaths); } bool is_portable = config.get_portable(); pal::string_t fx_dir = is_portable ? resolve_fx_dir(mode, own_dir, config, fx_version) : _X(""); trace::verbose(_X("Executing as a %s app as per config file [%s]"), (is_portable ? _X("portable") : _X("standalone")), config_file.c_str()); pal::string_t impl_dir; if (!resolve_hostpolicy_dir(mode, own_dir, fx_dir, app_candidate, deps_file, fx_version, probe_realpaths, config, &impl_dir)) { return CoreHostLibMissingFailure; } corehost_init_t init(deps_file, probe_realpaths, fx_dir, mode, config); return execute_app(impl_dir, &init, new_argc, new_argv); }