Index: head/stand/common/boot.c =================================================================== --- head/stand/common/boot.c (revision 329018) +++ head/stand/common/boot.c (revision 329019) @@ -1,415 +1,415 @@ /*- * Copyright (c) 1998 Michael Smith * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * Loading modules, booting the system */ #include #include #include "bootstrap.h" static char *getbootfile(int try); static int loadakernel(int try, int argc, char* argv[]); /* List of kernel names to try (may be overwritten by boot.config) XXX should move from here? */ static const char *default_bootfiles = "kernel"; static int autoboot_tried; /* * The user wants us to boot. */ COMMAND_SET(boot, "boot", "boot a file or loaded kernel", command_boot); static int command_boot(int argc, char *argv[]) { - struct preloaded_file *fp; + struct preloaded_file *fp; - /* - * See if the user has specified an explicit kernel to boot. - */ - if ((argc > 1) && (argv[1][0] != '-')) { + /* + * See if the user has specified an explicit kernel to boot. + */ + if ((argc > 1) && (argv[1][0] != '-')) { - /* XXX maybe we should discard everything and start again? */ - if (file_findfile(NULL, NULL) != NULL) { - snprintf(command_errbuf, sizeof(command_errbuf), - "can't boot '%s', kernel module already loaded", argv[1]); - return(CMD_ERROR); + /* XXX maybe we should discard everything and start again? */ + if (file_findfile(NULL, NULL) != NULL) { + snprintf(command_errbuf, sizeof(command_errbuf), + "can't boot '%s', kernel module already loaded", argv[1]); + return(CMD_ERROR); + } + + /* find/load the kernel module */ + if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0) + return(CMD_ERROR); + /* we have consumed all arguments */ + argc = 1; } - /* find/load the kernel module */ - if (mod_loadkld(argv[1], argc - 2, argv + 2) != 0) - return(CMD_ERROR); - /* we have consumed all arguments */ - argc = 1; - } + /* + * See if there is a kernel module already loaded + */ + if (file_findfile(NULL, NULL) == NULL) + if (loadakernel(0, argc - 1, argv + 1)) + /* we have consumed all arguments */ + argc = 1; - /* - * See if there is a kernel module already loaded - */ - if (file_findfile(NULL, NULL) == NULL) - if (loadakernel(0, argc - 1, argv + 1)) - /* we have consumed all arguments */ - argc = 1; + /* + * Loaded anything yet? + */ + if ((fp = file_findfile(NULL, NULL)) == NULL) { + command_errmsg = "no bootable kernel"; + return(CMD_ERROR); + } - /* - * Loaded anything yet? - */ - if ((fp = file_findfile(NULL, NULL)) == NULL) { - command_errmsg = "no bootable kernel"; - return(CMD_ERROR); - } + /* + * If we were given arguments, discard any previous. + * XXX should we merge arguments? Hard to DWIM. + */ + if (argc > 1) { + if (fp->f_args != NULL) + free(fp->f_args); + fp->f_args = unargv(argc - 1, argv + 1); + } - /* - * If we were given arguments, discard any previous. - * XXX should we merge arguments? Hard to DWIM. - */ - if (argc > 1) { - if (fp->f_args != NULL) - free(fp->f_args); - fp->f_args = unargv(argc - 1, argv + 1); - } + /* Hook for platform-specific autoloading of modules */ + if (archsw.arch_autoload() != 0) + return(CMD_ERROR); - /* Hook for platform-specific autoloading of modules */ - if (archsw.arch_autoload() != 0) + /* Call the exec handler from the loader matching the kernel */ + file_formats[fp->f_loader]->l_exec(fp); return(CMD_ERROR); - - /* Call the exec handler from the loader matching the kernel */ - file_formats[fp->f_loader]->l_exec(fp); - return(CMD_ERROR); } /* * Autoboot after a delay */ COMMAND_SET(autoboot, "autoboot", "boot automatically after a delay", command_autoboot); static int command_autoboot(int argc, char *argv[]) { - int howlong; - char *cp, *prompt; + int howlong; + char *cp, *prompt; - prompt = NULL; - howlong = -1; - switch(argc) { - case 3: - prompt = argv[2]; - /* FALLTHROUGH */ - case 2: - howlong = strtol(argv[1], &cp, 0); - if (*cp != 0) { - snprintf(command_errbuf, sizeof(command_errbuf), - "bad delay '%s'", argv[1]); - return(CMD_ERROR); + prompt = NULL; + howlong = -1; + switch(argc) { + case 3: + prompt = argv[2]; + /* FALLTHROUGH */ + case 2: + howlong = strtol(argv[1], &cp, 0); + if (*cp != 0) { + snprintf(command_errbuf, sizeof(command_errbuf), + "bad delay '%s'", argv[1]); + return(CMD_ERROR); + } + /* FALLTHROUGH */ + case 1: + return(autoboot(howlong, prompt)); } - /* FALLTHROUGH */ - case 1: - return(autoboot(howlong, prompt)); - } - command_errmsg = "too many arguments"; - return(CMD_ERROR); + command_errmsg = "too many arguments"; + return(CMD_ERROR); } /* * Called before we go interactive. If we think we can autoboot, and * we haven't tried already, try now. */ void autoboot_maybe() { - char *cp; + char *cp; - cp = getenv("autoboot_delay"); - if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO"))) - autoboot(-1, NULL); /* try to boot automatically */ + cp = getenv("autoboot_delay"); + if ((autoboot_tried == 0) && ((cp == NULL) || strcasecmp(cp, "NO"))) + autoboot(-1, NULL); /* try to boot automatically */ } int autoboot(int timeout, char *prompt) { - time_t when, otime, ntime; - int c, yes; - char *argv[2], *cp, *ep; - char *kernelname; + time_t when, otime, ntime; + int c, yes; + char *argv[2], *cp, *ep; + char *kernelname; #ifdef BOOT_PROMPT_123 - const char *seq = "123", *p = seq; + const char *seq = "123", *p = seq; #endif - autoboot_tried = 1; + autoboot_tried = 1; - if (timeout == -1) { - timeout = 10; - /* try to get a delay from the environment */ - if ((cp = getenv("autoboot_delay"))) { - timeout = strtol(cp, &ep, 0); - if (cp == ep) - timeout = 10; /* Unparseable? Set default! */ + if (timeout == -1) { + timeout = 10; + /* try to get a delay from the environment */ + if ((cp = getenv("autoboot_delay"))) { + timeout = strtol(cp, &ep, 0); + if (cp == ep) + timeout = 10; /* Unparseable? Set default! */ + } } - } - kernelname = getenv("kernelname"); - if (kernelname == NULL) { - argv[0] = NULL; - loadakernel(0, 0, argv); kernelname = getenv("kernelname"); if (kernelname == NULL) { - command_errmsg = "no valid kernel found"; - return(CMD_ERROR); + argv[0] = NULL; + loadakernel(0, 0, argv); + kernelname = getenv("kernelname"); + if (kernelname == NULL) { + command_errmsg = "no valid kernel found"; + return(CMD_ERROR); + } } - } - if (timeout >= 0) { - otime = time(NULL); - when = otime + timeout; /* when to boot */ + if (timeout >= 0) { + otime = time(NULL); + when = otime + timeout; /* when to boot */ - yes = 0; + yes = 0; #ifdef BOOT_PROMPT_123 - printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or " - "1 2 3 sequence for command prompt." : prompt); + printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or " + "1 2 3 sequence for command prompt." : prompt); #else - printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt); + printf("%s\n", (prompt == NULL) ? "Hit [Enter] to boot immediately, or any other key for command prompt." : prompt); #endif - for (;;) { - if (ischar()) { - c = getchar(); + for (;;) { + if (ischar()) { + c = getchar(); #ifdef BOOT_PROMPT_123 - if ((c == '\r') || (c == '\n')) { - yes = 1; - break; - } else if (c != *p++) - p = seq; - if (*p == 0) - break; + if ((c == '\r') || (c == '\n')) { + yes = 1; + break; + } else if (c != *p++) + p = seq; + if (*p == 0) + break; #else - if ((c == '\r') || (c == '\n')) - yes = 1; - break; + if ((c == '\r') || (c == '\n')) + yes = 1; + break; #endif - } - ntime = time(NULL); - if (ntime >= when) { - yes = 1; - break; - } + } + ntime = time(NULL); + if (ntime >= when) { + yes = 1; + break; + } - if (ntime != otime) { - printf("\rBooting [%s] in %d second%s... ", - kernelname, (int)(when - ntime), - (when-ntime)==1?"":"s"); - otime = ntime; - } - } - } else { - yes = 1; - } + if (ntime != otime) { + printf("\rBooting [%s] in %d second%s... ", + kernelname, (int)(when - ntime), + (when-ntime)==1?"":"s"); + otime = ntime; + } + } + } else { + yes = 1; + } - if (yes) - printf("\rBooting [%s]... ", kernelname); - putchar('\n'); - if (yes) { - argv[0] = "boot"; - argv[1] = NULL; - return(command_boot(1, argv)); - } - return(CMD_OK); + if (yes) + printf("\rBooting [%s]... ", kernelname); + putchar('\n'); + if (yes) { + argv[0] = "boot"; + argv[1] = NULL; + return(command_boot(1, argv)); + } + return(CMD_OK); } /* * Scrounge for the name of the (try)'th file we will try to boot. */ static char * getbootfile(int try) { - static char *name = NULL; - const char *spec, *ep; - size_t len; + static char *name = NULL; + const char *spec, *ep; + size_t len; - /* we use dynamic storage */ - if (name != NULL) { - free(name); - name = NULL; - } + /* we use dynamic storage */ + if (name != NULL) { + free(name); + name = NULL; + } - /* - * Try $bootfile, then try our builtin default - */ - if ((spec = getenv("bootfile")) == NULL) - spec = default_bootfiles; + /* + * Try $bootfile, then try our builtin default + */ + if ((spec = getenv("bootfile")) == NULL) + spec = default_bootfiles; - while ((try > 0) && (spec != NULL)) { - spec = strchr(spec, ';'); - if (spec) - spec++; /* skip over the leading ';' */ - try--; - } - if (spec != NULL) { - if ((ep = strchr(spec, ';')) != NULL) { - len = ep - spec; - } else { - len = strlen(spec); + while ((try > 0) && (spec != NULL)) { + spec = strchr(spec, ';'); + if (spec) + spec++; /* skip over the leading ';' */ + try--; } - name = malloc(len + 1); - strncpy(name, spec, len); - name[len] = 0; - } - if (name && name[0] == 0) { - free(name); - name = NULL; - } - return(name); + if (spec != NULL) { + if ((ep = strchr(spec, ';')) != NULL) { + len = ep - spec; + } else { + len = strlen(spec); + } + name = malloc(len + 1); + strncpy(name, spec, len); + name[len] = 0; + } + if (name && name[0] == 0) { + free(name); + name = NULL; + } + return(name); } /* * Try to find the /etc/fstab file on the filesystem (rootdev), * which should be be the root filesystem, and parse it to find * out what the kernel ought to think the root filesystem is. * * If we're successful, set vfs.root.mountfrom to : * so that the kernel can tell both which VFS and which node to use * to mount the device. If this variable's already set, don't * overwrite it. */ int getrootmount(char *rootdev) { - char lbuf[128], *cp, *ep, *dev, *fstyp, *options; - int fd, error; + char lbuf[128], *cp, *ep, *dev, *fstyp, *options; + int fd, error; - if (getenv("vfs.root.mountfrom") != NULL) - return(0); + if (getenv("vfs.root.mountfrom") != NULL) + return(0); - error = 1; - sprintf(lbuf, "%s/etc/fstab", rootdev); - if ((fd = open(lbuf, O_RDONLY)) < 0) - goto notfound; + error = 1; + sprintf(lbuf, "%s/etc/fstab", rootdev); + if ((fd = open(lbuf, O_RDONLY)) < 0) + goto notfound; - /* loop reading lines from /etc/fstab What was that about sscanf again? */ - fstyp = NULL; - dev = NULL; - while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) { - if ((lbuf[0] == 0) || (lbuf[0] == '#')) - continue; + /* loop reading lines from /etc/fstab What was that about sscanf again? */ + fstyp = NULL; + dev = NULL; + while (fgetstr(lbuf, sizeof(lbuf), fd) >= 0) { + if ((lbuf[0] == 0) || (lbuf[0] == '#')) + continue; - /* skip device name */ - for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) - ; - if (*cp == 0) /* misformatted */ - continue; - /* delimit and save */ - *cp++ = 0; - free(dev); - dev = strdup(lbuf); + /* skip device name */ + for (cp = lbuf; (*cp != 0) && !isspace(*cp); cp++) + ; + if (*cp == 0) /* misformatted */ + continue; + /* delimit and save */ + *cp++ = 0; + free(dev); + dev = strdup(lbuf); - /* skip whitespace up to mountpoint */ - while ((*cp != 0) && isspace(*cp)) - cp++; - /* must have / to be root */ - if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1))) - continue; - /* skip whitespace up to fstype */ - cp += 2; - while ((*cp != 0) && isspace(*cp)) - cp++; - if (*cp == 0) /* misformatted */ - continue; - /* skip text to end of fstype and delimit */ - ep = cp; - while ((*cp != 0) && !isspace(*cp)) - cp++; - *cp = 0; - free(fstyp); - fstyp = strdup(ep); + /* skip whitespace up to mountpoint */ + while ((*cp != 0) && isspace(*cp)) + cp++; + /* must have / to be root */ + if ((*cp == 0) || (*cp != '/') || !isspace(*(cp + 1))) + continue; + /* skip whitespace up to fstype */ + cp += 2; + while ((*cp != 0) && isspace(*cp)) + cp++; + if (*cp == 0) /* misformatted */ + continue; + /* skip text to end of fstype and delimit */ + ep = cp; + while ((*cp != 0) && !isspace(*cp)) + cp++; + *cp = 0; + free(fstyp); + fstyp = strdup(ep); - /* skip whitespace up to mount options */ - cp += 1; - while ((*cp != 0) && isspace(*cp)) - cp++; - if (*cp == 0) /* misformatted */ - continue; - /* skip text to end of mount options and delimit */ - ep = cp; - while ((*cp != 0) && !isspace(*cp)) - cp++; - *cp = 0; - options = strdup(ep); - /* Build the : and save it in vfs.root.mountfrom */ - sprintf(lbuf, "%s:%s", fstyp, dev); - setenv("vfs.root.mountfrom", lbuf, 0); + /* skip whitespace up to mount options */ + cp += 1; + while ((*cp != 0) && isspace(*cp)) + cp++; + if (*cp == 0) /* misformatted */ + continue; + /* skip text to end of mount options and delimit */ + ep = cp; + while ((*cp != 0) && !isspace(*cp)) + cp++; + *cp = 0; + options = strdup(ep); + /* Build the : and save it in vfs.root.mountfrom */ + sprintf(lbuf, "%s:%s", fstyp, dev); + setenv("vfs.root.mountfrom", lbuf, 0); - /* Don't override vfs.root.mountfrom.options if it is already set */ - if (getenv("vfs.root.mountfrom.options") == NULL) { - /* save mount options */ - setenv("vfs.root.mountfrom.options", options, 0); + /* Don't override vfs.root.mountfrom.options if it is already set */ + if (getenv("vfs.root.mountfrom.options") == NULL) { + /* save mount options */ + setenv("vfs.root.mountfrom.options", options, 0); + } + free(options); + error = 0; + break; } - free(options); - error = 0; - break; - } - close(fd); - free(dev); - free(fstyp); + close(fd); + free(dev); + free(fstyp); notfound: - if (error) { - const char *currdev; + if (error) { + const char *currdev; - currdev = getenv("currdev"); - if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { - cp = strdup(currdev); - cp[strlen(cp) - 1] = '\0'; - setenv("vfs.root.mountfrom", cp, 0); - error = 0; - free(cp); + currdev = getenv("currdev"); + if (currdev != NULL && strncmp("zfs:", currdev, 4) == 0) { + cp = strdup(currdev); + cp[strlen(cp) - 1] = '\0'; + setenv("vfs.root.mountfrom", cp, 0); + error = 0; + free(cp); + } } - } - return(error); + return(error); } static int loadakernel(int try, int argc, char* argv[]) { - char *cp; + char *cp; for (try = 0; (cp = getbootfile(try)) != NULL; try++) - if (mod_loadkld(cp, argc - 1, argv + 1) != 0) - printf("can't load '%s'\n", cp); - else - return 1; + if (mod_loadkld(cp, argc - 1, argv + 1) != 0) + printf("can't load '%s'\n", cp); + else + return 1; return 0; } Index: head/stand/common/interp_backslash.c =================================================================== --- head/stand/common/interp_backslash.c (revision 329018) +++ head/stand/common/interp_backslash.c (revision 329019) @@ -1,167 +1,167 @@ /*- * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 29 August 1998 * * Routine for doing backslash elimination. */ #include __FBSDID("$FreeBSD$"); #include #include #include "bootstrap.h" #define DIGIT(x) (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A') /* * backslash: Return malloc'd copy of str with all standard "backslash * processing" done on it. Original can be free'd if desired. */ char * backslash(const char *str) { - /* - * Remove backslashes from the strings. Turn \040 etc. into a single - * character (we allow eight bit values). Currently NUL is not - * allowed. - * - * Turn "\n" and "\t" into '\n' and '\t' characters. Etc. - * - */ - char *new_str; - int seenbs = 0; - int i = 0; + /* + * Remove backslashes from the strings. Turn \040 etc. into a single + * character (we allow eight bit values). Currently NUL is not + * allowed. + * + * Turn "\n" and "\t" into '\n' and '\t' characters. Etc. + * + */ + char *new_str; + int seenbs = 0; + int i = 0; - if ((new_str = strdup(str)) == NULL) - return NULL; + if ((new_str = strdup(str)) == NULL) + return NULL; - while (*str) { - if (seenbs) { - seenbs = 0; - switch (*str) { - case '\\': - new_str[i++] = '\\'; - str++; - break; + while (*str) { + if (seenbs) { + seenbs = 0; + switch (*str) { + case '\\': + new_str[i++] = '\\'; + str++; + break; - /* preserve backslashed quotes, dollar signs */ - case '\'': - case '"': - case '$': - new_str[i++] = '\\'; - new_str[i++] = *str++; - break; + /* preserve backslashed quotes, dollar signs */ + case '\'': + case '"': + case '$': + new_str[i++] = '\\'; + new_str[i++] = *str++; + break; - case 'b': - new_str[i++] = '\b'; - str++; - break; + case 'b': + new_str[i++] = '\b'; + str++; + break; - case 'f': - new_str[i++] = '\f'; - str++; - break; + case 'f': + new_str[i++] = '\f'; + str++; + break; - case 'r': - new_str[i++] = '\r'; - str++; - break; + case 'r': + new_str[i++] = '\r'; + str++; + break; - case 'n': - new_str[i++] = '\n'; - str++; - break; + case 'n': + new_str[i++] = '\n'; + str++; + break; - case 's': - new_str[i++] = ' '; - str++; - break; + case 's': + new_str[i++] = ' '; + str++; + break; - case 't': - new_str[i++] = '\t'; - str++; - break; + case 't': + new_str[i++] = '\t'; + str++; + break; - case 'v': - new_str[i++] = '\13'; - str++; - break; + case 'v': + new_str[i++] = '\13'; + str++; + break; - case 'z': - str++; - break; + case 'z': + str++; + break; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': { - char val; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { + char val; - /* Three digit octal constant? */ - if (*str >= '0' && *str <= '3' && - *(str + 1) >= '0' && *(str + 1) <= '7' && - *(str + 2) >= '0' && *(str + 2) <= '7') { + /* Three digit octal constant? */ + if (*str >= '0' && *str <= '3' && + *(str + 1) >= '0' && *(str + 1) <= '7' && + *(str + 2) >= '0' && *(str + 2) <= '7') { - val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) + - DIGIT(*(str + 2)); + val = (DIGIT(*str) << 6) + (DIGIT(*(str + 1)) << 3) + + DIGIT(*(str + 2)); - /* Allow null value if user really wants to shoot - at feet, but beware! */ - new_str[i++] = val; - str += 3; - break; - } + /* Allow null value if user really wants to shoot + at feet, but beware! */ + new_str[i++] = val; + str += 3; + break; + } - /* One or two digit hex constant? - * If two are there they will both be taken. - * Use \z to split them up if this is not wanted. - */ - if (*str == '0' && - (*(str + 1) == 'x' || *(str + 1) == 'X') && - isxdigit(*(str + 2))) { - val = DIGIT(*(str + 2)); - if (isxdigit(*(str + 3))) { - val = (val << 4) + DIGIT(*(str + 3)); - str += 4; - } - else - str += 3; - /* Yep, allow null value here too */ - new_str[i++] = val; - break; - } - } - break; + /* One or two digit hex constant? + * If two are there they will both be taken. + * Use \z to split them up if this is not wanted. + */ + if (*str == '0' && + (*(str + 1) == 'x' || *(str + 1) == 'X') && + isxdigit(*(str + 2))) { + val = DIGIT(*(str + 2)); + if (isxdigit(*(str + 3))) { + val = (val << 4) + DIGIT(*(str + 3)); + str += 4; + } + else + str += 3; + /* Yep, allow null value here too */ + new_str[i++] = val; + break; + } + } + break; - default: - new_str[i++] = *str++; - break; - } + default: + new_str[i++] = *str++; + break; + } + } + else { + if (*str == '\\') { + seenbs = 1; + str++; + } + else + new_str[i++] = *str++; + } } - else { - if (*str == '\\') { - seenbs = 1; - str++; - } - else - new_str[i++] = *str++; - } - } - if (seenbs) { - /* - * The final character was a '\'. Put it in as a single backslash. - */ - new_str[i++] = '\\'; - } - new_str[i] = '\0'; - return new_str; + if (seenbs) { + /* + * The final character was a '\'. Put it in as a single backslash. + */ + new_str[i++] = '\\'; + } + new_str[i] = '\0'; + return new_str; } Index: head/stand/common/interp_parse.c =================================================================== --- head/stand/common/interp_parse.c (revision 329018) +++ head/stand/common/interp_parse.c (revision 329019) @@ -1,222 +1,227 @@ /*- * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Jordan K. Hubbard * 29 August 1998 * * The meat of the simple parser. */ #include __FBSDID("$FreeBSD$"); #include #include #include "bootstrap.h" static void clean(void); static int insert(int *argcp, char *buf); static char *variable_lookup(char *name); #define PARSE_BUFSIZE 1024 /* maximum size of one element */ #define MAXARGS 20 /* maximum number of elements */ static char *args[MAXARGS]; /* * parse: accept a string of input and "parse" it for backslash * substitutions and environment variable expansions (${var}), * returning an argc/argv style vector of whitespace separated * arguments. Returns 0 on success, 1 on failure (ok, ok, so I * wimped-out on the error codes! :). * * Note that the argv array returned must be freed by the caller, but * we own the space allocated for arguments and will free that on next * invocation. This allows argv consumers to modify the array if * required. * * NB: environment variables that expand to more than one whitespace * separated token will be returned as a single argv[] element, not * split in turn. Expanded text is also immune to further backslash * elimination or expansion since this is a one-pass, non-recursive * parser. You didn't specify more than this so if you want more, ask * me. - jkh */ #define PARSE_FAIL(expr) \ -if (expr) { \ - printf("fail at line %d\n", __LINE__); \ - clean(); \ - free(copy); \ - free(buf); \ - return 1; \ -} + if (expr) { \ + printf("fail at line %d\n", __LINE__); \ + clean(); \ + free(copy); \ + free(buf); \ + return 1; \ + } /* Accept the usual delimiters for a variable, returning counterpart */ static char isdelim(int ch) { - if (ch == '{') - return '}'; - else if (ch == '(') - return ')'; - return '\0'; + + if (ch == '{') + return '}'; + else if (ch == '(') + return ')'; + return '\0'; } static int isquote(int ch) { - return (ch == '\''); + + return (ch == '\''); } static int isdquote(int ch) { - return (ch == '"'); + + return (ch == '"'); } int parse(int *argc, char ***argv, const char *str) { - int ac; - char *val, *p, *q, *copy = NULL; - size_t i = 0; - char token, tmp, quote, dquote, *buf; - enum { STR, VAR, WHITE } state; + int ac; + char *val, *p, *q, *copy = NULL; + size_t i = 0; + char token, tmp, quote, dquote, *buf; + enum { STR, VAR, WHITE } state; - ac = *argc = 0; - dquote = quote = 0; - if (!str || (p = copy = backslash(str)) == NULL) - return 1; + ac = *argc = 0; + dquote = quote = 0; + if (!str || (p = copy = backslash(str)) == NULL) + return 1; - /* Initialize vector and state */ - clean(); - state = STR; - buf = (char *)malloc(PARSE_BUFSIZE); - token = 0; + /* Initialize vector and state */ + clean(); + state = STR; + buf = (char *)malloc(PARSE_BUFSIZE); + token = 0; - /* And awaaaaaaaaay we go! */ - while (*p) { - switch (state) { - case STR: - if ((*p == '\\') && p[1]) { - p++; - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } else if (isquote(*p)) { - quote = quote ? 0 : *p; - if (dquote) { /* keep quote */ - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } else - ++p; - } else if (isdquote(*p)) { - dquote = dquote ? 0 : *p; - if (quote) { /* keep dquote */ - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } else - ++p; - } else if (isspace(*p) && !quote && !dquote) { - state = WHITE; - if (i) { - buf[i] = '\0'; - PARSE_FAIL(insert(&ac, buf)); - i = 0; - } - ++p; - } else if (*p == '$' && !quote) { - token = isdelim(*(p + 1)); - if (token) - p += 2; - else - ++p; - state = VAR; - } else { - PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); - buf[i++] = *p++; - } - break; + /* And awaaaaaaaaay we go! */ + while (*p) { + switch (state) { + case STR: + if ((*p == '\\') && p[1]) { + p++; + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else if (isquote(*p)) { + quote = quote ? 0 : *p; + if (dquote) { /* keep quote */ + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else + ++p; + } else if (isdquote(*p)) { + dquote = dquote ? 0 : *p; + if (quote) { /* keep dquote */ + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } else + ++p; + } else if (isspace(*p) && !quote && !dquote) { + state = WHITE; + if (i) { + buf[i] = '\0'; + PARSE_FAIL(insert(&ac, buf)); + i = 0; + } + ++p; + } else if (*p == '$' && !quote) { + token = isdelim(*(p + 1)); + if (token) + p += 2; + else + ++p; + state = VAR; + } else { + PARSE_FAIL(i == (PARSE_BUFSIZE - 1)); + buf[i++] = *p++; + } + break; - case WHITE: - if (isspace(*p)) - ++p; - else - state = STR; - break; + case WHITE: + if (isspace(*p)) + ++p; + else + state = STR; + break; - case VAR: - if (token) { - PARSE_FAIL((q = strchr(p, token)) == NULL); - } else { - q = p; - while (*q && !isspace(*q)) - ++q; - } - tmp = *q; - *q = '\0'; - if ((val = variable_lookup(p)) != NULL) { - size_t len = strlen(val); + case VAR: + if (token) { + PARSE_FAIL((q = strchr(p, token)) == NULL); + } else { + q = p; + while (*q && !isspace(*q)) + ++q; + } + tmp = *q; + *q = '\0'; + if ((val = variable_lookup(p)) != NULL) { + size_t len = strlen(val); - strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1)); - i += min(len, PARSE_BUFSIZE - 1); - } - *q = tmp; /* restore value */ - p = q + (token ? 1 : 0); - state = STR; - break; + strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1)); + i += min(len, PARSE_BUFSIZE - 1); + } + *q = tmp; /* restore value */ + p = q + (token ? 1 : 0); + state = STR; + break; + } } - } - /* missing terminating ' or " */ - PARSE_FAIL(quote || dquote); - /* If at end of token, add it */ - if (i && state == STR) { - buf[i] = '\0'; - PARSE_FAIL(insert(&ac, buf)); - } - args[ac] = NULL; - *argc = ac; - *argv = (char **)malloc((sizeof(char *) * ac + 1)); - bcopy(args, *argv, sizeof(char *) * ac + 1); - free(buf); - free(copy); - return 0; + /* missing terminating ' or " */ + PARSE_FAIL(quote || dquote); + /* If at end of token, add it */ + if (i && state == STR) { + buf[i] = '\0'; + PARSE_FAIL(insert(&ac, buf)); + } + args[ac] = NULL; + *argc = ac; + *argv = (char **)malloc((sizeof(char *) * ac + 1)); + bcopy(args, *argv, sizeof(char *) * ac + 1); + free(buf); + free(copy); + return 0; } #define MAXARGS 20 /* Clean vector space */ static void clean(void) { - int i; + int i; - for (i = 0; i < MAXARGS; i++) { - if (args[i] != NULL) { - free(args[i]); - args[i] = NULL; + for (i = 0; i < MAXARGS; i++) { + if (args[i] != NULL) { + free(args[i]); + args[i] = NULL; + } } - } } static int insert(int *argcp, char *buf) { - if (*argcp >= MAXARGS) - return 1; - args[(*argcp)++] = strdup(buf); - return 0; + + if (*argcp >= MAXARGS) + return 1; + args[(*argcp)++] = strdup(buf); + return 0; } static char * variable_lookup(char *name) { - /* XXX search "special variable" space first? */ - return (char *)getenv(name); + + /* XXX search "special variable" space first? */ + return (char *)getenv(name); }