afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * All rights reserved.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Redistribution and use in source and binary forms, with or without
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * modification, are permitted provided that the following conditions
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * 1. Redistributions of source code must retain the above copyright
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * notice, this list of conditions and the following disclaimer.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * notice, this list of conditions and the following disclaimer in the
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * documentation and/or other materials provided with the distribution.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * SUCH DAMAGE.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome/* Commands and return values; nonzero return sets command_errmsg != NULL */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soometypedef int (bootblk_cmd_t)(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Support for commands
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome uchar_t *d_hints; /* content of linker.hints file */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic STAILQ_HEAD(, moduledir) moduledir_list =
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic const char *default_searchpath = "/platform/i86pc";
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomeextern char **_environ;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomeextern void pager_open(void);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomeextern void pager_close(void);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomeextern int pager_output(const char *);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomeextern int pager_file(const char *);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int page_file(char *);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int include(const char *);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_help(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_commandlist(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_show(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_setprop(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_unset(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_echo(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_read(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_more(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_include(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_autoboot(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_boot(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_unload(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_load(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic int command_reboot(int argc, char *argv[]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome/* update when loader version will change */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * BootForth Interface to Ficl Forth interpreter.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Redistribution and use in source and binary forms, with or without
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * modification, are permitted provided that the following conditions
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * 1. Redistributions of source code must retain the above copyright
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * notice, this list of conditions and the following disclaimer.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * 2. Redistributions in binary form must reproduce the above copyright
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * notice, this list of conditions and the following disclaimer in the
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * documentation and/or other materials provided with the distribution.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Jordan K. Hubbard
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * 29 August 1998
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * The meat of the simple parser.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic void clean(void);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome#define PARSE_BUFSIZE 1024 /* maximum size of one element */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome#define MAXARGS 20 /* maximum number of elements */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome (isdigit(x) ? (x) - '0' : islower(x) ? (x) + 10 - 'a' : (x) + 10 - 'A')
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * backslash: Return malloc'd copy of str with all standard "backslash
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * processing" done on it. Original can be free'd if desired.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Remove backslashes from the strings. Turn \040 etc. into a single
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * character (we allow eight bit values). Currently NUL is not
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Turn "\n" and "\t" into '\n' and '\t' characters. Etc.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* preserve backslashed quotes, dollar signs */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome case '0': case '1': case '2': case '3': case '4':
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome case '5': case '6': case '7': case '8': case '9': {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Three digit octal constant? */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Allow null value if user really
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * wants to shoot at feet, but beware!
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * One or two digit hex constant?
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * If two are there they will both be taken.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Use \z to split them up if this is not
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Yep, allow null value here too */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * The final character was a '\'.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Put it in as a single backslash.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * parse: accept a string of input and "parse" it for backslash
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * substitutions and environment variable expansions (${var}),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * returning an argc/argv style vector of whitespace separated
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * arguments. Returns 0 on success, 1 on failure (ok, ok, so I
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * wimped-out on the error codes! :).
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Note that the argv array returned must be freed by the caller, but
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * we own the space allocated for arguments and will free that on next
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * invocation. This allows argv consumers to modify the array if
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * NB: environment variables that expand to more than one whitespace
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * separated token will be returned as a single argv[] element, not
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * split in turn. Expanded text is also immune to further backslash
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * elimination or expansion since this is a one-pass, non-recursive
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * parser. You didn't specify more than this so if you want more, ask
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return (1); \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome/* Accept the usual delimiters for a variable, returning counterpart */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return ('}');
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return (')');
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return ('\0');
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if (!str || (p = copy = backslash(str)) == NULL)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Initialize vector and state */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* And awaaaaaaaaay we go! */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome while (*p) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome buf[i++] = *p++;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome } else if (isquote(*p)) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome buf[i++] = *p++;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome } else if (isdquote(*p)) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome buf[i++] = *p++;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome buf[i++] = *p++;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome while (*q && !isspace(*q))
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome strncpy(buf + i, val, PARSE_BUFSIZE - (i + 1));
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* missing terminating ' or " */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* If at end of token, add it */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome *argv = (char **)malloc((sizeof (char *) * ac + 1));
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome/* Clean vector space */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (i = 0; i < MAXARGS; i++) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic char *
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome ret = sysinfo(SI_ARCHITECTURE_K, buf, bufsize);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Shim for taking commands from BF and passing them out to 'standard'
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * argv/argc command functions.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Get the name of the current word */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Find our command structure */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if ((cmdp->c_name != NULL) && strcmp(name, cmdp->c_name) == 0)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome printf("callout for unknown command '%s'\n", name);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Check whether we have been compiled or are being interpreted */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if (ficlStackPopInteger(ficlVmGetDataStack(vm))) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Get parameters from stack, in the format:
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * an un ... a2 u2 a1 u1 n --
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Where n is the number of strings, a/u are pairs of
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * address/size for strings, and they will be concatenated
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * in LIFO order.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome nstrings = ficlStackPopInteger(ficlVmGetDataStack(vm));
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome len += ficlStackFetch(ficlVmGetDataStack(vm), i * 2).i + 1;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (i = 0; i < nstrings; i++) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Get remainder of invocation */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome cp != vm->tib.end && *cp != 0 && *cp != '\n'; cp++, len++)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * If there was error during nested ficlExec(), we may no longer have
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * valid environment to return. Throw all exceptions from here.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* This is going to be thrown!!! */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome ficlStackPushInteger(ficlVmGetDataStack(vm), result);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic char *
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* do the best we can to return something... */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome (void) asprintf(&currdev, "zfs:%s:", mp.mnt_special);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Replace a word definition (a builtin command) with another
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * - Throw error results instead of returning them on the stack
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * - Pass a flag indicating whether the word was compiled or is
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * being interpreted.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * There is one major problem with builtins that cannot be overcome
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * in anyway, except by outlawing it. We want builtins to behave
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * differently depending on whether they have been compiled or they
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * are being interpreted. Notice that this is *not* the interpreter's
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * current state. For example:
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : example ls ; immediate
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : problem example ; \ "ls" gets executed while compiling
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * example \ "ls" gets executed while interpreting
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Notice that, though the current state is different in the two
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * invocations of "example", in both cases "ls" has been
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * *compiled in*, which is what we really want.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * The problem arises when you tick the builtin. For example:
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : example-1 ['] ls postpone literal ; immediate
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : example-2 example-1 execute ; immediate
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : problem example-2 ;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * We have no way, when we get EXECUTEd, of knowing what our behavior
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * should be. Thus, our only alternative is to "outlaw" this. See RFI
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * 0007, and ANS Forth Standard's appendix D, item 6.7 for a related
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * problem, concerning compile semantics.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * The problem is compounded by the fact that "' builtin CATCH" is valid
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * and desirable. The only solution is to create an intermediary word.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * For example:
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : my-ls ls ;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : example ['] my-ls catch ;
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * So, with the below implementation, here is a summary of the behavior
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * of builtins:
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * ls -l \ "interpret" behavior, ie,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * \ takes parameters from TIB
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-1 s" -l" 1 ls ; \ "compile" behavior, ie,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * \ takes parameters from the stack
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-2 ['] ls catch ; immediate \ undefined behavior
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-3 ['] ls catch ; \ undefined behavior
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * ex-2 ex-3 \ "interpret" behavior,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * \ catch works
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-4 ex-2 ; \ "compile" behavior,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * \ catch does not work
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-5 ex-3 ; immediate \ same as ex-2
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-6 ex-3 ; \ same as ex-3
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-7 ['] ex-1 catch ; \ "compile" behavior,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * \ catch works
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-8 postpone ls ; immediate \ same as ex-2
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * : ex-9 postpone ls ; \ same as ex-3
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * As the definition below is particularly tricky, and it's side effects
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * must be well understood by those playing with it, I'll be heavy on
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * the comments.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * (if you edit this definition, pay attention to trailing spaces after
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * each word -- I warned you! :-) )
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome": builtin: " \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"create " /* create a new definition of the next word */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"immediate " /* make the new definition an immediate word */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"does> " /* Now, the *new* definition will: */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"1 postpone literal " /* pass 1 flag to indicate compile */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"@ compile, " /* compile in previous definition */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"postpone throw " /* throw stack-returned result */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome"0 swap " /* pass 0 flag to indicate interpret */ \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome ptr = malloc(sizeof (struct bootblk_command)); \
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Initialise the Forth interpreter, create all our commands as words.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome char create_buf[41]; /* 31 characters-long builtins */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* set up commands list */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "help", "detailed help", command_help);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "?", "list commands", command_commandlist);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "show", "show variable(s)", command_show);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "printenv", "show variable(s)", command_show);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "set", "set a variable", command_set);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "setprop", "set a variable", command_setprop);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "unset", "unset a variable", command_unset);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "echo", "echo arguments", command_echo);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "read", "read input from the terminal", command_read);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "more", "show contents of a file", command_more);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "ls", "list files", command_ls);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "include", "read commands from a file",
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "boot", "boot a file or loaded kernel", command_boot);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "autoboot", "boot automatically after a delay",
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "load", "load a kernel or module", command_load);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "unload", "unload all modules", command_unload);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome COMMAND_SET(cmdp, "reboot", "reboot the system", command_reboot);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if (buf == NULL || strcmp(buf, "amd64") != 0) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Put all private definitions in a "builtins" vocabulary */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome "vocabulary builtins also builtins definitions");
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Builtin constructor word */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome rv = ficlVmEvaluate(bf_vm, BUILTIN_CONSTRUCTOR);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* make all commands appear as Forth words */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome ficlDictionaryAppendPrimitive(dict, (char *)cmdp->c_name,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome rv = ficlVmEvaluate(bf_vm, "forth definitions builtins");
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome sprintf(create_buf, "builtin: %s", cmdp->c_name);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome rv = ficlVmEvaluate(bf_vm, "builtins definitions");
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome rv = ficlVmEvaluate(bf_vm, "only forth definitions");
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Export some version numbers so that code can detect the
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome ficlDictionarySetConstant(env, "loader_version",
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome (bootprog_rev[0] - '0') * 10 + (bootprog_rev[2] - '0'));
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* try to load and run init file if present */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Feed a line of user input to the Forth interpreter
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome setenv("interpret", bf_vm->state ? "" : "ok", 1);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* do the best we can to return something... */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * the path can have device provided, check for it
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * and extract it.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome (void) asprintf(&buf, "%s/%s", ret? "":mp.mnt_mountp, tmppath);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome (void) asprintf(&buf, "%s/%s/%s", ret? "":mp.mnt_mountp, cwd,
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome case '\177':
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /*NOTREACHED*/
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome while (size != 0) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return (-1);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if ((c == '\r') || (c == '\n')) /* line terminators */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic char *
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (i = 0; i < argc; i++) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Help is read from a formatted text file.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Entries in the file are formatted as:
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * # Ttopic [Ssubtopic] Ddescription
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Note that for code simplicity's sake, the above format must be followed
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Subtopic entries must immediately follow the topic (this is used to
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * produce the listing of subtopics).
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * If no argument(s) are supplied by the user, the help for 'help' is displayed.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomehelp_getnext(int fd, char **topic, char **subtopic, char **desc)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if ((strlen(line) < 3) || (line[0] != '#') || (line[1] != ' '))
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome } else if ((*cp == 'S') && (*subtopic == NULL)) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomehelp_emitsummary(char *topic, char *subtopic, char *desc)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome } while (i++ < 30);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* page the help text from our load path */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome "use '?' to list commands\n");
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* pick up request from arguments */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome command_errmsg = "usage is 'help <topic> [<subtopic>]";
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* magic "index" keyword */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Scan the helpfile looking for help matching the request */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* topic mismatch */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* nothing more on this topic, stop scanning */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* topic matched */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* exact match, print text */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome } else if ((subtopic == NULL) && (s != NULL)) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* topic match, list subtopics */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if ((cmdp->c_name != NULL) && (cmdp->c_desc != NULL)) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * XXX set/show should become set/echo if we have variable
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * substitution happening.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * With no arguments, print everything.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if ((err = setenv(argv[1], argv[2], 1)) != 0) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* getopt has already reported an error */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * A passable emulation of the sh(1) command of the same name.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome while ((c = getopt(argc, argv, "p:t:")) != -1) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome switch (c) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * File pager
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome sprintf(line, "*** FILE %s BEGIN ***\n", argv[i]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome sprintf(line, "*** FILE %s END ***\n", argv[i]);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* getopt has already reported an error */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if (strcmp(d->d_name, ".") && strcmp(d->d_name, "..")) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* stat the file, if possible */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome buf = malloc(strlen(path) + strlen(d->d_name) + 2);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* ignore return, could be symlink, etc. */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Given (path) containing a vaguely reasonable path specification, return an fd
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * on the directory, and an allocated copy of the path to the directory.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* one extra byte for a possible trailing slash required */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Make sure the path is respectable to begin with */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* If there's no path on the device, assume '/' */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome "open '%s' failed: %s", path, strerror(errno));
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return (-1);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Since argv is static, we need to save it here.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome argvbuf = (char **)calloc(argc, sizeof (char *));
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (i = 0; i < argc; i++)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (i = 1; (i < argc) && (res == CMD_OK); i++)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (i = 0; i < argc; i++)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Header prepended to each line. The text immediately follows the header.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * We try to make this short in order to save memory -- the loader has
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * limited memory available, and some of the forth files are very long.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Read the script into memory.
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome while (fgetstr(input, sizeof (input), fd) >= 0) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* Allocate script line structure and copy line, flags */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome continue; /* ignore empty line, save memory */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome continue; /* ignore comment */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome sp = malloc(sizeof (struct includeline) + strlen(cp) + 1);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * On malloc failure (it happens!), free as much as possible
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome "file '%s' line %d: memory allocation "
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Execute the script
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome bf_vm->sourceId.i = fd+1; /* 0 is user input device */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome snprintf(command_errbuf, sizeof (command_errbuf),
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome "Error while including %s, in the line %d:\n%s",
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Rebuild list of module directories if it changed
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Ignore trailing slashes
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/';
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome * Delete unused directories if any
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic char *
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomefile_lookup(const char *path, const char *name, int namelen)
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome if (stat(result, &st) == 0 && S_ISREG(st.st_mode))
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* also check for gz file */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soomestatic char *
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome /* also check for gz file */
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome result = file_lookup(mdp->d_path, name, namelen);
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome while ((ch = getopt(argc, argv, "kt:")) != -1) {
afc2ba1deb75b323afde536f2dd18bcafdaa308dToomas Soome return (file_loadraw(argv[1], typestr, argc - 2, argv + 2, 1)