2 * Copyright (c) 2000 Daniel Capo Sobral
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 /*******************************************************************
31 ** Additional FICL words designed for FreeBSD's loader
33 *******************************************************************/
36 #include <sys/types.h>
46 #include "bootstrap.h"
51 /* FreeBSD's loader interaction words and extras
53 * setenv ( value n name n' -- )
54 * setenv? ( value n name n' flag -- )
55 * getenv ( addr n -- addr' n' | -1 )
56 * unsetenv ( addr n -- )
57 * copyin ( addr addr' len -- )
58 * copyout ( addr addr' len -- )
59 * findfile ( name len type len' -- addr )
60 * pnpdevices ( -- addr )
61 * pnphandlers ( -- addr )
62 * ccall ( [[...[p10] p9] ... p1] n addr -- result )
63 * uuid-from-string ( addr n -- addr' )
64 * uuid-to-string ( addr' -- addr n )
69 ficlSetenv(FICL_VM *pVM)
78 vmCheckStack(pVM, 4, 0);
80 names = stackPopINT(pVM->pStack);
81 namep = (char*) stackPopPtr(pVM->pStack);
82 values = stackPopINT(pVM->pStack);
83 valuep = (char*) stackPopPtr(pVM->pStack);
86 name = (char*) ficlMalloc(names+1);
88 vmThrowErr(pVM, "Error: out of memory");
89 strncpy(name, namep, names);
91 value = (char*) ficlMalloc(values+1);
93 vmThrowErr(pVM, "Error: out of memory");
94 strncpy(value, valuep, values);
97 setenv(name, value, 1);
106 ficlSetenvq(FICL_VM *pVM)
111 char *namep, *valuep;
112 int names, values, overwrite;
115 vmCheckStack(pVM, 5, 0);
117 overwrite = stackPopINT(pVM->pStack);
118 names = stackPopINT(pVM->pStack);
119 namep = (char*) stackPopPtr(pVM->pStack);
120 values = stackPopINT(pVM->pStack);
121 valuep = (char*) stackPopPtr(pVM->pStack);
124 name = (char*) ficlMalloc(names+1);
126 vmThrowErr(pVM, "Error: out of memory");
127 strncpy(name, namep, names);
129 value = (char*) ficlMalloc(values+1);
131 vmThrowErr(pVM, "Error: out of memory");
132 strncpy(value, valuep, values);
133 value[values] = '\0';
135 setenv(name, value, overwrite);
144 ficlGetenv(FICL_VM *pVM)
153 vmCheckStack(pVM, 2, 2);
155 names = stackPopINT(pVM->pStack);
156 namep = (char*) stackPopPtr(pVM->pStack);
159 name = (char*) ficlMalloc(names+1);
161 vmThrowErr(pVM, "Error: out of memory");
162 strncpy(name, namep, names);
165 value = getenv(name);
169 stackPushPtr(pVM->pStack, value);
170 stackPushINT(pVM->pStack, strlen(value));
173 stackPushINT(pVM->pStack, -1);
179 ficlUnsetenv(FICL_VM *pVM)
188 vmCheckStack(pVM, 2, 0);
190 names = stackPopINT(pVM->pStack);
191 namep = (char*) stackPopPtr(pVM->pStack);
194 name = (char*) ficlMalloc(names+1);
196 vmThrowErr(pVM, "Error: out of memory");
197 strncpy(name, namep, names);
208 ficlCopyin(FICL_VM *pVM)
215 vmCheckStack(pVM, 3, 0);
218 len = stackPopINT(pVM->pStack);
219 dest = stackPopINT(pVM->pStack);
220 src = stackPopPtr(pVM->pStack);
223 archsw.arch_copyin(src, dest, len);
230 ficlCopyout(FICL_VM *pVM)
237 vmCheckStack(pVM, 3, 0);
240 len = stackPopINT(pVM->pStack);
241 dest = stackPopPtr(pVM->pStack);
242 src = stackPopINT(pVM->pStack);
245 archsw.arch_copyout(src, dest, len);
252 ficlFindfile(FICL_VM *pVM)
258 struct preloaded_file* fp;
262 vmCheckStack(pVM, 4, 1);
265 types = stackPopINT(pVM->pStack);
266 typep = (char*) stackPopPtr(pVM->pStack);
267 names = stackPopINT(pVM->pStack);
268 namep = (char*) stackPopPtr(pVM->pStack);
270 name = (char*) ficlMalloc(names+1);
272 vmThrowErr(pVM, "Error: out of memory");
273 strncpy(name, namep, names);
275 type = (char*) ficlMalloc(types+1);
277 vmThrowErr(pVM, "Error: out of memory");
278 strncpy(type, typep, types);
281 fp = file_findfile(name, type);
285 stackPushPtr(pVM->pStack, fp);
292 /* isvirtualized? - Return whether the loader runs under a
295 * isvirtualized? ( -- flag )
298 ficlIsvirtualizedQ(FICL_VM *pVM)
304 vmCheckStack(pVM, 0, 1);
307 hv = (archsw.arch_hypervisor != NULL)
308 ? (*archsw.arch_hypervisor)()
310 flag = (hv != NULL) ? FICL_TRUE : FICL_FALSE;
311 stackPushINT(pVM->pStack, flag);
314 #endif /* ndef TESTMAIN */
317 ficlCcall(FICL_VM *pVM)
319 int (*func)(int, ...);
324 vmCheckStack(pVM, 2, 0);
327 func = stackPopPtr(pVM->pStack);
328 nparam = stackPopINT(pVM->pStack);
331 vmCheckStack(pVM, nparam, 1);
334 for (i = 0; i < nparam; i++)
335 p[i] = stackPopINT(pVM->pStack);
337 result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
340 stackPushINT(pVM->pStack, result);
346 ficlUuidFromString(FICL_VM *pVM)
357 vmCheckStack(pVM, 2, 0);
360 uuids = stackPopINT(pVM->pStack);
361 uuidp = (char *) stackPopPtr(pVM->pStack);
364 uuid = (char *)ficlMalloc(uuids + 1);
366 vmThrowErr(pVM, "Error: out of memory");
367 strncpy(uuid, uuidp, uuids);
370 u = (uuid_t *)ficlMalloc(sizeof (*u));
372 uuid_from_string(uuid, u, &status);
374 if (status != uuid_s_ok) {
381 stackPushPtr(pVM->pStack, u);
388 ficlUuidToString(FICL_VM *pVM)
397 vmCheckStack(pVM, 1, 0);
400 u = (uuid_t *)stackPopPtr(pVM->pStack);
403 uuid_to_string(u, &uuid, &status);
404 if (status != uuid_s_ok) {
405 stackPushPtr(pVM->pStack, uuid);
406 stackPushINT(pVM->pStack, strlen(uuid));
409 stackPushINT(pVM->pStack, -1);
414 /**************************************************************************
416 ** reads in text from file fd and passes it to ficlExec()
417 * returns VM_OUTOFTEXT on success or the ficlExec() error code on
421 int ficlExecFD(FICL_VM *pVM, int fd)
424 int nLine = 0, rval = VM_OUTOFTEXT;
429 pVM->sourceID.i = fd;
431 /* feed each line to ficlExec */
436 while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
444 rval = ficlExecC(pVM, cp, i);
445 if(rval != VM_QUIT && rval != VM_USEREXIT && rval != VM_OUTOFTEXT)
452 ** Pass an empty line with SOURCE-ID == -1 to flush
453 ** any pending REFILLs (as required by FILE wordset)
455 pVM->sourceID.i = -1;
462 static void displayCellNoPad(FICL_VM *pVM)
466 vmCheckStack(pVM, 1, 0);
468 c = stackPop(pVM->pStack);
469 ltoa((c).i, pVM->pad, pVM->base);
470 vmTextOut(pVM, pVM->pad, 0);
474 /* isdir? - Return whether an fd corresponds to a directory.
476 * isdir? ( fd -- bool )
478 static void isdirQuestion(FICL_VM *pVM)
485 vmCheckStack(pVM, 1, 1);
488 fd = stackPopINT(pVM->pStack);
493 if (fstat(fd, &sb) < 0)
495 if (!S_ISDIR(sb.st_mode))
499 stackPushINT(pVM->pStack, flag);
502 /* fopen - open a file and return new fd on stack.
504 * fopen ( ptr count mode -- fd )
506 static void pfopen(FICL_VM *pVM)
512 vmCheckStack(pVM, 3, 1);
515 mode = stackPopINT(pVM->pStack); /* get mode */
516 count = stackPopINT(pVM->pStack); /* get count */
517 ptr = stackPopPtr(pVM->pStack); /* get ptr */
519 if ((count < 0) || (ptr == NULL)) {
520 stackPushINT(pVM->pStack, -1);
524 /* ensure that the string is null terminated */
525 name = (char *)malloc(count+1);
526 bcopy(ptr,name,count);
530 fd = open(name, mode);
531 #ifdef LOADER_VERIEXEC
533 if (verify_file(fd, name, 0, VE_GUESS, __func__) < 0) {
534 /* not verified writing ok but reading is not */
535 if ((mode & O_ACCMODE) != O_WRONLY) {
540 /* verified reading ok but writing is not */
541 if ((mode & O_ACCMODE) != O_RDONLY) {
549 stackPushINT(pVM->pStack, fd);
553 /* fclose - close a file who's fd is on stack.
557 static void pfclose(FICL_VM *pVM)
562 vmCheckStack(pVM, 1, 0);
564 fd = stackPopINT(pVM->pStack); /* get fd */
570 /* fread - read file contents
572 * fread ( fd buf nbytes -- nread )
574 static void pfread(FICL_VM *pVM)
580 vmCheckStack(pVM, 3, 1);
582 len = stackPopINT(pVM->pStack); /* get number of bytes to read */
583 buf = stackPopPtr(pVM->pStack); /* get buffer */
584 fd = stackPopINT(pVM->pStack); /* get fd */
585 if (len > 0 && buf && fd != -1)
586 stackPushINT(pVM->pStack, read(fd, buf, len));
588 stackPushINT(pVM->pStack, -1);
592 /* freaddir - read directory contents
594 * freaddir ( fd -- ptr len TRUE | FALSE )
596 static void pfreaddir(FICL_VM *pVM)
599 static struct dirent dirent;
610 vmCheckStack(pVM, 1, 3);
613 fd = stackPopINT(pVM->pStack);
616 * The readdirfd() function is specific to the loader environment.
617 * We do the best we can to make freaddir work, but it's not at
625 if (fstat(fd, &sb) == -1)
627 blksz = (sb.st_blksize) ? sb.st_blksize : getpagesize();
628 if ((blksz & (blksz - 1)) != 0)
633 off = lseek(fd, 0LL, SEEK_CUR);
637 if (lseek(fd, 0, SEEK_SET) == -1)
639 bufsz = getdents(fd, buf, blksz);
640 while (bufsz > 0 && bufsz <= ptr) {
642 bufsz = getdents(fd, buf, blksz);
646 d = (void *)(buf + ptr);
649 d = (lseek(fd, off, SEEK_SET) != off) ? NULL : &dirent;
657 stackPushPtr(pVM->pStack, d->d_name);
658 stackPushINT(pVM->pStack, strlen(d->d_name));
659 stackPushINT(pVM->pStack, FICL_TRUE);
661 stackPushINT(pVM->pStack, FICL_FALSE);
665 /* fload - interpret file contents
669 static void pfload(FICL_VM *pVM)
674 vmCheckStack(pVM, 1, 0);
676 fd = stackPopINT(pVM->pStack); /* get fd */
682 /* fwrite - write file contents
684 * fwrite ( fd buf nbytes -- nwritten )
686 static void pfwrite(FICL_VM *pVM)
692 vmCheckStack(pVM, 3, 1);
694 len = stackPopINT(pVM->pStack); /* get number of bytes to read */
695 buf = stackPopPtr(pVM->pStack); /* get buffer */
696 fd = stackPopINT(pVM->pStack); /* get fd */
697 if (len > 0 && buf && fd != -1)
698 stackPushINT(pVM->pStack, write(fd, buf, len));
700 stackPushINT(pVM->pStack, -1);
704 /* fseek - seek to a new position in a file
706 * fseek ( fd ofs whence -- pos )
708 static void pfseek(FICL_VM *pVM)
713 vmCheckStack(pVM, 3, 1);
715 whence = stackPopINT(pVM->pStack);
716 pos = stackPopINT(pVM->pStack);
717 fd = stackPopINT(pVM->pStack);
718 stackPushINT(pVM->pStack, lseek(fd, pos, whence));
722 /* key - get a character from stdin
726 static void key(FICL_VM *pVM)
729 vmCheckStack(pVM, 0, 1);
731 stackPushINT(pVM->pStack, getchar());
735 /* key? - check for a character from stdin (FACILITY)
739 static void keyQuestion(FICL_VM *pVM)
742 vmCheckStack(pVM, 0, 1);
745 /* XXX Since we don't fiddle with termios, let it always succeed... */
746 stackPushINT(pVM->pStack, FICL_TRUE);
748 /* But here do the right thing. */
749 stackPushINT(pVM->pStack, ischar()? FICL_TRUE : FICL_FALSE);
754 /* seconds - gives number of seconds since beginning of time
756 * beginning of time is defined as:
758 * BTX - number of seconds since midnight
759 * FreeBSD - number of seconds since Jan 1 1970
763 static void pseconds(FICL_VM *pVM)
766 vmCheckStack(pVM,0,1);
768 stackPushUNS(pVM->pStack, (FICL_UNS) time(NULL));
772 /* ms - wait at least that many milliseconds (FACILITY)
777 static void ms(FICL_VM *pVM)
780 vmCheckStack(pVM,1,0);
783 usleep(stackPopUNS(pVM->pStack)*1000);
785 delay(stackPopUNS(pVM->pStack)*1000);
790 /* fkey - get a character from a file
792 * fkey ( file -- char )
794 static void fkey(FICL_VM *pVM)
800 vmCheckStack(pVM, 1, 1);
802 fd = stackPopINT(pVM->pStack);
803 i = read(fd, &ch, 1);
804 stackPushINT(pVM->pStack, i > 0 ? ch : -1);
810 ** Retrieves free space remaining on the dictionary
813 static void freeHeap(FICL_VM *pVM)
815 stackPushINT(pVM->pStack, dictCellsAvail(ficlGetDict(pVM->pSys)));
819 /******************* Increase dictionary size on-demand ******************/
821 static void ficlDictThreshold(FICL_VM *pVM)
823 stackPushPtr(pVM->pStack, &dictThreshold);
826 static void ficlDictIncrease(FICL_VM *pVM)
828 stackPushPtr(pVM->pStack, &dictIncrease);
831 /**************************************************************************
832 f i c l C o m p i l e P l a t f o r m
833 ** Build FreeBSD platform extensions into the system dictionary
834 **************************************************************************/
835 void ficlCompilePlatform(FICL_SYSTEM *pSys)
837 ficlCompileFcn **fnpp;
838 FICL_DICT *dp = pSys->dp;
841 dictAppendWord(dp, ".#", displayCellNoPad, FW_DEFAULT);
842 dictAppendWord(dp, "isdir?", isdirQuestion, FW_DEFAULT);
843 dictAppendWord(dp, "fopen", pfopen, FW_DEFAULT);
844 dictAppendWord(dp, "fclose", pfclose, FW_DEFAULT);
845 dictAppendWord(dp, "fread", pfread, FW_DEFAULT);
846 dictAppendWord(dp, "freaddir", pfreaddir, FW_DEFAULT);
847 dictAppendWord(dp, "fload", pfload, FW_DEFAULT);
848 dictAppendWord(dp, "fkey", fkey, FW_DEFAULT);
849 dictAppendWord(dp, "fseek", pfseek, FW_DEFAULT);
850 dictAppendWord(dp, "fwrite", pfwrite, FW_DEFAULT);
851 dictAppendWord(dp, "key", key, FW_DEFAULT);
852 dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT);
853 dictAppendWord(dp, "ms", ms, FW_DEFAULT);
854 dictAppendWord(dp, "seconds", pseconds, FW_DEFAULT);
855 dictAppendWord(dp, "heap?", freeHeap, FW_DEFAULT);
856 dictAppendWord(dp, "dictthreshold", ficlDictThreshold, FW_DEFAULT);
857 dictAppendWord(dp, "dictincrease", ficlDictIncrease, FW_DEFAULT);
859 dictAppendWord(dp, "setenv", ficlSetenv, FW_DEFAULT);
860 dictAppendWord(dp, "setenv?", ficlSetenvq, FW_DEFAULT);
861 dictAppendWord(dp, "getenv", ficlGetenv, FW_DEFAULT);
862 dictAppendWord(dp, "unsetenv", ficlUnsetenv, FW_DEFAULT);
863 dictAppendWord(dp, "copyin", ficlCopyin, FW_DEFAULT);
864 dictAppendWord(dp, "copyout", ficlCopyout, FW_DEFAULT);
865 dictAppendWord(dp, "findfile", ficlFindfile, FW_DEFAULT);
866 dictAppendWord(dp, "ccall", ficlCcall, FW_DEFAULT);
867 dictAppendWord(dp, "uuid-from-string", ficlUuidFromString, FW_DEFAULT);
868 dictAppendWord(dp, "uuid-to-string", ficlUuidToString, FW_DEFAULT);
870 dictAppendWord(dp, "isvirtualized?",ficlIsvirtualizedQ, FW_DEFAULT);
873 SET_FOREACH(fnpp, Xficl_compile_set)
876 #if defined(__i386__)
877 ficlSetEnv(pSys, "arch-i386", FICL_TRUE);
878 ficlSetEnv(pSys, "arch-powerpc", FICL_FALSE);
879 #elif defined(__powerpc__)
880 ficlSetEnv(pSys, "arch-i386", FICL_FALSE);
881 ficlSetEnv(pSys, "arch-powerpc", FICL_TRUE);