troglobit / finit

Fast init for Linux. Cookies included
https://troglobit.com/projects/finit/
MIT License
622 stars 61 forks source link

Allow custom modprobe command in modules-load plugin #325

Closed hongkongkiwi closed 1 year ago

hongkongkiwi commented 1 year ago

Here is my modules-load.d/03-wifi.conf file:

set noindex
compat.ko
cfg80211.ko
brcmfmac.ko
brcmutil.ko

I would like to have optional module loading based on condition, for example:

<hw/wifi/mode-normal> brcmfmac.ko
<hw/wifi/mode-mfgtest> brcmfmac.ko alternative_fw_path=/a/b/c

Is it possible to add this to the modules-load.d syntax for me? I think this can be backwards compatible because if <> is not defined before the module name then it would just act as normal.

If not, do you have another suggestion on how to handle this?

hongkongkiwi commented 1 year ago

I guess an alternative option is to add support for running a script in the modules-load.d file, that way the script can check the condition instead of running modprobe directly.

Perhaps !myscript.sh line ? (! to indicate a script)

troglobit commented 1 year ago

It's possible, a bit of work of course, but wouldn't it be easier to fold this in with the alternative fstab support that was added earlier? I.e., to always use the alternative_fw_path=/a/b/c but have different things be mounted there depending on fstab?

hongkongkiwi commented 1 year ago

That's a bit tricky in my system because those are used for boot slots to match the RAUC style, with the fstab being selected specifically based on the bootslot.

What about this minor change? (suggestion below the source)

#define SERVICE_LINE \
    "cgroup.init name:modprobe.%s :%d [2345] /sbin/modprobe %s %s -- Kernel module: %s"
#define SERVICE_LINE_NOINDEX \
    "cgroup.init name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s"

static int load_file(const char *file, int index)
{
    char module_path[PATH_MAX];
    char line[256];
    int num = 0;
    FILE *fp;

    strlcpy(module_path, MODULES_LOAD_PATH "/", sizeof(module_path));
    strlcat(module_path, file, sizeof(module_path));

    fp = fopen(module_path, "r");
    if (!fp)
        return 0;

    while (fgets(line, sizeof(line), fp)) {
        char cmd[CMD_SIZE], *mod, *args;

        chomp(line);

        mod = strip_line(line);
        if (!mod[0])
            continue;

        if (mod[0] == '#' || mod[0] == ';')
            continue;

        if (!strcmp(mod, "set noindex")) {
            index = 0;
            continue;
        }
        if (!strncmp(mod, "set index", 9)) {
            mod += 9;
            args = strchr(mod, '=');
            if (args) /* optional */
                mod = args + 1;
            index = atoi(mod);
            continue;
        }

        mod = strtok_r(mod, " ", &args);
        if (!mod)
            continue;

        if (!index)
            snprintf(cmd, sizeof(cmd), SERVICE_LINE_NOINDEX, mod, mod, args, mod);
        else
            snprintf(cmd, sizeof(cmd), SERVICE_LINE, mod, index++, mod, args, mod);

        service_register(SVC_TYPE_TASK, cmd, global_rlimit, NULL);
        num++;
    }
    fclose(fp);

    return num;
}

From what I can see, you loop through and set a state based on each line you detect. For example, when you hit no index, then modules from that line onwards would be not indexed.

Could we have it like this?

Add a new flag which simply defines the modprobe command to run, e.g.: modprobe /usr/bin/mymodprobe

then from every line forward, when you create the task, instead of creating: cgroup.init name:modprobe.%s [2345] /sbin/modprobe %s %s -- Kernel module: %s

You create: cgroup.init name:modprobe.%s [2345] %s %s %s -- Kernel module: %s and pass the first arg as whatever came after modprobe.

This is flexible and allows users to also override what your calling, or add extra arguments to modprobe if needed e.g. modprobe /sbin/modprobe myarg

It allows a wrapper script to modprobe (such as my case), OR to define another binary if wanted.

So in my case, my file would look like this:

set noindex
compat.ko
cfg80211.ko
modprobe /usr/sbin/modprobe-wifi-wrapper
brcmfmac.ko
modprobe /sbin/modprobe
brcmutil.ko
troglobit commented 1 year ago

(On the move, so just skimmed through your proposal, but if understood it correctly) that works. If you're okay with using the set keyword, as in set modprobe ...?

hongkongkiwi commented 1 year ago

Yup, no problem with using set. (ideally I would love to also support conditions here too which might not be hard since this is a task but you need to add additional parsing for this so we can add it as maybe a future feature)

set noindex
compat.ko
cfg80211.ko
set modprobe /usr/sbin/modprobe-wifi-wrapper
brcmfmac.ko
set modprobe /sbin/modprobe
brcmutil.ko
troglobit commented 1 year ago

Yeah conditions would be nice, but let's postpone that to a later release.

troglobit commented 1 year ago

There, basic set modprobe fooloader in place, and the documentation has been updated accordingly: https://github.com/troglobit/finit/blob/master/doc/plugins.md