Ignore:
Timestamp:
Dec 20, 2016, 4:07:32 PM (7 years ago)
Author:
Bruno Cornec
Message:

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

Location:
branches/3.3
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/3.3/mindi-busybox/modutils/modprobe-small.c

    r3232 r3621  
    1010
    1111//applet:IF_MODPROBE_SMALL(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP))
    12 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
    13 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
    14 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
    15 //applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, modprobe))
     12//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, depmod))
     13//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, insmod))
     14//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, lsmod))
     15//applet:IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, BB_DIR_SBIN, BB_SUID_DROP, rmmod))
    1616
    1717#include "libbb.h"
     
    2222extern int init_module(void *module, unsigned long len, const char *options);
    2323extern int delete_module(const char *module, unsigned flags);
    24 extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret);
     24/* linux/include/linux/module.h has limit of 64 chars on module names */
     25#undef MODULE_NAME_LEN
     26#define MODULE_NAME_LEN 64
    2527
    2628
     
    4446    char *aliases;
    4547    char *deps;
     48    smallint open_read_failed;
    4649} module_info;
    4750
     
    114117static char* find_keyword(char *ptr, size_t len, const char *word)
    115118{
    116     int wlen;
    117 
    118119    if (!ptr) /* happens if xmalloc_open_zipped_read_close cannot read it */
    119120        return NULL;
    120121
    121     wlen = strlen(word);
    122     len -= wlen - 1;
     122    len -= strlen(word) - 1;
    123123    while ((ssize_t)len > 0) {
    124124        char *old = ptr;
     125        char *after_word;
     126
    125127        /* search for the first char in word */
    126         ptr = memchr(ptr, *word, len);
     128        ptr = memchr(ptr, word[0], len);
    127129        if (ptr == NULL) /* no occurance left, done */
    128130            break;
    129         if (strncmp(ptr, word, wlen) == 0)
    130             return ptr + wlen; /* found, return ptr past it */
     131        after_word = is_prefixed_with(ptr, word);
     132        if (after_word)
     133            return after_word; /* found, return ptr past it */
    131134        ++ptr;
    132135        len -= (ptr - old);
     
    142145        ++s;
    143146    }
     147}
     148
     149static char *filename2modname(const char *filename, char *modname)
     150{
     151    int i;
     152    const char *from;
     153
     154    // Disabled since otherwise "modprobe dir/name" would work
     155    // as if it is "modprobe name". It is unclear why
     156    // 'basenamization' was here in the first place.
     157    //from = bb_get_last_path_component_nostrip(filename);
     158    from = filename;
     159    for (i = 0; i < (MODULE_NAME_LEN-1) && from[i] != '\0' && from[i] != '.'; i++)
     160        modname[i] = (from[i] == '-') ? '_' : from[i];
     161    modname[i] = '\0';
     162
     163    return modname;
     164}
     165
     166static int pathname_matches_modname(const char *pathname, const char *modname)
     167{
     168    int r;
     169    char name[MODULE_NAME_LEN];
     170    filename2modname(bb_get_last_path_component_nostrip(pathname), name);
     171    r = (strcmp(name, modname) == 0);
     172    return r;
    144173}
    145174
     
    195224}
    196225
    197 static void parse_module(module_info *info, const char *pathname)
     226/* Returns !0 if open/read was unsuccessful */
     227static int parse_module(module_info *info, const char *pathname)
    198228{
    199229    char *module_image;
     
    204234
    205235    /* Read (possibly compressed) module */
     236    errno = 0;
    206237    len = 64 * 1024 * 1024; /* 64 Mb at most */
    207238    module_image = xmalloc_open_zipped_read_close(pathname, &len);
     
    213244    pos = 0;
    214245    while (1) {
     246        unsigned start = stringbuf_idx;
    215247        ptr = find_keyword(module_image + pos, len - pos, "alias=");
    216248        if (!ptr) {
     
    229261        append(ptr);
    230262        appendc(' ');
     263        /*
     264         * Don't add redundant aliases, such as:
     265         * libcrc32c.ko symbol:crc32c symbol:crc32c
     266         */
     267        if (start) { /* "if we aren't the first alias" */
     268            char *found, *last;
     269            stringbuf[stringbuf_idx] = '\0';
     270            last = stringbuf + start;
     271            /*
     272             * String at last-1 is " symbol:crc32c "
     273             * (with both leading and trailing spaces).
     274             */
     275            if (strncmp(stringbuf, last, stringbuf_idx - start) == 0)
     276                /* First alias matches us */
     277                found = stringbuf;
     278            else
     279                /* Does any other alias match? */
     280                found = strstr(stringbuf, last-1);
     281            if (found < last-1) {
     282                /* There is absolutely the same string before us */
     283                dbg2_error_msg("redundant:'%s'", last);
     284                stringbuf_idx = start;
     285                goto skip;
     286            }
     287        }
    231288 skip:
    232289        pos = (ptr - module_image);
     
    245302        append(ptr);
    246303    }
     304    free(module_image);
    247305    info->deps = copy_stringbuf();
    248306
    249     free(module_image);
    250 }
    251 
    252 static int pathname_matches_modname(const char *pathname, const char *modname)
    253 {
    254     const char *fname = bb_get_last_path_component_nostrip(pathname);
    255     const char *suffix = strrstr(fname, ".ko");
    256 //TODO: can do without malloc?
    257     char *name = xstrndup(fname, suffix - fname);
    258     int r;
    259     replace(name, '-', '_');
    260     r = (strcmp(name, modname) == 0);
    261     free(name);
    262     return r;
     307    info->open_read_failed = (module_image == NULL);
     308    return info->open_read_failed;
    263309}
    264310
     
    291337    dbg1_error_msg("'%s' module name matches", pathname);
    292338    module_found_idx = cur;
    293     parse_module(&modinfo[cur], pathname);
     339    if (parse_module(&modinfo[cur], pathname) != 0)
     340        return TRUE; /* failed to open/read it, no point in trying loading */
    294341
    295342    if (!(option_mask32 & OPT_r)) {
     
    422469}
    423470
    424 static module_info* find_alias(const char *alias)
     471static module_info** find_alias(const char *alias)
    425472{
    426473    int i;
    427474    int dep_bb_fd;
    428     module_info *result;
     475    int infoidx;
     476    module_info **infovec;
    429477    dbg1_error_msg("find_alias('%s')", alias);
    430478
     
    439487                parse_module(&modinfo[i], modinfo[i].pathname);
    440488            }
    441             return &modinfo[i];
     489            infovec = xzalloc(2 * sizeof(infovec[0]));
     490            infovec[0] = &modinfo[i];
     491            return infovec;
    442492        }
    443493        i++;
     
    452502    /* Scan all module bodies, extract modinfo (it contains aliases) */
    453503    i = 0;
    454     result = NULL;
     504    infoidx = 0;
     505    infovec = NULL;
    455506    while (modinfo[i].pathname) {
    456507        char *desc, *s;
    457508        if (!modinfo[i].aliases) {
    458509            parse_module(&modinfo[i], modinfo[i].pathname);
    459         }
    460         if (result) {
    461             i++;
    462             continue;
    463510        }
    464511        /* "alias1 symbol:sym1 alias2 symbol:sym2" */
     
    473520                dbg1_error_msg("found alias '%s' in module '%s'",
    474521                        alias, modinfo[i].pathname);
    475                 result = &modinfo[i];
     522                infovec = xrealloc_vector(infovec, 1, infoidx);
     523                infovec[infoidx++] = &modinfo[i];
    476524                break;
    477525            }
    478526        }
    479527        free(desc);
    480         if (result && dep_bb_fd < 0)
    481             return result;
    482528        i++;
    483529    }
     
    488534    }
    489535
    490     dbg1_error_msg("find_alias '%s' returns %p", alias, result);
    491     return result;
     536    dbg1_error_msg("find_alias '%s' returns %d results", alias, infoidx);
     537    return infovec;
    492538}
    493539
     
    496542static int already_loaded(const char *name)
    497543{
    498     int ret = 0;
    499     char *s;
    500     parser_t *parser = config_open2("/proc/modules", xfopen_for_read);
    501     while (config_read(parser, &s, 1, 1, "# \t", PARSE_NORMAL & ~PARSE_GREEDY)) {
    502         if (strcmp(s, name) == 0) {
    503             ret = 1;
    504             break;
    505         }
    506     }
    507     config_close(parser);
    508     return ret;
     544    int ret;
     545    char *line;
     546    FILE *fp;
     547
     548    ret = 5 * 2;
     549 again:
     550    fp = fopen_for_read("/proc/modules");
     551    if (!fp)
     552        return 0;
     553    while ((line = xmalloc_fgetline(fp)) != NULL) {
     554        char *live;
     555        char *after_name;
     556
     557        // Examples from kernel 3.14.6:
     558        //pcspkr 12718 0 - Live 0xffffffffa017e000
     559        //snd_timer 28690 2 snd_seq,snd_pcm, Live 0xffffffffa025e000
     560        //i915 801405 2 - Live 0xffffffffa0096000
     561        after_name = is_prefixed_with(line, name);
     562        if (!after_name || *after_name != ' ') {
     563            free(line);
     564            continue;
     565        }
     566        live = strstr(line, " Live");
     567        free(line);
     568        if (!live) {
     569            /* State can be Unloading, Loading, or Live.
     570             * modprobe must not return prematurely if we see "Loading":
     571             * it can cause further programs to assume load completed,
     572             * but it did not (yet)!
     573             * Wait up to 5*20 ms for it to resolve.
     574             */
     575            ret -= 2;
     576            if (ret == 0)
     577                break;  /* huh? report as "not loaded" */
     578            fclose(fp);
     579            usleep(20*1000);
     580            goto again;
     581        }
     582        ret = 1;
     583        break;
     584    }
     585    fclose(fp);
     586
     587    return ret & 1;
    509588}
    510589#else
    511 #define already_loaded(name) is_rmmod
     590#define already_loaded(name) 0
    512591#endif
     592
     593static int rmmod(const char *filename)
     594{
     595    int r;
     596    char modname[MODULE_NAME_LEN];
     597
     598    filename2modname(filename, modname);
     599    r = delete_module(modname, O_NONBLOCK | O_EXCL);
     600    dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
     601    if (r != 0 && !(option_mask32 & OPT_q)) {
     602        bb_perror_msg("remove '%s'", modname);
     603    }
     604    return r;
     605}
    513606
    514607/*
     
    522615#define cmdline_options ""
    523616#endif
    524 static void process_module(char *name, const char *cmdline_options)
     617static int process_module(char *name, const char *cmdline_options)
    525618{
    526619    char *s, *deps, *options;
     620    module_info **infovec;
    527621    module_info *info;
    528     int is_rmmod = (option_mask32 & OPT_r) != 0;
     622    int infoidx;
     623    int is_remove = (option_mask32 & OPT_r) != 0;
     624    int exitcode = EXIT_SUCCESS;
     625
    529626    dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
    530627
    531628    replace(name, '-', '_');
    532629
    533     dbg1_error_msg("already_loaded:%d is_rmmod:%d", already_loaded(name), is_rmmod);
    534     if (already_loaded(name) != is_rmmod) {
     630    dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
     631
     632    if (applet_name[0] == 'r') {
     633        /* rmmod.
     634         * Does not remove dependencies, no need to scan, just remove.
     635         * (compat note: this allows and strips .ko suffix)
     636         */
     637        rmmod(name);
     638        return EXIT_SUCCESS;
     639    }
     640
     641    /*
     642     * We used to have "is_remove != already_loaded(name)" check here, but
     643     *  modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80
     644     * won't unload modules (there are more than one)
     645     * which have this alias.
     646     */
     647    if (!is_remove && already_loaded(name)) {
    535648        dbg1_error_msg("nothing to do for '%s'", name);
    536         return;
     649        return EXIT_SUCCESS;
    537650    }
    538651
    539652    options = NULL;
    540     if (!is_rmmod) {
     653    if (!is_remove) {
    541654        char *opt_filename = xasprintf("/etc/modules/%s", name);
    542655        options = xmalloc_open_read_close(opt_filename, NULL);
     
    561674        /* Scan module directory. This is done only once.
    562675         * It will attempt module load, and will exit(EXIT_SUCCESS)
    563          * on success. */
     676         * on success.
     677         */
    564678        module_found_idx = -1;
    565679        recursive_action(".",
     
    568682            NULL, /* dir action */
    569683            name, /* user data */
    570             0); /* depth */
     684            0 /* depth */
     685        );
    571686        dbg1_error_msg("dirscan complete");
    572         /* Module was not found, or load failed, or is_rmmod */
     687        /* Module was not found, or load failed, or is_remove */
    573688        if (module_found_idx >= 0) { /* module was found */
    574             info = &modinfo[module_found_idx];
     689            infovec = xzalloc(2 * sizeof(infovec[0]));
     690            infovec[0] = &modinfo[module_found_idx];
    575691        } else { /* search for alias, not a plain module name */
    576             info = find_alias(name);
     692            infovec = find_alias(name);
    577693        }
    578694    } else {
    579         info = find_alias(name);
    580     }
    581 
    582 // Problem here: there can be more than one module
    583 // for the given alias. For example,
    584 // "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches
    585 // ata_piix because it has an alias "pci:v00008086d00007010sv*sd*bc*sc*i*"
    586 // and ata_generic, it has an alias "alias=pci:v*d*sv*sd*bc01sc01i*"
    587 // Standard modprobe would load them both.
    588 // In this code, find_alias() returns only the first matching module.
    589 
    590     /* rmmod? unload it by name */
    591     if (is_rmmod) {
    592         if (delete_module(name, O_NONBLOCK | O_EXCL) != 0) {
    593             if (!(option_mask32 & OPT_q))
    594                 bb_perror_msg("remove '%s'", name);
    595             goto ret;
    596         }
    597 
    598         if (applet_name[0] == 'r') {
    599             /* rmmod: do not remove dependencies, exit */
    600             goto ret;
    601         }
    602 
     695        infovec = find_alias(name);
     696    }
     697
     698    if (!infovec) {
     699        /* both dirscan and find_alias found nothing */
     700        if (!is_remove && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
     701            bb_error_msg("module '%s' not found", name);
     702//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
     703        goto ret;
     704    }
     705
     706    /* There can be more than one module for the given alias. For example,
     707     * "pci:v00008086d00007010sv00000000sd00000000bc01sc01i80" matches
     708     * ata_piix because it has alias "pci:v00008086d00007010sv*sd*bc*sc*i*"
     709     * and ata_generic, it has alias "pci:v*d*sv*sd*bc01sc01i*"
     710     * Standard modprobe loads them both. We achieve it by returning
     711     * a *list* of modinfo pointers from find_alias().
     712     */
     713
     714    /* modprobe -r? unload module(s) */
     715    if (is_remove) {
     716        infoidx = 0;
     717        while ((info = infovec[infoidx++]) != NULL) {
     718            int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
     719            if (r != 0) {
     720                goto ret; /* error */
     721            }
     722        }
    603723        /* modprobe -r: we do not stop here -
    604724         * continue to unload modules on which the module depends:
     
    609729    }
    610730
    611     if (!info) {
    612         /* both dirscan and find_alias found nothing */
    613         if (!is_rmmod && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
    614             bb_error_msg("module '%s' not found", name);
    615 //TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
    616         goto ret;
    617     }
    618 
    619     /* Iterate thru dependencies, trying to (un)load them */
    620     deps = str_2_list(info->deps);
    621     for (s = deps; *s; s += strlen(s) + 1) {
    622         //if (strcmp(name, s) != 0) // N.B. do loops exist?
    623         dbg1_error_msg("recurse on dep '%s'", s);
    624         process_module(s, NULL);
    625         dbg1_error_msg("recurse on dep '%s' done", s);
    626     }
    627     free(deps);
    628 
    629     /* modprobe -> load it */
    630     if (!is_rmmod) {
    631         if (!options || strstr(options, "blacklist") == NULL) {
    632             errno = 0;
    633             if (load_module(info->pathname, options) != 0) {
    634                 if (EEXIST != errno) {
    635                     bb_error_msg("'%s': %s",
    636                         info->pathname,
    637                         moderror(errno));
    638                 } else {
    639                     dbg1_error_msg("'%s': %s",
    640                         info->pathname,
    641                         moderror(errno));
    642                 }
     731    infoidx = 0;
     732    while ((info = infovec[infoidx++]) != NULL) {
     733        /* Iterate thru dependencies, trying to (un)load them */
     734        deps = str_2_list(info->deps);
     735        for (s = deps; *s; s += strlen(s) + 1) {
     736            //if (strcmp(name, s) != 0) // N.B. do loops exist?
     737            dbg1_error_msg("recurse on dep '%s'", s);
     738            process_module(s, NULL);
     739            dbg1_error_msg("recurse on dep '%s' done", s);
     740        }
     741        free(deps);
     742
     743        if (is_remove)
     744            continue;
     745
     746        /* We are modprobe: load it */
     747        if (options && strstr(options, "blacklist")) {
     748            dbg1_error_msg("'%s': blacklisted", info->pathname);
     749            continue;
     750        }
     751        if (info->open_read_failed) {
     752            /* We already tried it, didn't work. Don't try load again */
     753            exitcode = EXIT_FAILURE;
     754            continue;
     755        }
     756        errno = 0;
     757        if (load_module(info->pathname, options) != 0) {
     758            if (EEXIST != errno) {
     759                bb_error_msg("'%s': %s",
     760                    info->pathname,
     761                    moderror(errno));
     762            } else {
     763                dbg1_error_msg("'%s': %s",
     764                    info->pathname,
     765                    moderror(errno));
    643766            }
    644         } else {
    645             dbg1_error_msg("'%s': blacklisted", info->pathname);
     767            exitcode = EXIT_FAILURE;
    646768        }
    647769    }
    648770 ret:
     771    free(infovec);
    649772    free(options);
    650 //TODO: return load attempt result from process_module.
    651 //If dep didn't load ok, continuing makes little sense.
     773
     774    return exitcode;
    652775}
    653776#undef cmdline_options
     
    704827//usage:#if ENABLE_MODPROBE_SMALL
    705828
    706 //// Note: currently, help system shows modprobe --help text for all aliased cmds
    707 //// (see APPLET_ODDNAME macro definition).
    708 //// All other help texts defined below are not used. FIXME?
    709 
    710829//usage:#define depmod_trivial_usage NOUSAGE_STR
    711830//usage:#define depmod_full_usage ""
     
    721840//usage:    "[SYMBOL=VALUE]..."
    722841//usage:#define insmod_full_usage "\n\n"
    723 //usage:       "Load the specified kernel modules into the kernel"
     842//usage:       "Load kernel module"
    724843//usage:    IF_FEATURE_2_4_MODULES( "\n"
    725844//usage:     "\n    -f  Force module to load into the wrong kernel version"
     
    746865
    747866//usage:#define modprobe_trivial_usage
    748 //usage:    "[-qfwrsv] MODULE [symbol=value]..."
     867//usage:    "[-qfwrsv] MODULE [SYMBOL=VALUE]..."
    749868//usage:#define modprobe_full_usage "\n\n"
    750869//usage:       "    -r  Remove MODULE (stacks) or do autoclean"
     
    760879int modprobe_main(int argc UNUSED_PARAM, char **argv)
    761880{
     881    int exitcode;
    762882    struct utsname uts;
    763883    char applet0 = applet_name[0];
     
    831951
    832952#if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
    833     /* If not rmmod, parse possible module options given on command line.
     953    /* If not rmmod/-r, parse possible module options given on command line.
    834954     * insmod/modprobe takes one module name, the rest are parameters. */
    835955    options = NULL;
    836     if ('r' != applet0) {
     956    if (!(option_mask32 & OPT_r)) {
    837957        char **arg = argv;
    838958        while (*++arg) {
     
    845965    }
    846966#else
    847     if ('r' != applet0)
     967    if (!(option_mask32 & OPT_r))
    848968        argv[1] = NULL;
    849969#endif
     
    865985                    *argv, moderror(errno));
    866986        }
    867         return 0;
     987        return EXIT_SUCCESS;
    868988    }
    869989
    870990    /* Try to load modprobe.dep.bb */
    871     load_dep_bb();
     991    if ('r' != applet0) { /* not rmmod */
     992        load_dep_bb();
     993    }
    872994
    873995    /* Load/remove modules.
    874      * Only rmmod loops here, modprobe has only argv[0] */
     996     * Only rmmod/modprobe -r loops here, insmod/modprobe has only argv[0] */
     997    exitcode = EXIT_SUCCESS;
    875998    do {
    876         process_module(*argv, options);
     999        exitcode |= process_module(*argv, options);
    8771000    } while (*++argv);
    8781001
     
    8801003        IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
    8811004    }
    882     return EXIT_SUCCESS;
    883 }
     1005    return exitcode;
     1006}
Note: See TracChangeset for help on using the changeset viewer.