Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64a55345 authored by Steve Muckle's avatar Steve Muckle
Browse files

toolbox: add modprobe

Add an implementation of modprobe based on libmodprobe.

Change-Id: I85ba440766406fe6ca7e90bec204d06632785a66
parent ded44c06
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ cc_defaults {
        "toolbox.c",
        "getevent.c",
        "getprop.cpp",
        "modprobe.cpp",
        "setprop.cpp",
        "start.cpp",
    ],
@@ -33,11 +34,15 @@ cc_defaults {
    shared_libs: [
        "libbase",
    ],
    static_libs: ["libpropertyinfoparser"],
    static_libs: [
        "libmodprobe",
        "libpropertyinfoparser",
    ],

    symlinks: [
        "getevent",
        "getprop",
        "modprobe",
        "setprop",
        "start",
        "stop",

toolbox/modprobe.cpp

0 → 100644
+201 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <ctype.h>
#include <getopt.h>
#include <stdlib.h>
#include <iostream>

#include <android-base/strings.h>
#include <modprobe/modprobe.h>

enum modprobe_mode {
    AddModulesMode,
    RemoveModulesMode,
    ListModulesMode,
    ShowDependenciesMode,
};

static void print_usage(void) {
    std::cerr << "Usage:" << std::endl;
    std::cerr << std::endl;
    std::cerr << "  modprobe [-alrqvsDb] [-d DIR] [MODULE]+" << std::endl;
    std::cerr << "  modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]" << std::endl;
    std::cerr << std::endl;
    std::cerr << "Options:" << std::endl;
    std::cerr << "  -b: Apply blacklist to module names too" << std::endl;
    std::cerr << "  -d: Load modules from DIR, option may be used multiple times" << std::endl;
    std::cerr << "  -D: Print dependencies for modules only, do not load";
    std::cerr << "  -h: Print this help" << std::endl;
    std::cerr << "  -l: List modules matching pattern" << std::endl;
    std::cerr << "  -r: Remove MODULE (multiple modules may be specified)" << std::endl;
    std::cerr << "  -q: Quiet" << std::endl;
    std::cerr << "  -v: Verbose" << std::endl;
    std::cerr << std::endl;
}

#define check_mode()                                                      \
    if (mode != AddModulesMode) {                                         \
        std::cerr << "Error, multiple mode flags specified" << std::endl; \
        print_usage();                                                    \
        return EXIT_FAILURE;                                              \
    }

extern "C" int modprobe_main(int argc, char** argv) {
    std::vector<std::string> modules;
    std::string module_parameters;
    std::vector<std::string> mod_dirs;
    modprobe_mode mode = AddModulesMode;
    bool blacklist = false;
    bool verbose = false;
    int rv = EXIT_SUCCESS;

    int opt;
    while ((opt = getopt(argc, argv, "abd:Dhlqrv")) != -1) {
        switch (opt) {
            case 'a':
                // toybox modprobe supported -a to load multiple modules, this
                // is supported here by default, ignore flag
                check_mode();
                break;
            case 'b':
                blacklist = true;
                break;
            case 'd':
                mod_dirs.emplace_back(optarg);
                break;
            case 'D':
                check_mode();
                mode = ShowDependenciesMode;
                break;
            case 'h':
                print_usage();
                return EXIT_SUCCESS;
            case 'l':
                check_mode();
                mode = ListModulesMode;
                break;
            case 'q':
                verbose = false;
                break;
            case 'r':
                check_mode();
                mode = RemoveModulesMode;
                break;
            case 'v':
                verbose = true;
                break;
            default:
                std::cerr << "Unrecognized option: " << opt << std::endl;
                return EXIT_FAILURE;
        }
    }

    int parameter_count = 0;
    for (opt = optind; opt < argc; opt++) {
        if (!strchr(argv[opt], '=')) {
            modules.emplace_back(argv[opt]);
        } else {
            parameter_count++;
            if (module_parameters.empty()) {
                module_parameters = argv[opt];
            } else {
                module_parameters = module_parameters + " " + argv[opt];
            }
        }
    }

    if (verbose) {
        std::cout << "mode is " << mode << std::endl;
        std::cout << "verbose is " << verbose << std::endl;
        std::cout << "mod_dirs is: " << android::base::Join(mod_dirs, "") << std::endl;
        std::cout << "modules is: " << android::base::Join(modules, "") << std::endl;
        std::cout << "module parameters is: " << android::base::Join(module_parameters, "")
                  << std::endl;
    }

    if (modules.empty()) {
        if (mode == ListModulesMode) {
            // emulate toybox modprobe list with no pattern (list all)
            modules.emplace_back("*");
        } else {
            std::cerr << "No modules given." << std::endl;
            print_usage();
            return EXIT_FAILURE;
        }
    }
    if (mod_dirs.empty()) {
        std::cerr << "No module configuration directories given." << std::endl;
        print_usage();
        return EXIT_FAILURE;
    }
    if (parameter_count && modules.size() > 1) {
        std::cerr << "Only one module may be loaded when specifying module parameters."
                  << std::endl;
        print_usage();
        return EXIT_FAILURE;
    }

    Modprobe m(mod_dirs);
    m.EnableVerbose(verbose);
    if (blacklist) {
        m.EnableBlacklist(true);
    }

    for (const auto& module : modules) {
        switch (mode) {
            case AddModulesMode:
                if (!m.LoadWithAliases(module, true, module_parameters)) {
                    std::cerr << "Failed to load module " << module;
                    rv = EXIT_FAILURE;
                }
                break;
            case RemoveModulesMode:
                if (!m.Remove(module)) {
                    std::cerr << "Failed to remove module " << module;
                    rv = EXIT_FAILURE;
                }
                break;
            case ListModulesMode: {
                std::vector<std::string> list = m.ListModules(module);
                std::cout << android::base::Join(list, "\n") << std::endl;
                break;
            }
            case ShowDependenciesMode: {
                std::vector<std::string> pre_deps;
                std::vector<std::string> deps;
                std::vector<std::string> post_deps;
                if (!m.GetAllDependencies(module, &pre_deps, &deps, &post_deps)) {
                    rv = EXIT_FAILURE;
                    break;
                }
                std::cout << "Dependencies for " << module << ":" << std::endl;
                std::cout << "Soft pre-dependencies:" << std::endl;
                std::cout << android::base::Join(pre_deps, "\n") << std::endl;
                std::cout << "Hard dependencies:" << std::endl;
                std::cout << android::base::Join(deps, "\n") << std::endl;
                std::cout << "Soft post-dependencies:" << std::endl;
                std::cout << android::base::Join(post_deps, "\n") << std::endl;
                break;
            }
            default:
                std::cerr << "Bad mode";
                rv = EXIT_FAILURE;
        }
    }

    return rv;
}
+1 −0
Original line number Diff line number Diff line
TOOL(getevent)
TOOL(getprop)
TOOL(modprobe)
TOOL(setprop)
TOOL(start)
TOOL(stop)