Beispiel #1
0
void i860_cpu_device::run_cycle() {
    CLEAR_FLOW();
    m_dim_cc_valid = false;
    m_flow        &= ~DIM_OP;
    UINT64 insn64  = ifetch64(m_pc);
    
    if(!(m_pc & 4)) {
        UINT32 savepc  = m_pc;
        
#if ENABLE_DEBUGGER
        if(m_single_stepping) debugger(0,0);
#endif
        
        UINT32 insnLow = insn64;
        if(insnLow == INSN_FNOP_DIM) {
            if(m_dim) m_flow |=  DIM_OP;
            else      m_flow &= ~DIM_OP;
        } else if((insnLow & INSN_MASK_DIM) == INSN_FP_DIM)
            m_flow |= DIM_OP;
        
        decode_exec(insnLow);
        
        if (PENDING_TRAP()) {
            handle_trap(savepc);
            goto done;
        } else if(GET_PC_UPDATED()) {
            goto done;
        } else {
            // If the PC wasn't updated by a control flow instruction, just bump to next sequential instruction.
            m_pc   += 4;
            CLEAR_FLOW();
        }
    }
    
    if(m_pc & 4) {
        UINT32 savepc  = m_pc;
        
#if ENABLE_DEBUGGER
        if(m_single_stepping && !(m_dim)) debugger(0,0);
#endif

        UINT32 insnHigh= insn64 >> 32;
        decode_exec(insnHigh);
        
        // only check for external interrupts
        // - on high-word (speedup)
        // - not DIM (safety :-)
        // - when no other traps are pending
        if(!(m_dim) && !(PENDING_TRAP())) {
            if(m_flow & EXT_INTR) {
                m_flow &= ~EXT_INTR;
                gen_interrupt();
            } else
                clr_interrupt();
        }
        
        if (PENDING_TRAP()) {
            handle_trap(savepc);
        } else if (GET_PC_UPDATED()) {
            goto done;
        } else {
            // If the PC wasn't updated by a control flow instruction, just bump to next sequential instruction.
            m_pc += 4;
        }
    }
Beispiel #2
0
/*
 *	Read the configuration file.
 *	If parameter "all" == 0 then ignore everything except path info
 *	Return -1 if any error.
 *	Error messages generated.
 */
static int do_read(int all, char *force_ver, char *base_dir, char *conf_file, int depth)
{
#define MAX_LEVEL 20
    FILE *fin;
    GLOB_LIST g;
    int i;
    int assgn;
    int drop_default_paths = 1;
    int lineno = 0;
    int ret = 0;
    int state[MAX_LEVEL + 1]; /* nested "if" */
    int level = 0;
    int sizebuf;
    char *buf = NULL;
    char tmpline[PATH_MAX];
    char **pathp;
    char *envpath;
    char *version;
    char *type;
    char **glb;
    char old_name[] = "/etc/conf.modules";
    int conf_file_specified = 0;

    /*
     * The configuration file is optional.
     * No error is printed if it is missing.
     * If it is missing the following content is assumed.
     *
     * path[boot]=/lib/modules/boot
     *
     * path[toplevel]=/lib/modules/`uname -r`
     *
     * path[toplevel]=/lib/modules/`kernelversion`
     *   (where kernelversion gives the major kernel version: "2.0", "2.2"...)
     *
     * path[toplevel]=/lib/modules/default
     *
     * path[kernel]=/lib/modules/kernel
     * path[fs]=/lib/modules/fs
     * path[net]=/lib/modules/net
     * path[scsi]=/lib/modules/scsi
     * path[block]=/lib/modules/block
     * path[cdrom]=/lib/modules/cdrom
     * path[ipv4]=/lib/modules/ipv4
     * path[ipv6]=/lib/modules/ipv6
     * path[sound]=/lib/modules/sound
     * path[fc4]=/lib/modules/fc4
     * path[video]=/lib/modules/video
     * path[misc]=/lib/modules/misc
     * path[pcmcia]=/lib/modules/pcmcia
     * path[atm]=/lib/modules/atm
     * path[usb]=/lib/modules/usb
     * path[ide]=/lib/modules/ide
     * path[ieee1394]=/lib/modules/ieee1394
     * path[mtd]=/lib/modules/mtd
     *
     * The idea is that modprobe will look first if the
     * modules are compiled for the current release of the kernel.
     * If not found, it will look for modules that fit for the
     * general kernelversion (2.0, 2.2 and so on).
     * If still not found, it will look into the default release.
     * And if still not found, it will look in the other directories.
     *
     * The strategy should be like this:
     * When you install a new linux kernel, the modules should go
     * into a directory related to the release (version) of the kernel.
     * Then you can do a symlink "default" to this directory.
     *
     * Each time you compile a new kernel, the make modules_install
     * will create a new directory, but it won't change thee default.
     *
     * When you get a module unrelated to the kernel distribution
     * you can place it in one of the last three directory types.
     *
     * This is the default strategy. Of course you can overide
     * this in /etc/modules.conf.
     *
     * 2.3.15 added a new file tree walk algorithm which made it possible to
     * point at a top level directory and get the same behaviour as earlier
     * versions of modutils.  2.3.16 takes this one stage further, it
     * removes all the individual directory names from most of the scans,
     * only pointing at the top level directory.  The only exception is the
     * last ditch scan, scanning all of /lib/modules would be a bad idea(TM)
     * so the last ditch scan still runs individual directory names under
     * /lib/modules.
     *
     * Additional syntax:
     *
     * [add] above module module1 ...
     *	Specify additional modules to pull in on top of a module
     *
     * [add] below module module1 ...
     *	Specify additional modules needed to be able to load a module
     *
     * [add] prune filename ...
     *
     * [add] probe name module1 ...
     *	When "name" is requested, modprobe tries to install each
     *	module in the list until it succeeds.
     *
     * [add] probeall name module1 ...
     *	When "name" is requested, modprobe tries to install all
     *	modules in the list.
     *	If any module is installed, the command has succeeded.
     *
     * [add] options module option_list
     *
     * For all of the above, the optional "add" prefix is used to
     * add to a list instead of replacing the contents.
     *
     * include FILE_TO_INCLUDE
     *	This does what you expect. No limitation on include levels.
     *
     * persistdir=persist_directory
     *	Name the directory to save persistent data from modules.
     *
     * In the following WORD is a sequence if non-white characters.
     * If ' " or ` is found in the string, all characters up to the
     * matching ' " or ` will also be included, even whitespace.
     * Every WORD will then be expanded w.r.t. meta-characters.
     * If the expanded result gives more than one word, then only
     * the first word of the result will be used.
     *
     *
     * define CODE WORD
     *		Do a putenv("CODE=WORD")
     *
     * EXPRESSION below can be:
     *	WORD compare_op WORD
     *		where compare_op is one of == != < <= >= >
     *		The string values of the WORDs are compared
     * or
     *	-n WORD compare_op WORD
     *		where compare_op is one of == != < <= >= >
     *		The numeric values of the WORDs are compared
     * or
     *	WORD
     *		if the expansion of WORD fails, or if the
     *		expansion is "0" (zero), "false" or "" (empty)
     *		then the expansion has the value FALSE.
     *		Otherwise the expansion has the value TRUE
     * or
     *	-f FILENAME
     *		Test if the file FILENAME exists
     * or
     *	-k
     *		Test if "autoclean" (i.e. called from the kernel)
     * or
     *	! EXPRESSION
     *		A negated expression is also an expression
     *
     * if EXPRESSION
     *	any config line
     *	...
     * elseif EXPRESSION
     *	any config line
     *	...
     * else
     *	any config line
     *	...
     * endif
     *
     * The else and elseif keywords are optional.
     * "if"-statements nest up to 20 levels.
     */

    state[0] = 1;

    if (force_ver)
        version = force_ver;
    else
        version = uts_info.release;

    config_version = xstrdup(version);

    /* Only read the default entries on the first file */
    if (depth == 0) {
        maxpath = 100;
        modpath = (struct PATH_TYPE *)xmalloc(maxpath * sizeof(struct PATH_TYPE));
        nmodpath = 0;

        maxexecs = 10;
        execs = (struct EXEC_TYPE *)xmalloc(maxexecs * sizeof(struct EXEC_TYPE));
        nexecs = 0;

        /*
         * Build predef options
         */
        if (all && optlist[0])
            n_opt_list = build_list(optlist, &opt_list, version, 1);

        /*
         * Build predef above
         */
        if (all && above[0])
            n_abovelist = build_list(above, &abovelist, version, 0);

        /*
         * Build predef below
         */
        if (all && below[0])
            n_belowlist = build_list(below, &belowlist, version, 0);

        /*
         * Build predef prune list
         */
        if (prune[0])
            n_prunelist = build_list(prune, &prunelist, version, 0);

        /*
         * Build predef aliases
         */
        if (all && aliaslist[0])
            n_aliases = build_list(aliaslist, &aliases, version, 0);

        /* Order and priority is now: (MODPATH + modules.conf) || (predefs + modules.conf) */
        if ((envpath = getenv("MODPATH")) != NULL && !safemode) {
            size_t len;
            char *p;
            char *path;

            /* Make a copy so's we can mung it with strtok.  */
            len = strlen(envpath) + 1;
            p = alloca(len);
            memcpy(p, envpath, len);
            path = alloca(PATH_MAX);

            for (p = strtok(p, ":"); p != NULL; p = strtok(NULL, ":")) {
                len = snprintf(path, PATH_MAX, p, version);
                modpath[nmodpath].path = xstrdup(path);
                if ((type = strrchr(path, '/')) != NULL)
                    type += 1;
                else
                    type = "misc";
                modpath[nmodpath].type = xstrdup(type);
                if (++nmodpath >= maxpath) {
                    maxpath += 100;
                    modpath = (struct PATH_TYPE *)xrealloc(modpath,
                                                           maxpath * sizeof(struct PATH_TYPE));
                }

            }
        } else {
            /*
             * Build the default "path[type]" configuration
             */
            int n;
            char *k;

            /* The first entry in the path list */
            modpath[nmodpath].type = xstrdup("boot");
            snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/boot", base_dir);
            modpath[nmodpath].path = xstrdup(tmpline);
            ++nmodpath;

            /* The second entry in the path list, `uname -r` */
            modpath[nmodpath].type = xstrdup("toplevel");
            snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%s", base_dir, version);
            modpath[nmodpath].path = xstrdup(tmpline);
            ++nmodpath;

            /* The third entry in the path list, `kernelversion` */
            modpath[nmodpath].type = xstrdup("toplevel");
            for (n = 0, k = version; *k; ++k) {
                if (*k == '.' && ++n == 2)
                    break;
            }
            snprintf(tmpline, sizeof(tmpline), "%s/lib/modules/%.*s", base_dir,
                     (/* typecast for Alpha */ int)(k - version), version);
            modpath[nmodpath].path = xstrdup(tmpline);
            ++nmodpath;

            /* The rest of the entries in the path list */
            for (pathp = tbpath; *pathp; ++pathp) {
                char **type;

                for (type = tbtype; *type; ++type) {
                    char path[PATH_MAX];

                    snprintf(path, sizeof(path), "%s%s/%s", base_dir, *pathp, *type);
                    if (meta_expand(path, &g, NULL, version, ME_ALL)) {
                        ret = -1;
                        goto out;
                    }

                    for (glb = g.pathv; glb && *glb; ++glb) {
                        modpath[nmodpath].type = xstrdup(*type);
                        modpath[nmodpath].path = *glb;
                        if (++nmodpath >= maxpath) {
                            maxpath += 100;
                            modpath = (struct PATH_TYPE *)xrealloc(modpath,
                                                                   maxpath * sizeof(struct PATH_TYPE));
                        }
                    }
                }
            }
        }

        /* Environment overrides for testing only, undocumented */
        for (i = 0; i < gen_file_count; ++i)
            gen_file_env(gen_file+i);

    }	/* End of depth == 0 */

    if (conf_file ||
            ((conf_file = getenv("MODULECONFIG")) != NULL && *conf_file && !safemode)) {
        if (!(fin = fopen(conf_file, "r"))) {
            error("Can't open %s", conf_file);
            ret = -1;
            goto out;
        }
        conf_file_specified = 1;
    } else {
        if (!(fin = fopen((conf_file = ETC_MODULES_CONF), "r"))) {
            /* Fall back to non-standard name */
            if ((fin = fopen((conf_file = old_name), "r"))) {
                fprintf(stderr,
                        "Warning: modutils is reading from %s because\n"
                        "         %s does not exist.  The use of %s is\n"
                        "         deprecated, please rename %s to %s\n"
                        "         as soon as possible.  Command\n"
                        "         mv %s %s\n",
                        old_name, ETC_MODULES_CONF,
                        old_name, old_name, ETC_MODULES_CONF,
                        old_name, ETC_MODULES_CONF);
            }
            /* So what... use the default configuration */
        }
    }

    if (fin) {
        struct stat statbuf1, statbuf2;
        if (fstat(fileno(fin), &statbuf1) == 0)
            config_mtime = statbuf1.st_mtime;
        config_file = xstrdup(conf_file);	/* Save name actually used */
        if (!conf_file_specified &&
                stat(ETC_MODULES_CONF, &statbuf1) == 0 &&
                stat(old_name, &statbuf2) == 0) {
            /* Both /etc files exist */
            if (statbuf1.st_dev == statbuf2.st_dev &&
                    statbuf1.st_ino == statbuf2.st_ino) {
                if (lstat(ETC_MODULES_CONF, &statbuf1) == 0 &&
                        S_ISLNK(statbuf1.st_mode))
                    fprintf(stderr,
                            "Warning: You do not need a link from %s to\n"
                            "         %s.  The use of %s is deprecated,\n"
                            "         please remove %s and rename %s\n"
                            "         to %s as soon as possible.  Commands.\n"
                            "           rm %s\n"
                            "           mv %s %s\n",
                            ETC_MODULES_CONF, old_name,
                            old_name, ETC_MODULES_CONF, old_name, ETC_MODULES_CONF,
                            ETC_MODULES_CONF,
                            old_name, ETC_MODULES_CONF);
                else {
#ifndef NO_WARN_ON_OLD_LINK
                    fprintf(stderr,
                            "Warning: You do not need a link from %s to\n"
                            "         %s.  The use of %s is deprecated,\n"
                            "         please remove %s as soon as possible.  Command\n"
                            "           rm %s\n",
                            old_name, ETC_MODULES_CONF,
                            old_name, old_name,
                            old_name);
#endif
                }
            }
            else
                fprintf(stderr,
                        "Warning: modutils is reading from %s and\n"
                        "         ignoring %s.  The use of %s is deprecated,\n"
                        "         please remove %s as soon as possible.  Command\n"
                        "           rm %s\n",
                        ETC_MODULES_CONF, old_name,
                        old_name, old_name,
                        old_name);
        }
    }

    /*
     * Finally, decode the file
     */
    while (fin && fgets_strip(&buf, &sizebuf, fin, &lineno) != NULL) {
        char *arg2;
        char *parm = buf;
        char *arg;
        int one_err = 0;
        int adding;

        while (isspace(*parm))
            parm++;

        if (strncmp(parm, "add", 3) == 0) {
            adding = 1;
            parm += 3;
            while (isspace(*parm))
                parm++;
        } else
            adding = 0;

        arg = parm;

        if (*parm == '\0')
            continue;

        one_err = 1;

        while (*arg > ' ' && *arg != '=')
            arg++;

        if (*arg == '=')
            assgn = 1;
        else
            assgn = 0;
        *arg++ = '\0';
        while (isspace(*arg))
            arg++;

        /*
         * endif
         */
        if (!assgn && strcmp(parm, "endif") == 0) {
            if (level > 0)
                --level;
            else {
                error("unmatched endif in line %d", lineno);
                ret = -1;
                goto out;
            }
            continue;
        }

        /*
         * else
         */
        if (!assgn && strcmp(parm, "else") == 0) {
            if (level <= 0) {
                error("else without if in line %d", lineno);
                ret = -1;
                goto out;
            }
            state[level] = !state[level];
            continue;
        }

        /*
         * elseif
         */
        if (!assgn && strcmp(parm, "elseif") == 0) {
            if (level <= 0) {
                error("elseif without if in line %d", lineno);
                ret = -1;
                goto out;
            }
            if (state[level] != 0) {
                /*
                 * We have already found a TRUE
                 * if statement in this "chain".
                 * That's what "2" means.
                 */
                state[level] = 2;
                continue;
            }
            /* else: No TRUE if has been found, cheat */
            /*
             * The "if" handling increments level,
             * but this is the _same_ level as before.
             * So, compensate for it.
             */
            --level;
            parm = "if";
            /* Fallthru to "if" */
        }

        /*
         * if
         */
        if (strcmp(parm, "if") == 0) {
            char *cmp;
            int not = 0;
            int numeric = 0;

            if (level >= MAX_LEVEL) {
                error("Too many nested if's in line %d\n", lineno);
                ret = -1;
                goto out;
            }
            state[++level] = 0; /* default false */

            if (*arg == '!') {
                not = 1;
                arg = next_word(arg);
            }

            if (strncmp(arg, "-k", 2) == 0) {
                state[level] = flag_autoclean;
                continue;
            }

            if (strncmp(arg, "-f", 2) == 0) {
                char *file = next_word(arg);
                meta_expand(file, &g, NULL, version, ME_ALL);
                if (access(g.pathc ? g.pathv[0] : file, R_OK) == 0)
                    state[level] = !not;
                else
                    state[level] = not;
                continue;
            }

            if (strncmp(arg, "-n", 2) == 0) {
                numeric = 1;
                arg = next_word(arg);
            }


            cmp = next_word(arg);
            if (*cmp) {
                GLOB_LIST g2;
                long n1 = 0;
                long n2 = 0;
                char *w1 = "";
                char *w2 = "";

                arg2 = next_word(cmp);

                meta_expand(arg, &g, NULL, version, ME_ALL);
                if (g.pathc && g.pathv[0])
                    w1 = g.pathv[0];

                meta_expand(arg2, &g2, NULL, version, ME_ALL);
                if (g2.pathc && g2.pathv[0])
                    w2 = g2.pathv[0];

                if (numeric) {
                    n1 = strtol(w1, NULL, 0);
                    n2 = strtol(w2, NULL, 0);
                }

                if (strcmp(cmp, "==") == 0 ||
                        strcmp(cmp, "=") == 0) {
                    if (numeric)
                        state[level] = (n1 == n2);
                    else
                        state[level] = strcmp(w1, w2) == 0;
                } else if (strcmp(cmp, "!=") == 0) {
                    if (numeric)
                        state[level] = (n1 != n2);
                    else
                        state[level] = strcmp(w1, w2) != 0;
                } else if (strcmp(cmp, ">=") == 0) {
                    if (numeric)
                        state[level] = (n1 >= n2);
                    else
                        state[level] = strcmp(w1, w2) >= 0;
                } else if (strcmp(cmp, "<=") == 0) {
                    if (numeric)
                        state[level] = (n1 <= n2);
                    else
                        state[level] = strcmp(w1, w2) <= 0;
                } else if (strcmp(cmp, ">") == 0) {
                    if (numeric)
                        state[level] = (n1 > n2);
                    else
                        state[level] = strcmp(w1, w2) > 0;
                } else if (strcmp(cmp, "<") == 0) {
                    if (numeric)
                        state[level] = (n1 < n2);
                    else
                        state[level] = strcmp(w1, w2) < 0;
                }
            } else { /* Check defined value, if any */
                /* undef or defined as
                 *	"" or "0" or "false" => false
                 *  defined => true
                 */
                if (!meta_expand(arg, &g, NULL, version, ME_ALL) &&
                        g.pathc > 0 &&
                        strcmp(g.pathv[0], "0") != 0 &&
                        strcmp(g.pathv[0], "false") != 0 &&
                        strlen(g.pathv[0]) != 0)
                    state[level] = 1; /* true */
            }
            if (not)
                state[level] = !state[level];

            continue;
        }

        /*
         * Should we bother?
         */
        if (state[level] != 1)
            continue;

        /*
         * define
         */
        if (!assgn && strcmp(parm, "define") == 0) {
            char env[PATH_MAX];

            arg2 = next_word(arg);
            meta_expand(arg2, &g, NULL, version, ME_ALL);
            snprintf(env, sizeof(env), "%s=%s", arg, (g.pathc ? g.pathv[0] : ""));
            putenv(xstrdup(env));
            one_err = 0;
        }

        /*
         * include
         */
        if (!assgn && strcmp(parm, "include") == 0) {
            int inc_idx = 0;

            while (*arg) {
                arg2=next_word(arg);
                meta_expand(arg, &g, NULL, version, ME_ALL);

                if (g.pathc>0) {
                    for ( ; inc_idx<g.pathc; inc_idx++) {
                        if (!do_read(all, version, base_dir, g.pathv[inc_idx], depth+1))
                            one_err = 0;
                        else
                            error("include %s failed\n", g.pathv[inc_idx]);
                    }
                }
                else {
                    if (!do_read(all, version, base_dir, g.pathc ? g.pathv[0] : arg, depth+1))
                        one_err = 0;
                    else
                        error("include %s failed\n", arg);
                }

                arg = arg2;
            }
        }

        /*
         * above
         */
        else if (all && !assgn && strcmp(parm, "above") == 0) {
            decode_list(&n_abovelist, &abovelist, arg, adding, version, 0);
            one_err = 0;
        }

        /*
         * below
         */
        else if (all && !assgn && strcmp(parm, "below") == 0) {
            decode_list(&n_belowlist, &belowlist, arg, adding, version, 0);
            one_err = 0;
        }

        /*
         * prune
         */
        else if (!assgn && strcmp(parm, "prune") == 0) {
            decode_list(&n_prunelist, &prunelist, arg, adding, version, 0);
            one_err = 0;
        }

        /*
         * probe
         */
        else if (all && !assgn && strcmp(parm, "probe") == 0) {
            decode_list(&n_probe_list, &probe_list, arg, adding, version, 0);
            one_err = 0;
        }

        /*
         * probeall
         */
        else if (all && !assgn && strcmp(parm, "probeall") == 0) {
            decode_list(&n_probeall_list, &probeall_list, arg, adding, version, 0);
            one_err = 0;
        }

        /*
         * options
         */
        else if (all && !assgn && strcmp(parm, "options") == 0) {
            decode_list(&n_opt_list, &opt_list, arg, adding, version, 1);
            one_err = 0;
        }

        /*
         * alias
         */
        else if (all && !assgn && strcmp(parm, "alias") == 0) {
            /*
             * Replace any previous (default) definitions
             * for the same module
             */
            decode_list(&n_aliases, &aliases, arg, 0, version, 0);
            one_err = 0;
        }

        /*
         * Specification: /etc/modules.conf
         * The format of the commands in /etc/modules.conf are:
         *
         *	pre-install module command
         *	install module command
         *	post-install module command
         *	pre-remove module command
         *	remove module command
         *	post-remove module command
         *
         * The different words are separated by tabs or spaces.
         */
        /*
         * pre-install
         */
        else if (all && !assgn && (strcmp(parm, "pre-install") == 0)) {
            decode_exec(arg, EXEC_PRE_INSTALL);
            one_err = 0;
        }

        /*
         * install
         */
        else if (all && !assgn && (strcmp(parm, "install") == 0)) {
            decode_exec(arg, EXEC_INSTALL);
            one_err = 0;
        }

        /*
         * post-install
         */
        else if (all && !assgn && (strcmp(parm, "post-install") == 0)) {
            decode_exec(arg, EXEC_POST_INSTALL);
            one_err = 0;
        }

        /*
         * pre-remove
         */
        else if (all && !assgn && (strcmp(parm, "pre-remove") == 0)) {
            decode_exec(arg, EXEC_PRE_REMOVE);
            one_err = 0;
        }

        /*
         * remove
         */
        else if (all && !assgn && (strcmp(parm, "remove") == 0)) {
            decode_exec(arg, EXEC_REMOVE);
            one_err = 0;
        }

        /*
         * post-remove
         */
        else if (all && !assgn && (strcmp(parm, "post-remove") == 0)) {
            decode_exec(arg, EXEC_POST_REMOVE);
            one_err = 0;
        }

        /*
         * insmod_opt=
         */
        else if (assgn && (strcmp(parm, "insmod_opt") == 0)) {
            insmod_opt = xstrdup(arg);
            one_err = 0;
        }

        /*
         * keep
         */
        else if (!assgn && (strcmp(parm, "keep") == 0)) {
            drop_default_paths = 0;
            one_err = 0;
        }

        /*
         * path...=
         */
        else if (assgn && strncmp(parm, "path", 4) == 0) {
            /*
             * Specification: config file / path parameter
             * The path parameter specifies a directory to
             * search for modules.
             * This parameter may be repeated multiple times.
             *
             * Note that the actual path may be defined using
             * wildcards and other shell meta-chars, such as "*?`".
             * For example:
             *      path[misc]=/lib/modules/1.1.5?/misc
             *
             * Optionally the path keyword carries a tag.
             * This tells us a little more about the purpose of
             * this directory and allows some automated operations.
             * A path is marked with a tag by adding the tag,
             * enclosed in square brackets, to the path keyword:
             * #
             * path[boot]=/lib/modules/boot
             * #
             * This case identifies the path a of directory
             * holding modules loadable a boot time.
             */

            if (drop_default_paths) {
                int n;

                /*
                 * Specification: config file / path / default
                 *
                 * Whenever there is a path[] specification
                 * in the config file, all the default
                 * path are reset.
                 *
                 * If one instead wants to _add_ to the default
                 * set of paths, one has to have the option
                 *    keep
                 * before the first path[]-specification line
                 * in the configuration file.
                 */
                drop_default_paths = 0;
                for (n = 0; n < nmodpath; n++) {
                    free(modpath[n].path);
                    free(modpath[n].type);
                }
                nmodpath = 0;
            }

            /*
             * Get (the optional) tag
             * If the tag is missing, the word "misc"
             * is assumed.
             */
            type = "misc";

            if (parm[4] == '[') {
                char *pt_type = parm + 5;

                while (*pt_type != '\0' && *pt_type != ']')
                    pt_type++;

                if (*pt_type == ']' && pt_type[1] == '\0') {
                    *pt_type = '\0';
                    type = parm + 5;
                } /* else CHECKME */
            }

            /*
             * Handle the actual path description
             */
            if (meta_expand(arg, &g, base_dir, version, ME_ALL)) {
                ret = -1;
                goto out;
            }
            for (glb = g.pathv; glb && *glb; ++glb) {
                modpath[nmodpath].type = xstrdup(type);
                modpath[nmodpath].path = *glb;
                if (++nmodpath >= maxpath) {
                    maxpath += 100;
                    modpath = (struct PATH_TYPE *)xrealloc(modpath,
                                                           maxpath * sizeof(struct PATH_TYPE));
                }
            }
            one_err = 0;
        }

        /*
         * persistdir
         */
        else if (assgn && strcmp(parm, "persistdir") == 0) {
            meta_expand(arg, &g, NULL, version, ME_ALL);
            persistdir = xstrdup(g.pathc ? g.pathv[0] : arg);
            one_err = 0;
        }

        /* Names for generated files in config file */
        for (i = 0; one_err && i < gen_file_count; ++i)
            one_err = gen_file_conf(gen_file+i, assgn, parm, arg);

        /*
         * any errors so far?
         */
        if (all == 0)
            one_err = 0;
        else if (one_err) {
            error("Invalid line %d in %s\n\t%s",
                  lineno, conf_file, buf);
            ret = -1;
        }
    }
    if (fin)
        fclose(fin);

    if (level) {
        error("missing endif at %s EOF", conf_file);
        ret = -1;
    }

    if (ret)
        goto out;
    /* else */

    if (depth == 0) {
        /* Check we have names for generated files */
        for (i = 0; !ret && i < gen_file_count; ++i)
            ret = gen_file_check(gen_file+i, &g, base_dir, version);
    }

out:
    return ret;
}