Ejemplo n.º 1
0
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);
    }
}
Ejemplo n.º 2
0
int fx_muxer_t::parse_args_and_execute(
    const pal::string_t& own_dir,
    const pal::string_t& own_dll,
    int argoff, int argc, const pal::char_t* argv[], bool exec_mode, host_mode_t mode, bool* is_an_app)
{
    *is_an_app = true;

    std::vector<pal::string_t> known_opts = { _X("--additionalprobingpath") };
    if (exec_mode || mode == host_mode_t::split_fx || mode == host_mode_t::standalone)
    {
        known_opts.push_back(_X("--depsfile"));
        known_opts.push_back(_X("--runtimeconfig"));
    }
    if (mode == host_mode_t::muxer)
    {
        known_opts.push_back(_X("--fx-version"));
    }

    // Parse the known 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 options or their values:"));
        for (const auto& arg : known_opts)
        {
            trace::error(_X("  %s"), arg.c_str());
        }
        return InvalidArgFailure;
    }

    const pal::char_t** new_argv = argv;
    int new_argc = argc;
    std::vector<const pal::char_t*> vec_argv;
    pal::string_t app_candidate = own_dll;
    int cur_i = argoff + num_parsed;
    if (mode != host_mode_t::standalone)
    {
        trace::verbose(_X("Detected a non-standalone application, expecting app.dll to execute."));
        if (cur_i >= argc)
        {
            return muxer_usage();
        }

        app_candidate = argv[cur_i];
        bool is_app_managed = (ends_with(app_candidate, _X(".dll"), false) || ends_with(app_candidate, _X(".exe"), false)) && pal::realpath(&app_candidate);

        if (!is_app_managed)
        {
            trace::verbose(_X("Application '%s' is not a managed executable."), app_candidate.c_str());

            *is_an_app = false;

            if (exec_mode)
            {
                trace::error(_X("dotnet exec needs a managed .dll or .exe extension. The application specified was '%s'"), app_candidate.c_str());
                return InvalidArgFailure;
            }

            // Route to CLI.
            return AppArgNotRunnable;
        }
    }

    // App is managed executable.
    trace::verbose(_X("Treating application '%s' as a managed executable."), app_candidate.c_str());

    if (!pal::file_exists(app_candidate))
    {
        trace::error(_X("The application to execute does not exist: '%s'"), app_candidate.c_str());
        return InvalidArgFailure;
    }

    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();
    }

    // Transform dotnet [exec] [--additionalprobingpath path] [--depsfile file] [dll] [args] -> dotnet [dll] [args]
    return read_config_and_execute(own_dir, app_candidate, opts, new_argc, new_argv, mode);
}